---
title: Linq Reference
description: Linq channel options, credentials, webhook verification, steering, attachments, inbound hooks, and tapbacks.
url: "https://eve.dev/docs/channels/linq/reference"
docs_index: /llms.txt
type: reference
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

This page documents every part of `linqChannel` from `eve/channels/linq`. For setup and common tasks, start with [Linq](/docs/channels/linq).

The Linq channel connects your agent to iMessage and SMS conversations through `agent/channels/linq.ts`.

## Setup and credentials

Run `eve add channel/linq` and choose Vercel Connect or portable credentials. With Vercel Connect, eve signs you in and links a Vercel project. It then asks whether to create a managed Linq account and line, or connect an existing account with its partner API token. You select the account's phone numbers for the agent, and eve configures the connector and webhook through Connect:

```ts title="agent/channels/linq.ts"
import { connectLinqCredentials } from "@vercel/connect/eve";
import { linqChannel } from "eve/channels/linq";

export default linqChannel({
  credentials: connectLinqCredentials("linq/my-agent"),
});
```

### Other hosts

On a host without Vercel Connect, choose **Use portable credentials** during `eve add channel/linq`. eve writes `LINQ_API_KEY` and `LINQ_WEBHOOK_SECRET` to `.env.local`.

After deploying the agent:

1. Create a Linq webhook for your public `https://…/eve/v1/linq` URL with `message.received`, `reaction.added`, and `reaction.removed` events.
2. Set `LINQ_API_KEY` and `LINQ_WEBHOOK_SECRET` in the host's encrypted environment variables.

To configure the channel by hand, pass the API key and webhook signing secret:

```ts title="agent/channels/linq.ts"
import { linqChannel } from "eve/channels/linq";

export default linqChannel({
  credentials: {
    apiKey: process.env.LINQ_API_KEY!,
    signingSecret: process.env.LINQ_WEBHOOK_SECRET!,
  },
});
```

A supplied `webhookVerifier` takes precedence over `signingSecret`.

## Inbound messages

The channel receives webhooks at `/eve/v1/linq` and, by default, verifies them with Vercel OIDC from the same project and environment. It builds auth from the person who sent each message, marks accepted messages as read, and keeps one eve session per Linq conversation.

