Linq

Linq Message Apps

Add Connect Onairos to Linq-powered message apps: the onairos-text-auth SDK for backends, the onairos-text-auth-mcp tools for LLM agents, and the raw HTTP contract underneath.

Updated 6 July 2026
linqmessagesimessageconnect-onairoswebhookconsentsdkmcpagent

Message app integration

Connect Onairos for Linq-Powered Apps

Use this when your Linq-powered app needs existing Onairos users to connect and consent from the same message thread.

New

Linq messaging integration is now a skill — copy one file and any backend can run the whole connect-and-consent flow. Copy the skill →

Your backend loop is simple:

  1. Receive the Linq message webhook.
  2. Send the user's latest text to Onairos.
  3. Relay the Onairos reply back to the same Linq chat.
  4. After the user replies YES, exchange the grant IDs for data.

User connection flow

9:41
YA

Your Assistant

Linq message thread

Active
Connect Onairos
What email is on your Onairos account?
user@example.com
I sent a 6-digit verification code. Reply with that code here.
123456
Allow this app to use Gmail, LinkedIn, Reddit, and YouTube? Reply YES or NO.
YES
Authorized. Grants are ready for your app backend to exchange.

Existing Onairos user consent inside a Linq-powered message thread.

User flow

Connect inside the message thread

The user replies in the message thread. Your backend relays each message and exchanges the grant after consent.

01

Text Connect Onairos

The user stays in the same Linq thread.

02

Verify account

Email first, then the 6-digit code.

03

Approve access

Connected accounts are shown before YES or NO.

04

Grant ready

Your backend exchanges it for the Onairos handoff.

Flow reference

Developer flow

One relay loop, five checkpoints

Keep the implementation simple: every user reply goes to Onairos, and every Onairos reply goes back to the same Linq chat.

Core loop

User text in app thread
Onairos command from backend
Linq reply to same chat
  1. 01

    Inbound message

    BackendStore the chat ID and sender IDs from the Linq webhook.

    UserSends Connect Onairos in the message thread.

  2. 02

    Relay loop

    BackendPOST the text to Onairos, then send the returned reply through Linq.

    UserSees the next Onairos prompt in the same thread.

  3. 03

    Email verification

    BackendForward the email and code replies. Onairos verifies them.

    UserEnters their email, then the 6-digit code.

  4. 04

    Explicit consent

    BackendWait for YES or NO before treating anything as authorized.

    UserReviews connected accounts and replies YES or NO.

  5. 05

    Grant exchange

    BackendExchange grantId for apiUrl, token, and authorizedData.

    UserYour app can use the approved Onairos data.

Whichever path you integrate, consent is explicit and belongs to the user:

Consent checkpoint

Nothing is authorized until the user says YES

The existing Onairos account is verified first, then Onairos asks the user to approve the app and data categories.

Verified existing Onairos account

Allow this app to use Gmail, LinkedIn, Reddit, and YouTube, and share personality traits and preferences?

YES
NO

Consent state

approved by user

Grant IDs

stored server-side

Exchange result

apiUrl, token, authorizedData

Credential rule

never expose keys or grants client-side

Grant exchange ready
Your backend can now exchange approved grants with the Onairos backend.

Copy the skill

The fastest way to integrate, and the one that works on any backend. Copy the file below into the agent that runs your thread, or hand it to your coding assistant — it has the two endpoints, the request and response shapes, and the rules. No SDK and no MCP server required.

---
name: onairos-linq-connect
description: Connect existing Onairos users from a Linq message thread and fetch their personality and preferences, from any backend.
---

# Onairos + Linq — Connect Onairos skill

Let people connect their Onairos account and share their persona from inside a Linq
message thread. Your backend relays each message between Linq and Onairos. Onairos runs
the email, verification, and consent conversation and returns the authorized data.

Works with any backend. You need two API keys, both kept server-side only:
  - Onairos developer API key
  - Linq Partner API key

