AgentQuickstart

Quickstart

Send a message, get the reply back, and discover + call the capabilities connected to the account. Use any API key with the agent:invoke scope for messaging, and capabilities:read/capabilities:invoke for the capability calls below — mint one under Settings → Developer → API Keys (see Authentication if you don't have one yet). There's no separate sub-key step: one key per integration is enough, and a reseller wanting per-end-customer separation just mints one ordinary key per customer the same way.

1. Send a message

idempotency_key is required — a retried call with the same key returns the same task rather than dispatching twice.

curl -X POST https://ai.synup.com/api/v1/agent/messages \
  -H "Authorization: Bearer sy_..." \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "req-2026-08-31-001",
    "message": "What'"'"'s our average review rating this month?"
  }'
{
  "data": {
    "id": "task_9f2c...",
    "status": "queued",
    "stream_url": "https://ai.synup.com/api/v1/agent/stream?token=...",
    "stream_refresh_token": "..."
  }
}

2. Get the reply

Simplest option — poll until status is terminal:

curl https://ai.synup.com/api/v1/agent/messages/task_9f2c... \
  -H "Authorization: Bearer sy_..."
{
  "data": {
    "id": "task_9f2c...",
    "status": "completed",
    "resultText": "Your average rating this month is 4.6, up from 4.4 last month.",
    "errorReason": null,
    "conversationId": "3f7900ae-34b2-47b0-8254-27864bf3b5c8"
  }
}

Want the reply live instead of polling, or pushed to you with no polling at all? See Streaming or register a webhook for agent.message.completed in Settings → Developer → Webhooks.

Continuing a conversation

A completed task's conversationId (shown above) is the thread to reuse for a follow-up — pass it back as conversation_id on your next dispatch to keep the same context instead of starting a new conversation. Don't generate this value yourself; it only ever comes from a prior task's response.

curl -X POST https://ai.synup.com/api/v1/agent/messages \
  -H "Authorization: Bearer sy_..." \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "req-2026-08-31-002",
    "message": "And how does that compare to last quarter?",
    "conversation_id": "3f7900ae-34b2-47b0-8254-27864bf3b5c8"
  }'

3. See what's connected (optional)

Capabilities only ever come from servers that required the account to actively connect them — a custom MCP server, a Pipedream workflow, or a Synup-provided connector template like Notion, Asana, or HubSpot that the account authorized with its own credentials. The line isn't "did Synup build it" — Synup built Notion's connector too — it's whether the account had to do anything to turn it on. Zero-action defaults every account gets automatically (SEO, content/web-scraping, weather, demographics, and the rest of the built-in toolset) aren't part of this surface regardless; reach those through the Agent instead. If you just want to know what's connected without paying for a full capability fetch, list the servers on their own:

curl https://ai.synup.com/api/v1/capabilities/servers \
  -H "Authorization: Bearer sy_..."
{
  "data": [
    { "name": "mycrm" },
    { "name": "pipedream-billing" }
  ],
  "count": 2
}

4. List connected capabilities

Returns every capability connected to this account, up to limit (default 25, max 100) per page. An account with no connected server yet gets { "data": [], "count": 0, "has_next_page": false, "next_cursor": null } — that's the normal, expected response, not an error. A tool's input_schema can be null if one hasn't been cached for it yet — don't assume it's always a populated object.

curl https://ai.synup.com/api/v1/capabilities \
  -H "Authorization: Bearer sy_..."
{
  "data": [
    { "name": "mycrm.lookup_contact", "description": "Look up a contact by email", "input_schema": { "type": "object", "properties": { "email": { "type": "string" } }, "required": ["email"] } },
    { "name": "pipedream-billing.create_invoice", "description": "Draft an invoice for a contact", "input_schema": null }
  ],
  "count": 2,
  "has_next_page": false,
  "next_cursor": null
}

count is the total number of matching capabilities across every page, not this page's data.length — it stays the same as you page through. has_next_pagetells you whether more results exist; when it's true, pass next_cursor back as cursor to fetch the next page:

curl "https://ai.synup.com/api/v1/capabilities?cursor=MjU" \
  -H "Authorization: Bearer sy_..."
{
  "data": [
    { "name": "mycrm.update_contact", "description": "Update a contact's fields", "input_schema": { "type": "object" } }
  ],
  "count": 47,
  "has_next_page": false,
  "next_cursor": null
}

The list is recomputed fresh on every call rather than read from a fixed snapshot, so if a server connects or disconnects while you're mid-walk through a large result set, entries can shift between pages. This is rare in practice — most integrations never notice — but if you need a fully consistent read, re-fetch from page 1 rather than trusting a long cursor walk to stay perfectly stable.

5. Search (optional)

Add ?q= to search by keyword instead of listing everything.

curl "https://ai.synup.com/api/v1/capabilities?q=contact" \
  -H "Authorization: Bearer sy_..."

6. Filter by server (optional)

Add ?server= to narrow the list to one connected server instead of searching or listing every one of them — useful once you already know which integration you want from step 3. Only that server's tools are fetched, not the whole catalog.

curl "https://ai.synup.com/api/v1/capabilities?server=mycrm" \
  -H "Authorization: Bearer sy_..."

Comma-separate multiple server names to narrow to more than one:

curl "https://ai.synup.com/api/v1/capabilities?server=mycrm,pipedream-billing" \
  -H "Authorization: Bearer sy_..."

Combine with ?q=to search within a specific server's tools. A name that doesn't match any connected server just yields an empty list for it — same as a q that matches nothing, never an error.

7. Call one

Pass the name exactly as the list gave it to you, plus whatever arguments that capability expects.

curl -X POST https://ai.synup.com/api/v1/capabilities/call \
  -H "Authorization: Bearer sy_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "mycrm.lookup_contact",
    "arguments": { "email": "jane@example.com" }
  }'
{
  "data": { "id": "c_204", "email": "jane@example.com", "name": "Jane Doe" }
}