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 four steps:

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_.

Save your Linq account

Give Stream the name and the signing secret:

curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
echo "$LINQ_SIGNING_SECRET" | getstream agents connectors client set linq --provider-app-id acme-linq --signing-secret -

The CLI prints Saved the provider app for linq.

Connect the line

Create the connection with your line's number and the Linq API token:

echo "$LINQ_API_TOKEN" | getstream agents connections create linq --label acme-imessage --input phone_number=+12025550100 --token -

The CLI prints Connected: linq / acme-imessage, with the connection's id.

Sync the agent

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.

In the Dashboard

Steps 2 and 3 work in the Dashboard too. In the Stream Dashboard, go to Agents > Library > Connectors and open Linq.

  1. Click Set OAuth client. The dialog has two fields: fill Provider app ID with acme-linq and Signing secret with the secret from step 1, then click Save client.
  2. Click Create connection. Owner starts on Signed-in user: pick App. Type acme-imessage in Label, your line's number in phone_number and the Linq API token in Token, then click Create connection. The connection's page opens, and the connection is connected.

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.

With the API

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