## The loop

On every inbound Linq message:
  1. Forward the message to Onairos (Endpoint 1).
  2. Send the "reply" it returns back into the same Linq chat.
  3. When the response contains "grants" (the user replied YES), exchange them for data (Endpoint 2).

Never send the email, verification code, or YES/NO yourself. Those must come from the
user's own messages — that is what keeps consent with the user.

## Endpoint 1 — relay a message

Forward the Linq webhook event, adding a metadata object:

    POST https://api2.onairos.uk/integrations/linq/text/command
    Authorization: Bearer YOUR_ONAIROS_API_KEY
    Content-Type: application/json

    {
      ...the Linq webhook event...,
      "metadata": {
        "applicationName": "Your App",
        "agentName": "Your Assistant",
        "confirmations": ["personality", "preferences"]
      }
    }

Response — send "reply" back into the Linq chat:

    {
      "success": true,
      "action": "connect_account",
      "reply": "What email is on your Onairos account?"
    }

After the user verifies and replies YES, the response also carries grants:

    {
      "success": true,
      "action": "authorize",
      "reply": "Authorized Your App to use your connected Onairos accounts.",
      "grants": [ { "grantId": "lta_abc123", "status": "active" } ]
    }

## Send a reply into the Linq thread

Use your Linq Partner key and the original chat ID so the user stays in one thread:

    POST https://api.linqapp.com/api/partner/v3/chats/CHAT_ID/messages
    Authorization: Bearer YOUR_LINQ_PARTNER_API_KEY
    Content-Type: application/json

    { "message": { "parts": [ { "type": "text", "value": "REPLY_TEXT" } ] } }

## Endpoint 2 — exchange grants for data

Only after the user replies YES. Server-to-server:

    POST https://api2.onairos.uk/integrations/linq/text/grants/exchange
    Authorization: Bearer YOUR_ONAIROS_API_KEY
    Content-Type: application/json

    {
      "grantIds": ["lta_abc123"],
      "confirmations": ["personality", "preferences"],
      "Info": { "appName": "Your App", "confirmations": ["personality", "preferences"], "fastTraits": true }
    }

Response — a handoff you use to fetch the persona:

    {
      "apiUrl": "https://api2.onairos.uk/traits-only-fast",
      "token": "one_hour_token",
      "authorizedData": { "personality": true, "preferences": true }
    }

Fetch the persona by calling apiUrl with the token:

    POST {apiUrl}
    Authorization: Bearer {token}

Use the returned personality and preferences to personalize your replies.

## Rules

  - Consent only counts when it arrives in the user's own YES message.
  - Keep both API keys on the backend. Never put them in client code or message text.
  - Reuse the same Linq chat ID for the whole conversation.
  - Wait for "grants" in Endpoint 1's response before calling Endpoint 2.

Most teams need nothing more than this. If you would rather use a maintained package, pick a path below.

Choose your integration path

The skill above is all most teams need. For a maintained package or the full endpoint reference, both paths below run the identical flow — pick the one that fits your backend.

  • With the SDK (Node). The onairos-text-auth package wraps the whole flow behind a single webhook call. Add onairos-text-auth-mcp on top when an LLM agent runs the thread.
  • Without the SDK (any backend). Call the same two Onairos endpoints directly over HTTP — from Python, Go, PHP, Ruby, or anything else — and send the Linq replies yourself.

Node backend SDK

onairos-text-auth

The Node backend SDK — one install, one webhook route. onairos-text-auth handles signature verification, event dedup, message relaying, consent replies, and grant exchange for you. All you supply is your Onairos developer API key and your Linq webhook signing secret.

npm install onairos-text-auth
import express from 'express';
import { createTextAuthRelay } from 'onairos-text-auth';

const app = express();

// Linq signs webhooks over the exact raw bytes - capture them.
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }));