A message that arrives during a turn joins that turn, so the agent can take the correction into account. Set `turnPolicy: "queue"` to let every reply finish before the next message starts. See [Overlapping messages](/docs/channels#overlapping-messages) for when a new message can interrupt the model.

## Attachments

Images and other files people send reach the agent as file parts. eve downloads each one over HTTPS. Downloads and redirects must resolve to public network addresses and time out after 30 seconds. A failed download, or a file over 25 MB, reaches the agent as a short note instead.

## Message hook

Customize inbound handling with `onMessage`. Return `null` to ignore a message, or return `title` alongside `auth` to set the run title when the message starts a run:

```ts
export default linqChannel({
  credentials: connectLinqCredentials("linq/my-agent"),
  onMessage(_ctx, message) {
    if (message.author.isBot) return null;
    return {
      auth: null,
      context: [`The sender is ${message.author.fullName}.`],
    };
  },
});
```

Set `route` to change the webhook path, or `webhookVerifier` (typed `LinqWebhookVerifier` from `eve/channels/linq`) to use a different trusted-forwarder verifier. A verifier receives the request and its raw body bytes. It rejects a webhook by throwing or returning a falsy value such as `null` or `false`.

## Options

`linqChannel(config)` takes these options. All are optional.

| Option        | Default                               | Description                                                                                                                  |
| ------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `credentials` | Same-project Vercel OIDC verification | From `connectLinqCredentials(...)`, or `{ apiKey, signingSecret, webhookVerifier }`. Each secret also takes a lazy resolver. |
| `route`       | `/eve/v1/linq`                        | Webhook path.                                                                                                                |
| `baseURL`     | Linq's API                            | Linq API endpoint, such as a sandbox.                                                                                        |
| `userName`    | `"eve"`                               | Bot display name.                                                                                                            |
| `turnPolicy`  | `"steer"`                             | `"steer"` or `"queue"` for messages that arrive during a turn.                                                               |
| `onMessage`   | Dispatch with the author's auth       | `(ctx, message)` hook. See [Message hook](#message-hook).                                                                    |
| `onTapback`   | None, so tapbacks are ignored         | `(ctx, tapback)` hook. See [Tapbacks](#tapbacks).                                                                            |
| `events`      | eve's default handlers                | Per-event handler overrides.                                                                                                 |

The channel mounts `GET` and `POST` on `/eve/v1/linq`.

## Tapbacks

`IMESSAGE_TAPBACKS` from `eve/channels/linq` lists the built-in tapback names.
Use it to populate a picker or validate a named reaction. Tapback APIs can also
accept a single emoji; the list does not enumerate those.

eve ignores tapbacks people send unless you pass `onTapback`. It receives the tapback and returns the same result as `onMessage`, or `null` to ignore it:

```ts title="agent/channels/linq.ts"
import { connectLinqCredentials } from "@vercel/connect/eve";
import { defaultLinqAuth, linqChannel } from "eve/channels/linq";

export default linqChannel({
  credentials: connectLinqCredentials("linq/my-agent"),
  onTapback(_ctx, tapback) {
    if (!tapback.added) return null;
    return { auth: defaultLinqAuth(tapback) };
  },
});
```

| Field               | Value                                                                                          |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| `tapback.tapback`   | `love`, `like`, `dislike`, `laugh`, `emphasize`, `question`, or the emoji for an emoji tapback |
| `tapback.messageId` | The message the tapback is on                                                                  |
| `tapback.author`    | The person who sent it                                                                         |

The agent reads an accepted tapback as iMessage's text form, such as `Tapback: Loved “See you at 7”` or `Tapback: Removed a like tapback from a message`. The quoted text appears when Linq can return the original message. An accepted tapback starts or steers a turn like any other message, following `turnPolicy`.

`onTapback` runs instead of `onMessage` for tapbacks, so repeat any sender checks from `onMessage` there. The agent's own tapbacks never reach it. Tapbacks arrive as `reaction.added` and `reaction.removed` webhook events, which `eve add channel/linq` subscribes to.

To let the agent send tapbacks, export the channel's tapback tool from a file in `agent/tools/`. The file name becomes the tool name:

```ts title="agent/tools/tapback.ts"
import linq from "../channels/linq";

export default linq.tapbackTool();
```

The model calls it with a standard tapback, such as `{ "tapback": "love" }`, or any single emoji, such as `{ "tapback": "🎉" }`. eve reacts to the latest message someone sent in the conversation. A standard tapback's own emoji, such as `👍`, sends that tapback.

The model can send a tapback alongside a reply; to let a tapback be the whole answer, also add [`no_reply`](/docs/concepts/built-in-tools#no_reply). Subagents don't receive the tool. In a session from another channel, such as web chat, or before anyone has sent a message, the call returns an error to the model.

### Answer approvals with a tapback

Return `answer` from `onTapback` to answer the approval or question in the message the tapback is on. A [tool approval](/docs/human-in-the-loop#approvals) offers the options `approve` and `deny`, so a like or dislike on the approval prompt can approve or deny it:

```ts title="agent/channels/linq.ts"
import { connectLinqCredentials } from "@vercel/connect/eve";
import { defaultLinqAuth, linqChannel } from "eve/channels/linq";

export default linqChannel({
  credentials: connectLinqCredentials("linq/my-agent"),
  onTapback(_ctx, tapback) {
    if (!tapback.added) return null;
    const auth = defaultLinqAuth(tapback);
    if (tapback.tapback === "like") return { auth, answer: "approve" };
    if (tapback.tapback === "dislike") return { auth, answer: "deny" };
    return { auth };
  },
});
```

`answer` answers only the request posted in that message, and only while that request is still open and offers that option. A tapback on any other message, or on an answered prompt, reaches the agent as an ordinary tapback, such as `Tapback: Liked “Got it”`. The approval's response policy still decides whether the sender may answer. For a [question](/docs/human-in-the-loop#questions), return one of its option ids.

Return `message` to replace the text the agent receives for a tapback. Don't set `message` to an option's id, label, or number, because eve reads that text like a typed reply. A typed reply answers the first waiting approval, no matter which message the tapback is on.

## What to read next

- [Channels overview](/docs/channels): the channel contract and every built-in channel
- [Auth & route protection](/docs/guides/auth-and-route-protection): authenticating inbound traffic

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)