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:
name: support
mode: text
llm: llm-fast
connectors:
- name: linq
connection: acme-imessage # the label of your Linq connectionYou need a Linq API token, and your line's number in E.164. Setup takes three steps:
- Subscribe at Linq. Pick a name for your Linq account, such as
acme-linq. At Linq, create a webhook subscription for themessage.receivedevent to$STREAM_ACCELERATION_URL/v1/connectors/events/linq/acme-linq?version=2026-02-03.$STREAM_ACCELERATION_URLis your router's URL. Keep the subscription's signing secret. It starts withwhsec_. - Save your Linq account. On the Stream Dashboard, open Library > Connectors, then Linq. Choose Set OAuth client. Fill Provider app ID with
acme-linqand Signing secret with the secret from step 1. Leave the other fields empty, then choose Save client. - Create the connection. On the same page, choose Create connection. Choose App as the Owner. Enter
acme-imessageas the Label, your line's number asphone_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 supportFrom 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.