# 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:

```yaml title="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:

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**

   Give Stream the name and the signing secret:

   ```sh
   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`.

3. **Connect the line**

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

   ```sh
   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.

4. **Sync the agent**

   ```sh
   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](https://getstream.io/signin/), 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:

```bash
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](https://getstream.io/agents/docs/auth/):

```bash
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

- [Channels](https://getstream.io/agents/docs/connectors/channels/): Every channel, what it needs, and which one to start with.
- [SMS](https://getstream.io/agents/docs/connectors/sms/): Answer over SMS on your own Telnyx number.
- [Slack](https://getstream.io/agents/docs/connectors/slack/): Answer in Slack threads as your workspace's bot.
- [Creating an agent](https://getstream.io/agents/docs/creating-an-agent/): The agent folder, and every key of agent.yaml.

---

For the most recent version of this documentation, visit [https://getstream.io/agents/docs/connectors/imessage/](https://getstream.io/agents/docs/connectors/imessage/).