const relay = createTextAuthRelay({
  onairosApiKey: process.env.ONAIROS_API_KEY,
  webhookSecret: process.env.LINQ_WEBHOOK_SECRET,
  appName: 'Example App',
  requestedConfirmations: ['personality', 'preferences'],
  autoExchangeGrants: true
});

// Your Linq webhook route: whichever path your Linq webhook subscription
// is registered to. Linq POSTs every inbound user message here — this one
// route is where the entire text conversation arrives.
app.post('/linq/webhook', async (req, res) => {
  const result = await relay.handleWebhook({
    headers: req.headers,
    rawBody: req.rawBody,
    body: req.body,
    sendMessage: ({ chatId, text }) => sendLinqReply({ chatId, text })
  });

  if (result.handoff) {
    const data = await relay.fetchAuthorizedData({ handoff: result.handoff });
    // personality traits / preferences - exactly what the user approved
  }
  res.json({ ok: true });
});

That is the entire integration. When a user texts Connect Onairos, the SDK runs the full conversation; the moment they authorize, result.handoff arrives in the same shape as the browser SDK handoff.

Prefer to pitch in your own words? Start the flow yourself as soon as your logic detects an opt-in:

await relay.startConnect({ body: req.body, sendMessage });
// thread receives: "What email is on your Onairos account?"

Consent always stays with the user. Your code can only start the flow or read its status — it can never approve on the user's behalf. Every YES/NO, email, and verification code has to arrive in the user's own message text, so a consent can't be forged in code.

For LLM agents

onairos-text-auth-mcp

Reach for this when an LLM agent — not fixed code — runs the thread. onairos-text-auth-mcp keeps that same guarantee under an agent: your agent decides when, deterministic code decides how. A bridge intercepts every flow message before the model sees it — verification codes and consent replies never enter its context — and exposes six tools the agent can call.

npm install onairos-text-auth onairos-text-auth-mcp
import { createTextAuthAgentBridge, buildTextAuthMcpServer } from 'onairos-text-auth-mcp';

const bridge = createTextAuthAgentBridge({ relay, sendMessage });

// Same Linq webhook route as above — the path your Linq subscription
// delivers message events to. The bridge sees every message BEFORE your
// agent and handles active auth flows deterministically.
app.post('/linq/webhook', async (req, res) => {
  const incoming = await bridge.handleIncoming({
    headers: req.headers, rawBody: req.rawBody, body: req.body
  });
  if (!incoming.ok) return res.status(401).json({ ok: false });
  if (incoming.handled) return res.json({ ok: true }); // flow message - agent never sees it

  await runAgentTurn(incoming.message); // your LLM, with the MCP tools below
  res.json({ ok: true });
});
  • onairos_start_connect - start the flow after a genuine opt-in
  • onairos_list_accounts - which platforms the user connected (silent)
  • onairos_flow_status - flow active? authorized? data fetchable?
  • onairos_get_data - the personalization payload, consented scopes only
  • onairos_request_authorization - ask for consent; the user still replies YES themselves
  • onairos_disconnect - revoke grants when the user asks to stop sharing

Mount the MCP server and connect your agent

The MCP server runs in the same process as your webhook handler so it shares the bridge's flow state. Expose it over the Model Context Protocol Streamable HTTP transport, then point your agent framework at the endpoint.

import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

// Same process as the webhook above - the MCP server shares bridge state.
const mcpServer = buildTextAuthMcpServer({ bridge });

app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
  res.on('close', () => transport.close());
  await mcpServer.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

Point your agent framework's MCP client at POST /mcp - http://localhost:3000/mcp in development, or your deployed webhook host in production. The six tools register automatically once the client connects, and no verification code or consent reply ever passes through the model.

The bridge keeps flow state in memory by default, which is all you need when the MCP server and your webhook handler share one process. If you run them separately, give both a shared store ({ get, set, delete }, for example Redis-backed) through createTextAuthAgentBridge so they see the same flows.