Response shape

The shapes every Dairo response uses: a single object, a list under data, one-time secrets on create, and predictable delete responses.

Every Dairo response comes back in one of a few predictable shapes. Learn them once and you can read an endpoint you have never called before, with no surprise wrapper keys to special-case.

A single object

When you fetch one thing, you get that thing back with an object field naming its type:

{
  "object": "message",
  "id": "msg_3aR8s0Kd",
  "inboxId": "inbox_123",
  "channel": "email",
  "direction": "outbound",
  "status": "sent",
  "from": { "address": "agent@yourdomain.com", "name": "Support" },
  "to": ["dev@example.com"],
  "subject": "Welcome",
  "createdAt": "2026-06-12T10:30:00Z"
}

The object field is always present, and it always names the type: message, thread, domain, inbox, webhook, api_key, template, audience, audience_member, contact, contact_handle, agent, event, and so on. Branch on object whenever you handle a value whose type you do not already know.

The type name is channel-neutral. An inbound reply, an outbound send, and an internal agent-to-agent hop are all object: "message"; the channel field says how each one traveled.

A list

Every collection uses one shape: object: "list", the items under data, and a pagination block. This holds for a full collection, a filtered result, a single item, or an empty result.

{
  "object": "list",
  "data": [
    { "object": "message", "id": "msg_1", "direction": "outbound", "status": "sent" },
    { "object": "message", "id": "msg_2", "direction": "inbound", "status": "received" }
  ],
  "pagination": {
    "nextCursor": "msg_2",
    "hasMore": true
  }
}

Each item in data is a full object with its own object field. The pagination block carries nextCursor (a string, or null on the last page) and hasMore (a boolean). Smaller collections that fit in one response return nextCursor: null and hasMore: false. To walk a large list, see Pagination.

curl "https://api.dairo.app/v1/messages?limit=25" \
  -H "Authorization: Bearer $DAIRO_API_KEY"

Objects that carry a nested collection

A few detail endpoints return the base object plus a related collection, inlined as a field. It is still one object with one object field:

  • A thread detail carries its messages.
  • A template detail carries the resolved version.
  • An audience detail (GET /v1/audiences/{id}) carries its members, each an object: "audience_member".
  • A contact detail carries its handles, each an object: "contact_handle".
  • An outbound message carries its delivery events, newest first; the same timeline is also a list at GET /v1/messages/{id}/events.
{
  "object": "thread",
  "id": "th_9fQ2",
  "subject": "Re: invoice",
  "messages": [
    { "object": "message", "id": "msg_1" },
    { "object": "message", "id": "msg_2" }
  ]
}

Create responses and one-time secrets

A create returns the new object flat, with its object discriminator, at 201. When the create mints a secret, the secret rides on the object as a field, alongside secretShownOnce: true:

{
  "object": "webhook",
  "id": "wh_7bK1",
  "url": "https://example.com/hooks/dairo",
  "events": ["message.received"],
  "signingSecret": "whsec_2bXr9f",
  "secretShownOnce": true
}

The field name depends on the resource: a webhook returns its signingSecret (whsec_…), an API key returns its secret (dairo_live_… or dairo_test_…). The value is shown once, at creation, and never returned again. Capture it immediately.

const key = await dairo.apiKeys.create({ name: "worker", scopes: ["messages:send"] });
console.log(key.id);     // the key id (safe to store and display)
console.log(key.secret); // dairo_live_… (shown once)

Status codes and deletes

The response shape pairs with predictable HTTP status codes:

OperationStatusBody
Create a resource (POST /v1/inboxes, /domains, /webhooks, /api-keys, /audiences, /templates, /agents, /buckets, a bucket's share links and bundles, /phone/calls, /phone/numbers)201the created object
Read or update (GET, PATCH, PUT)200the object, or a list
Send or action POST (send a message, broadcast to an audience, start an upload, replay events, enqueue an erasure job, verify, cancel)200 or 202the resulting object
Delete (DELETE /v1/{resource}/{id})204, or 200empty, or the object it changed

A message send returns 200, whether it goes out immediately or is scheduled; broadcasting to an audience returns 202, since Dairo expands and delivers it in the background. Deletes return 204 with no body. Three report what they changed and return 200 instead: deleting an agent passport returns the passport with deleted: true, clearing an agent's reputation returns the reset state, and releasing a phone number returns the number with status: "released".

Errors

Errors use their own shape, { "error": { "type", "code", "message", "param" } }, covered in full on the Errors page.

On this page