Task Interface

One endpoint. Plain English. The agent handles everything else.


The shift

Traditional integrations force you to learn endpoints, map fields, version schemas, and handle every edge case. The Chat Agent Gateway replaces all of that with agentic communication. Describe what you need. SOIS's own agent interprets your intent, negotiates the details, executes across your workspace, and replies with the result. This is the on-ramp for callers that bring no AI of their own. If you already have an agent, connect it directly over the MCP Server instead.

No connectors. No middleware. No third-party automation layer.


Authentication

Every message requires two credentials:

Header Value What it does
Authorization Bearer <token> Proves who you are
X-Api-Key sois_... Controls your budget, webhook, and signing

Why two? Your token proves identity. Your key controls spend. If either leaks alone, it's useless without the other. One user can have multiple keys with different budgets for different integrations.

Get both from Settings in your Sois AI workspace.


Send a message

POST /api/agent

Headers

Authorization: Bearer <your_token>
X-Api-Key: sois_...
Content-Type: application/json

Body

Field Type Required Description
message string Yes Tell the agent what you need, in plain English, up to 10,000 characters
context.entity_type string No Hint: contact, task, document, inbox, etc.
context.entity_id string No A specific record to work with
context.action string No Hint: create, update, search, summarize
metadata object No Any extra key-value data for the agent

Example

curl -X POST "https://your-workspace.sois.ai/api/agent" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Api-Key: sois_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Create a contact for John Smith at Acme Corp, [email protected], +44 7700 900000",
    "context": { "entity_type": "contact", "action": "create" }
  }'

Response 202 Accepted

{
    "conversation_uuid": "6cafd8ba-dd51-4411-808e-671d1dd59561",
    "status": "accepted",
    "message": "Your request has been queued."
}

Your message is in the gateway. The agent takes it from here.


Receive the reply

You have two options: wait for the webhook, or poll the conversation.

Option 1: Webhook (recommended)

If your key has a response_url, the agent delivers the result directly to you when it's done: signed, verified, no polling required.

POST https://your-app.com/webhook
Content-Type: application/json
X-Signature: <hmac_sha256>
X-Conversation-UUID: 6cafd8ba-...

Resolved:

{
    "conversation_uuid": "6cafd8ba-...",
    "status": "resolved",
    "response": "Contact created: John Smith, Acme Corp, [email protected], +44 7700 900000."
}

Failed:

{
    "conversation_uuid": "6cafd8ba-...",
    "status": "failed",
    "error": "An error occurred while processing your request."
}

Option 2: Poll the conversation

GET /api/agent/{conversation_uuid}
Authorization: Bearer <your_token>
X-Api-Key: sois_...

Response 200 OK:

{
    "conversation_uuid": "6cafd8ba-...",
    "status": "resolved",
    "turns": [
        {
            "role": "user",
            "payload": { "message": "Find all contacts from London" },
            "timestamp": "2026-02-12T01:07:03+00:00"
        },
        {
            "role": "agent",
            "payload": {
                "content": "I found 12 contacts based in London..."
            },
            "timestamp": "2026-02-12T01:07:13+00:00"
        }
    ],
    "webhook": {
        "status": "delivered",
        "delivered_at": "2026-02-12T01:07:14+00:00"
    },
    "resolved_at": "2026-02-12T01:07:13+00:00",
    "expires_at": "2026-02-13T01:07:03+00:00",
    "created_at": "2026-02-12T01:07:03+00:00"
}

Conversation statuses

Status What's happening
open In the gateway, waiting for the agent
processing The agent is working on it
resolved Done. The reply is in the final turn
failed Couldn't complete after retries

Verifying webhook signatures

Every webhook is signed with HMAC-SHA256 using your key's signing secret. Always verify before processing.

Python:

import hmac, hashlib

expected = hmac.new(
    key=your_signing_secret.encode(),
    msg=raw_request_body.encode(),
    digestmod=hashlib.sha256
).hexdigest()

assert expected == request.headers['X-Signature']

Node.js:

const crypto = require('crypto');
const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(rawBody)
    .digest('hex');

if (expected !== req.headers['x-signature']) {
    throw new Error('Invalid signature');
}

PHP:

$expected = hash_hmac('sha256', $rawBody, $signingSecret);
if (!hash_equals($expected, $request->header('X-Signature'))) {
    abort(403, 'Invalid signature');
}

Example conversations

The agent has full access to your Sois AI workspace. Here are some things you can ask:

Search:

{ "message": "Find all contacts from London" }

Create:

{
    "message": "Create a contact: Jane Doe, CEO of Acme Corp, [email protected]",
    "context": { "entity_type": "contact", "action": "create" }
}

Email:

{
    "message": "Send an email to [email protected] introducing our new product line",
    "context": { "entity_type": "inbox", "action": "compose" }
}

Tasks:

{
    "message": "Create a task: Research competitor pricing for Q1 2026",
    "context": { "entity_type": "task", "action": "create" }
}

Summarise:

{
    "message": "Give me a full summary of this contact",
    "context": { "entity_type": "contact", "entity_id": "abc-123", "action": "summarize" }
}

Multi-step:

{ "message": "Find the Q1 report, summarise it, and email the summary to the sales team" }

The agent negotiates ambiguity. If it needs to search before it can act, it searches. If multiple records match, it picks the best one and tells you why. No rigid schemas, just intent.


Key management

Manage your keys from Settings > API Keys in your Sois AI workspace, or programmatically.

Create a key

POST /api/api-keys
{
    "label": "My CRM Integration",
    "response_url": "https://your-app.com/webhook",
    "budget_usd_cents": 5000,
    "budget_period": "monthly"
}

The response includes your key (shown once, so copy it immediately) and your signing secret for webhook verification.

Field Type Required Description
label string No A name for this key
response_url url No Where to deliver webhook replies
budget_usd_cents integer No Spending cap in USD cents
budget_period string No daily, monthly, or total

Manage keys

Method Endpoint Description
GET /api/api-keys List all your keys
POST /api/api-keys Create a new key
GET /api/api-keys/{id} Key details and usage stats
PUT /api/api-keys/{id} Update label, webhook URL, or budget
DELETE /api/api-keys/{id} Revoke a key

Budget controls

Traditional integrations throttle you with arbitrary rate limits: 100 requests per minute, 10,000 per day. The Chat Agent Gateway uses dollars.

Set a budget per key. The agent charges credits per action. You control what each integration is worth.

Field Description
budget_usd_cents Cap in USD cents (e.g. 5000 = $50). null = unlimited.
budget_period daily resets at midnight, monthly resets on the 1st, total never resets

When a budget is exceeded, messages return 429 with a clear explanation, not a cryptic error code.


Errors

Every error follows the same format:

{
    "error": {
        "code": "ERROR_CODE",
        "message": "A clear, human-readable explanation."
    }
}
HTTP Code What happened
401 UNAUTHENTICATED Missing or invalid access token
401 INVALID_API_KEY Missing or invalid key
403 KEY_OWNER_MISMATCH The key doesn't belong to you
403 KEY_REVOKED This key has been revoked
404 NOT_FOUND Conversation not found or expired
422 (none) Validation error (check the message)
429 BUDGET_EXCEEDED Your budget is spent. Top up or wait for reset

Limits

What Limit
Message length 10,000 characters
Conversation expiry 24 hours
Budget Per key, you decide