iMessage

Let people text your agent. The linq connector answers them over iMessage on your own Linq line.

Answer on iMessage

Use your Linq connection:

agents/support/agent.yaml
name: support
mode: text
llm: llm-fast
connectors:
  - name: linq
    connection: acme-imessage # the label of your Linq connection

You need a Linq API token, and your line's number in E.164. Setup takes three steps:

  1. Subscribe at Linq. Pick a name for your Linq account, such as acme-linq. At Linq, create a webhook subscription for the message.received event to $STREAM_ACCELERATION_URL/v1/connectors/events/linq/acme-linq?version=2026-02-03. $STREAM_ACCELERATION_URL is your router's URL. Keep the subscription's signing secret. It starts with whsec_.
  2. Save your Linq account. On the Stream Dashboard, open Library > Connectors, then Linq. Choose Set OAuth client. Fill Provider app ID with acme-linq and Signing secret with the secret from step 1. Leave the other fields empty, then choose Save client.
  3. Create the connection. On the same page, choose Create connection. Choose App as the Owner. Enter acme-imessage as the Label, your line's number as phone_number, such as +12025550100, and Linq's API token as the Token. Choose Create connection.

Sync the agent:

curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
getstream agents sync support

From an iPhone, text "What is your return policy?" to your Linq line. The reply comes back in the same chat.

Conversations

  • Each chat is one conversation. Text "My name is Ana", then "What is my name?", and the agent answers "Your name is Ana."
  • Stream Chat keeps the conversation in one channel per chat, with the person's messages and the agent's replies.
  • A photo reaches the agent. Send a photo with "What is in this photo?", and the agent answers about the photo.
  • If photos do not reach the agent, save the Linq token again. On the connection's page, choose Replace token and enter the Linq API token again.

Set it up from your backend

Step 1 is one call to Linq's API, with your Linq API token:

curl -X POST "https://api.linqapp.com/api/partner/v3/webhook-subscriptions" \
  -H "Authorization: Bearer $LINQ_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "$STREAM_ACCELERATION_URL/v1/connectors/events/linq/acme-linq?version=2026-02-03", "subscribed_events": ["message.received"]}'

Put your router URL in place of $STREAM_ACCELERATION_URL. Linq returns the subscription's signing_secret.

Steps 2 and 3 are three calls to Stream. $SERVER_TOKEN is a server token:

curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connectors/linq/oauth-client" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provider_app_id": "acme-linq", "signing_secret": "whsec_..."}'

curl -X POST "$STREAM_ACCELERATION_URL/v1/agents/connections" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"connector_id": "linq", "owner": {"type": "app"}, "label": "acme-imessage", "inputs": {"phone_number": "+12025550100"}}'

curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connections/$CONNECTION_ID/credentials" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"expected_revision": 1, "values": {"token": "<Linq API token>"}}'

$CONNECTION_ID is the id the second call returns. After the third call, the connection is connected.

Keywords

Stream handles these, not the agent:

  • HELP: Stream answers with its help text, "Reply STOP to unsubscribe."
  • STOP: the person is opted out. They get no confirmation, and nothing more is sent to them until they send START.
  • START: the person is opted back in. Stream answers "You are subscribed again. Reply STOP to unsubscribe.", and the agent answers their next message.

Going further