Skip to content

API reference

Tact Platform API

Generated from the engine's OpenAPI file. Every request is JSON over HTTPS with a tenant secret key.

115 routesversion 2026-11-01

  • Base URL

    Placeholder until the domain is chosen.

    https://api.tact.example
  • Authentication

    Send the tenant secret key as a bearer token.

    Authorization: Bearer tact_sk_live_...
  • Account scope

    Account resources take the Account id or your own reference.

    Tact-Account: ext:cust_4821
  • Idempotency

    Every POST accepts a key, valid for 24 hours.

    Idempotency-Key: provision-cust_4821

Models2 routes

GET/v1/models

List the Tact models (OpenAI compatible)

models:invoke
Response example · 200
{
  "object": "list",
  "data": [
    {
      "id": "tact-1",
      "object": "model",
      "created": 1,
      "owned_by": "tact",
      "description": "string"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/chat/completions

Chat completion (OpenAI compatible; stream with stream: true)

Same wire format as OpenAI chat completions: point the OpenAI SDK at this base URL with a key that has models:invoke. The orchestrator picks the provider per request inside the data lock of the tenant (region and health data). With stream: true the answer comes as server-sent events (chat.completion.chunk) ending with [DONE]. Idempotency-Key is ignored here.

models:invoke

Parameters

  • Idempotency-Key

    header · string

Request body

  • modelrequired

    "tact-1" | "tact-1-mini" | "tact-1-pro"

  • messagesrequired

    object[]

  • tools

    object[]

  • tool_choice

    object

  • response_format

    object

    text, json_object or json_schema

  • max_tokens

    integer

    Default 1024, max 8192

  • max_completion_tokens

    integer

    Same as max_tokens

  • temperature

    number

    0 to 2 (values above 1 are sent as 1)

  • stop

    object

  • stream

    boolean

  • stream_options

    object

Request example
{
  "model": "tact-1",
  "messages": [
    {
      "role": "system",
      "content": "string",
      "tool_calls": [
        {}
      ],
      "tool_call_id": "string"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "Harbour Physio",
        "description": "string",
        "parameters": {}
      }
    }
  ],
  "tool_choice": "auto",
  "response_format": {},
  "max_tokens": 1,
  "max_completion_tokens": 1,
  "temperature": 1.5,
  "stop": "string",
  "stream": true,
  "stream_options": {
    "include_usage": true
  }
}
Response example · 200
{
  "id": "msg_9001",
  "object": "chat.completion",
  "created": 1,
  "model": "string",
  "choices": [
    {
      "index": 1,
      "message": {
        "role": "assistant",
        "content": "string",
        "tool_calls": [
          {}
        ]
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 1,
    "completion_tokens": 1,
    "total_tokens": 1
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Tenant8 routes

GET/v1/status

Component status (no authentication)

No authentication
Response example · 200
{
  "object": "status",
  "status": "operational",
  "components": [
    {
      "name": "Harbour Physio",
      "state": "ok",
      "since": "2026-11-02T09:30:00+00:00"
    }
  ],
  "checked_at": "2026-11-02T09:30:00+00:00"
}
Errors · 429
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/.well-known/jwks.json

Public keys of the Tact-Envelope sent on tool calls and outbox pulls (no authentication)

No authentication
Response example · 200
{
  "keys": [
    {
      "kty": "string",
      "crv": "string",
      "x": "string",
      "y": "string",
      "alg": "string",
      "use": "string",
      "kid": "string"
    }
  ]
}
Errors · 429
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/tenant

The authenticated tenant and key

Response example · 200
{
  "id": "ten_01JB6ZK8TQ0000000000000000",
  "object": "tenant",
  "slug": "string",
  "name": "Harbour Physio",
  "kind": "app",
  "status": "string",
  "default_data_region": "eu",
  "dpa_signed_at": "2026-11-02T09:30:00+00:00",
  "default_api_version": "string",
  "key": {
    "id": "key_01JB6ZK8TQ0000000000000000",
    "environment": "live",
    "scopes": [
      "accounts:read"
    ]
  },
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/tenant/readiness

Readiness checklist before going live

Response example · 200
{
  "object": "tenant_readiness",
  "mode": "live",
  "items": [
    {
      "key": "principal_verified",
      "status": "ok",
      "detail": "string"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/tenant/outbox_secret

Create or rotate the secret that signs pushes to ingress-tenant

The secret is shown once. Sign each push with Tact-Signature: t=<unix>,v1=hex(hmac_sha256(secret, t + "." + body)).

admin

Parameters

  • Idempotency-Key

    header · string

Response example · 201
{
  "object": "outbox_secret",
  "secret": "string",
  "push_url_path": "string",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/api_keys

List API keys

admin

Parameters

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "key_01JB6ZK8TQ0000000000000000",
      "object": "api_key",
      "environment": "live",
      "prefix": "string",
      "scopes": [
        "accounts:read"
      ],
      "expires_at": "2026-11-02T09:30:00+00:00",
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "last_used_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/api_keys

Create an API key (secret shown once)

admin

Parameters

  • Idempotency-Key

    header · string

Request body

  • environmentrequired

    "live" | "test"

  • scopesrequired

    "accounts:read" | "accounts:write" | "knowledge:read" | "knowledge:write" | "contacts:read" | "contacts:write" | "threads:read" | "threads:write" | "goals:write" | "memory:read" | "memory:write" | "policies:read" | "policies:write" | "approvals:read" | "approvals:write" | "packs:read" | "packs:write" | "events:write" | "usage:read" | "models:invoke" | "privacy:write" | "admin"[]

  • expires_at

    string (date-time)

Request example
{
  "environment": "live",
  "scopes": [
    "accounts:read"
  ],
  "expires_at": "2026-11-02T09:30:00+00:00"
}
Response example · 201
{
  "id": "key_01JB6ZK8TQ0000000000000000",
  "object": "api_key",
  "environment": "live",
  "prefix": "string",
  "scopes": [
    "accounts:read"
  ],
  "expires_at": "2026-11-02T09:30:00+00:00",
  "revoked_at": "2026-11-02T09:30:00+00:00",
  "last_used_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "secret": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/api_keys/{id}/revoke

Revoke an API key

admin

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "key_01JB6ZK8TQ0000000000000000",
  "object": "api_key",
  "environment": "live",
  "prefix": "string",
  "scopes": [
    "accounts:read"
  ],
  "expires_at": "2026-11-02T09:30:00+00:00",
  "revoked_at": "2026-11-02T09:30:00+00:00",
  "last_used_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Provisioning4 routes

GET/v1/provisioning_template

Read the provisioning template

accounts:read
Response example · 200
{
  "pack": {
    "id": "msg_9001",
    "key": "principal_verified",
    "version": "string"
  },
  "tool_base_url": "string",
  "agent": {
    "persona": {
      "name_template": "string",
      "default_locale": "en-IE"
    },
    "modes": [
      "assistant"
    ]
  },
  "playbooks": {
    "key": "on"
  },
  "policy_overrides": [
    {
      "action_type": "string",
      "decision": "allow",
      "conditions": [
        {
          "fact": "appointment.hours_until_start",
          "op": "eq",
          "value": null
        }
      ]
    }
  ],
  "budget": {
    "monthly_usd_micros": 1,
    "alert_at": [
      1.5
    ],
    "on_exceed": "alert"
  },
  "data_region_rule": {
    "key": "eu"
  },
  "onboarding": {
    "required_steps": [
      "string"
    ],
    "optional_steps": [
      "string"
    ]
  },
  "knowledge_kinds_expected": [
    "profile"
  ],
  "prerequisites_ack": [
    "string"
  ],
  "events": {
    "mode": "push"
  },
  "verify_tool_server": true,
  "object": "provisioning_template",
  "version": 1,
  "tool_server_verified_at": "2026-11-02T09:30:00+00:00",
  "rollout": {},
  "updated_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PUT/v1/provisioning_template

Write the provisioning template every new account receives

The tool server must list the tools required by the acknowledged phases at GET {tool_base_url}/.well-known/tact-tools, or the call fails with 422 missing_prerequisite.

accounts:write

Request body

  • packrequired

    object

  • tool_base_urlrequired

    string

    https URL of the tenant tool server

  • agent

    object

  • playbooks

    object

  • policy_overrides

    object[]

  • budget

    object

  • data_region_rule

    object

    ISO country or 'default' to region

  • onboarding

    object

  • knowledge_kinds_expected

    "profile" | "location" | "hours" | "holiday" | "service" | "staff" | "price" | "insurance" | "policy" | "faq" | "tone" | "document"[]

  • prerequisites_ack

    string[]

    Pack phases the tenant implemented (S0, S1)

  • events

    object

  • verify_tool_server

    boolean

    false only with a test key

Request example
{
  "pack": {
    "id": "msg_9001",
    "key": "principal_verified",
    "version": "string"
  },
  "tool_base_url": "string",
  "agent": {
    "persona": {
      "name_template": "string",
      "default_locale": "en-IE"
    },
    "modes": [
      "assistant"
    ]
  },
  "playbooks": {
    "key": "on"
  },
  "policy_overrides": [
    {
      "action_type": "string",
      "decision": "allow",
      "conditions": [
        {
          "fact": "appointment.hours_until_start",
          "op": "eq",
          "value": null
        }
      ]
    }
  ],
  "budget": {
    "monthly_usd_micros": 1,
    "alert_at": [
      1.5
    ],
    "on_exceed": "alert"
  },
  "data_region_rule": {
    "key": "eu"
  },
  "onboarding": {
    "required_steps": [
      "string"
    ],
    "optional_steps": [
      "string"
    ]
  },
  "knowledge_kinds_expected": [
    "profile"
  ],
  "prerequisites_ack": [
    "string"
  ],
  "events": {
    "mode": "push"
  },
  "verify_tool_server": true
}
Response example · 200
{
  "pack": {
    "id": "msg_9001",
    "key": "principal_verified",
    "version": "string"
  },
  "tool_base_url": "string",
  "agent": {
    "persona": {
      "name_template": "string",
      "default_locale": "en-IE"
    },
    "modes": [
      "assistant"
    ]
  },
  "playbooks": {
    "key": "on"
  },
  "policy_overrides": [
    {
      "action_type": "string",
      "decision": "allow",
      "conditions": [
        {
          "fact": "appointment.hours_until_start",
          "op": "eq",
          "value": null
        }
      ]
    }
  ],
  "budget": {
    "monthly_usd_micros": 1,
    "alert_at": [
      1.5
    ],
    "on_exceed": "alert"
  },
  "data_region_rule": {
    "key": "eu"
  },
  "onboarding": {
    "required_steps": [
      "string"
    ],
    "optional_steps": [
      "string"
    ]
  },
  "knowledge_kinds_expected": [
    "profile"
  ],
  "prerequisites_ack": [
    "string"
  ],
  "events": {
    "mode": "push"
  },
  "verify_tool_server": true,
  "object": "provisioning_template",
  "version": 1,
  "tool_server_verified_at": "2026-11-02T09:30:00+00:00",
  "rollout": {},
  "updated_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/provisioning_template/rollout

Roll the current template out to existing accounts (canary, then all after 48 h)

accounts:write

Parameters

  • Idempotency-Key

    header · string

Request body

  • phase

    "canary" | "all"

  • canary_percent

    integer

Request example
{
  "phase": "canary",
  "canary_percent": 1
}
Response example · 200
{
  "object": "provisioning_rollout",
  "version": 1,
  "phase": "canary",
  "canary_percent": 1,
  "canary_started_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00",
  "accounts_updated": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/accounts/provision

Provision an account with its owner, agent, pack, policy, budget and onboarding (upsert by external_ref)

Returns 201 when the account is created and 200 when it already existed. Never creates a second agent.

accounts:write

Parameters

  • Idempotency-Key

    header · string

Request body

  • external_refrequired

    string

    Account id in the tenant system

  • namerequired

    string

  • kind

    "business" | "person"

  • countryrequired

    string

    ISO 3166-1 alpha-2; any country works when timezone, locale, currency and regime are sent

  • timezone

    string

    IANA time zone

  • locale

    string

    BCP 47

  • currency

    string

    ISO 4217

  • regime

    string

    Data protection regime (gdpr, lgpd, appi ...)

  • holds_health_data

    boolean

  • ownerrequired

    object

  • lawful_basis

    object

    Lawful basis per purpose (service, reminder, recall, marketing)

Request example
{
  "external_ref": "cust_4821",
  "name": "Harbour Physio",
  "kind": "business",
  "country": "IE",
  "timezone": "Europe/Dublin",
  "locale": "en-IE",
  "currency": "EUR",
  "regime": "gdpr",
  "holds_health_data": true,
  "owner": {
    "external_ref": "cust_4821",
    "display_name": "Niamh Byrne",
    "kind": "person",
    "role": "string",
    "channels": [
      {
        "channel": "whatsapp",
        "address": "+353871234567",
        "priority": 1
      }
    ],
    "approval_permissions": [
      "string"
    ],
    "locale": "en-IE",
    "timezone": "Europe/Dublin"
  },
  "lawful_basis": {
    "key": "string"
  }
}
Response example · 201
{
  "account": {
    "id": "acc_01JB6ZK8TQ0000000000000000",
    "object": "account",
    "external_ref": "cust_4821",
    "status": "string",
    "data_region": "eu"
  },
  "agent": {
    "id": "agt_01JB6ZK8TQ0000000000000000",
    "object": "agent",
    "status": "string",
    "persona": {
      "name": "Harbour Physio"
    },
    "pack": {
      "id": "pck_01JB6ZK8TQ0000000000000000",
      "key": "principal_verified",
      "version": "string"
    }
  },
  "owner_principal": {
    "id": "prn_01JB6ZK8TQ0000000000000000",
    "object": "principal",
    "channels_pending_verification": [
      "whatsapp"
    ]
  },
  "onboarding": {
    "steps": [
      {
        "key": "principal_verified",
        "done": true,
        "at": "2026-11-02T09:30:00+00:00",
        "optional": true
      }
    ]
  },
  "template_version": 1,
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Accounts7 routes

GET/v1/accounts

List accounts

accounts:read

Parameters

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

  • external_ref

    query · string

  • created_after

    query · string (date-time)

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "acc_01JB6ZK8TQ0000000000000000",
      "object": "account",
      "external_ref": "cust_4821",
      "name": "Harbour Physio",
      "kind": "string",
      "status": "onboarding",
      "country": "IE",
      "timezone": "Europe/Dublin",
      "locale": "en-IE",
      "currency": "EUR",
      "regime": "gdpr",
      "data_region": "eu",
      "holds_health_data": true,
      "quiet_hours": {
        "start": "20:00",
        "end": "09:00"
      },
      "lawful_basis": {},
      "limits": {},
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "onboarding": {
        "steps": [
          {
            "key": "principal_verified",
            "done": true,
            "at": "2026-11-02T09:30:00+00:00",
            "optional": true
          }
        ]
      },
      "template_version": 1,
      "paused_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/accounts/{id}

Retrieve an account

accounts:read

Parameters

  • idrequired

    path · string

Response example · 200
{
  "id": "acc_01JB6ZK8TQ0000000000000000",
  "object": "account",
  "external_ref": "cust_4821",
  "name": "Harbour Physio",
  "kind": "string",
  "status": "onboarding",
  "country": "IE",
  "timezone": "Europe/Dublin",
  "locale": "en-IE",
  "currency": "EUR",
  "regime": "gdpr",
  "data_region": "eu",
  "holds_health_data": true,
  "quiet_hours": {
    "start": "20:00",
    "end": "09:00"
  },
  "lawful_basis": {},
  "limits": {},
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "onboarding": {
    "steps": [
      {
        "key": "principal_verified",
        "done": true,
        "at": "2026-11-02T09:30:00+00:00",
        "optional": true
      }
    ]
  },
  "template_version": 1,
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/accounts/{id}

Update an account and mark onboarding steps done

accounts:write

Parameters

  • idrequired

    path · string

Request body

  • name

    string

  • locale

    string

  • timezone

    string

  • holds_health_data

    boolean

  • quiet_hours

    object

  • lawful_basis

    object

  • onboarding

    object

    Steps done in the tenant product: disclosure_reviewed, playbooks_reviewed, account_taught, knowledge_synced

Request example
{
  "name": "Harbour Physio",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "holds_health_data": true,
  "quiet_hours": {
    "start": "20:00",
    "end": "09:00"
  },
  "lawful_basis": {
    "key": "string"
  },
  "onboarding": {
    "key": true
  }
}
Response example · 200
{
  "id": "acc_01JB6ZK8TQ0000000000000000",
  "object": "account",
  "external_ref": "cust_4821",
  "name": "Harbour Physio",
  "kind": "string",
  "status": "onboarding",
  "country": "IE",
  "timezone": "Europe/Dublin",
  "locale": "en-IE",
  "currency": "EUR",
  "regime": "gdpr",
  "data_region": "eu",
  "holds_health_data": true,
  "quiet_hours": {
    "start": "20:00",
    "end": "09:00"
  },
  "lawful_basis": {},
  "limits": {},
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "onboarding": {
    "steps": [
      {
        "key": "principal_verified",
        "done": true,
        "at": "2026-11-02T09:30:00+00:00",
        "optional": true
      }
    ]
  },
  "template_version": 1,
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/accounts/{id}/pause

Pause an account

accounts:write

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "acc_01JB6ZK8TQ0000000000000000",
  "object": "account",
  "external_ref": "cust_4821",
  "name": "Harbour Physio",
  "kind": "string",
  "status": "onboarding",
  "country": "IE",
  "timezone": "Europe/Dublin",
  "locale": "en-IE",
  "currency": "EUR",
  "regime": "gdpr",
  "data_region": "eu",
  "holds_health_data": true,
  "quiet_hours": {
    "start": "20:00",
    "end": "09:00"
  },
  "lawful_basis": {},
  "limits": {},
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "onboarding": {
    "steps": [
      {
        "key": "principal_verified",
        "done": true,
        "at": "2026-11-02T09:30:00+00:00",
        "optional": true
      }
    ]
  },
  "template_version": 1,
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/accounts/{id}/resume

Resume a paused account

accounts:write

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "acc_01JB6ZK8TQ0000000000000000",
  "object": "account",
  "external_ref": "cust_4821",
  "name": "Harbour Physio",
  "kind": "string",
  "status": "onboarding",
  "country": "IE",
  "timezone": "Europe/Dublin",
  "locale": "en-IE",
  "currency": "EUR",
  "regime": "gdpr",
  "data_region": "eu",
  "holds_health_data": true,
  "quiet_hours": {
    "start": "20:00",
    "end": "09:00"
  },
  "lawful_basis": {},
  "limits": {},
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "onboarding": {
    "steps": [
      {
        "key": "principal_verified",
        "done": true,
        "at": "2026-11-02T09:30:00+00:00",
        "optional": true
      }
    ]
  },
  "template_version": 1,
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/accounts/{id}/close

Close an account and schedule the cascade erasure

accounts:write

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Request body

  • retention_days

    integer

  • reason

    string

Request example
{
  "retention_days": 0,
  "reason": "requested by the account"
}
Response example · 200
{
  "account": {
    "id": "acc_01JB6ZK8TQ0000000000000000",
    "object": "account",
    "external_ref": "cust_4821",
    "name": "Harbour Physio",
    "kind": "string",
    "status": "onboarding",
    "country": "IE",
    "timezone": "Europe/Dublin",
    "locale": "en-IE",
    "currency": "EUR",
    "regime": "gdpr",
    "data_region": "eu",
    "holds_health_data": true,
    "quiet_hours": {
      "start": "20:00",
      "end": "09:00"
    },
    "lawful_basis": {},
    "limits": {},
    "agent_id": "agt_01JB6ZK8TQ0000000000000000",
    "onboarding": {
      "steps": [
        {
          "key": "principal_verified",
          "done": true,
          "at": "2026-11-02T09:30:00+00:00",
          "optional": true
        }
      ]
    },
    "template_version": 1,
    "paused_at": "2026-11-02T09:30:00+00:00",
    "created_at": "2026-11-02T09:30:00+00:00"
  },
  "erasure_request_id": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/account_sessions

Create a 15 minute session token for Tact Elements

Tact-Account requiredaccounts:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • principal_idrequired

    string

  • componentsrequired

    "tact-onboarding" | "tact-thread" | "tact-approvals" | "tact-knowledge" | "tact-policies" | "tact-usage" | "whatsapp-connect"[]

  • step_up

    boolean

Request example
{
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "components": [
    "tact-onboarding"
  ],
  "step_up": true
}
Response example · 201
{
  "id": "ses_01JB6ZK8TQ0000000000000000",
  "object": "account_session",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "components": [
    "string"
  ],
  "step_up": true,
  "token": "string",
  "expires_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Principals6 routes

GET/v1/principals

List principals

Tact-Account requiredaccounts:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "prn_01JB6ZK8TQ0000000000000000",
      "object": "principal",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "kind": "person",
      "role": "string",
      "display_name": "Niamh Byrne",
      "external_ref": "cust_4821",
      "locale": "en-IE",
      "timezone": "Europe/Dublin",
      "approval_permissions": [
        "string"
      ],
      "channels": [
        {
          "id": "pch_01JB6ZK8TQ0000000000000000",
          "object": "principal_channel",
          "channel": "whatsapp",
          "address": "+353871234567",
          "priority": 1,
          "verified_at": "2026-11-02T09:30:00+00:00"
        }
      ],
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/principals

Create or update a principal (upsert by external_ref)

Tact-Account requiredaccounts:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • kind

    "person" | "organization" | "entity"

  • role

    "owner" | "admin" | "staff" | "entity" | "reception" | "technical_lead"

  • display_namerequired

    string

  • external_ref

    string

  • approval_permissions

    string[]

  • channels

    object[]

  • locale

    string

  • timezone

    string

Request example
{
  "kind": "person",
  "role": "owner",
  "display_name": "Niamh Byrne",
  "external_ref": "cust_4821",
  "approval_permissions": [
    "string"
  ],
  "channels": [
    {
      "channel": "whatsapp",
      "address": "+353871234567",
      "priority": 1
    }
  ],
  "locale": "en-IE",
  "timezone": "Europe/Dublin"
}
Response example · 201
{
  "id": "prn_01JB6ZK8TQ0000000000000000",
  "object": "principal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "kind": "person",
  "role": "string",
  "display_name": "Niamh Byrne",
  "external_ref": "cust_4821",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "approval_permissions": [
    "string"
  ],
  "channels": [
    {
      "id": "pch_01JB6ZK8TQ0000000000000000",
      "object": "principal_channel",
      "channel": "whatsapp",
      "address": "+353871234567",
      "priority": 1,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/principals/{id}

Retrieve a principal

Tact-Account optionalaccounts:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "prn_01JB6ZK8TQ0000000000000000",
  "object": "principal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "kind": "person",
  "role": "string",
  "display_name": "Niamh Byrne",
  "external_ref": "cust_4821",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "approval_permissions": [
    "string"
  ],
  "channels": [
    {
      "id": "pch_01JB6ZK8TQ0000000000000000",
      "object": "principal_channel",
      "channel": "whatsapp",
      "address": "+353871234567",
      "priority": 1,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/principals/{id}

Update a principal

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • display_name

    string

  • role

    string

  • approval_permissions

    string[]

  • locale

    string

  • timezone

    string

Request example
{
  "display_name": "Niamh Byrne",
  "role": "string",
  "approval_permissions": [
    "string"
  ],
  "locale": "en-IE",
  "timezone": "Europe/Dublin"
}
Response example · 200
{
  "id": "prn_01JB6ZK8TQ0000000000000000",
  "object": "principal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "kind": "person",
  "role": "string",
  "display_name": "Niamh Byrne",
  "external_ref": "cust_4821",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "approval_permissions": [
    "string"
  ],
  "channels": [
    {
      "id": "pch_01JB6ZK8TQ0000000000000000",
      "object": "principal_channel",
      "channel": "whatsapp",
      "address": "+353871234567",
      "priority": 1,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/principals/{id}/channels

Add a channel to a principal and send a verification code

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • channelrequired

    "whatsapp" | "sms" | "email" | "voice" | "telegram" | "in_app" | "imessage"

  • addressrequired

    string

    E.164 for phones, e-mail address, or the tenant user id for in_app

  • priority

    integer

Request example
{
  "channel": "whatsapp",
  "address": "+353871234567",
  "priority": 1
}
Response example · 201
{
  "id": "pch_01JB6ZK8TQ0000000000000000",
  "object": "principal_channel",
  "channel": "whatsapp",
  "address": "+353871234567",
  "priority": 1,
  "verified_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/principals/{id}/channels/{cid}/verify

Verify a principal channel with the 6 digit code (without code: resend it)

With a test key nothing is sent and the code is always 000000.

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • cidrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • code

    string

Request example
{
  "code": "482913"
}
Response example · 200
{
  "id": "pch_01JB6ZK8TQ0000000000000000",
  "object": "principal_channel",
  "channel": "whatsapp",
  "address": "+353871234567",
  "priority": 1,
  "verified_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Agent5 routes

GET/v1/agent

The agent of the account in Tact-Account

Tact-Account requiredaccounts:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

Response example · 200
{
  "id": "agt_01JB6ZK8TQ0000000000000000",
  "object": "agent",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "status": "onboarding",
  "modes": [
    "assistant"
  ],
  "name": "Harbour Physio",
  "persona": {},
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "model_profile": "string",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string"
  },
  "pack_install_id": "pin_01JB6ZK8TQ0000000000000000",
  "playbooks": {
    "key": "on"
  },
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/agents/{id}

Retrieve an agent

Tact-Account optionalaccounts:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "agt_01JB6ZK8TQ0000000000000000",
  "object": "agent",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "status": "onboarding",
  "modes": [
    "assistant"
  ],
  "name": "Harbour Physio",
  "persona": {},
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "model_profile": "string",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string"
  },
  "pack_install_id": "pin_01JB6ZK8TQ0000000000000000",
  "playbooks": {
    "key": "on"
  },
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/agents/{id}

Update persona, channels and overrides

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • channel_ids

    string[]

  • modes

    "assistant" | "representative"[]

  • persona

    object

  • overrides

    object

Request example
{
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "modes": [
    "assistant"
  ],
  "persona": {
    "name": "Harbour Physio",
    "default_locale": "en-IE",
    "signature": "string"
  },
  "overrides": {
    "key": 1.5
  }
}
Response example · 200
{
  "id": "agt_01JB6ZK8TQ0000000000000000",
  "object": "agent",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "status": "onboarding",
  "modes": [
    "assistant"
  ],
  "name": "Harbour Physio",
  "persona": {},
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "model_profile": "string",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string"
  },
  "pack_install_id": "pin_01JB6ZK8TQ0000000000000000",
  "playbooks": {
    "key": "on"
  },
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/agents/{id}/pause

Pause the agent

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "agt_01JB6ZK8TQ0000000000000000",
  "object": "agent",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "status": "onboarding",
  "modes": [
    "assistant"
  ],
  "name": "Harbour Physio",
  "persona": {},
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "model_profile": "string",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string"
  },
  "pack_install_id": "pin_01JB6ZK8TQ0000000000000000",
  "playbooks": {
    "key": "on"
  },
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/agents/{id}/resume

Resume the agent

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "agt_01JB6ZK8TQ0000000000000000",
  "object": "agent",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "status": "onboarding",
  "modes": [
    "assistant"
  ],
  "name": "Harbour Physio",
  "persona": {},
  "channel_ids": [
    "chn_01JB6ZK8TQ0000000000000000"
  ],
  "model_profile": "string",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string"
  },
  "pack_install_id": "pin_01JB6ZK8TQ0000000000000000",
  "playbooks": {
    "key": "on"
  },
  "paused_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Channels5 routes

POST/v1/channels/whatsapp/signup_sessions

Start a WhatsApp Embedded Signup for the account

Tact-Account requiredaccounts:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • return_urlrequired

    string

    https URL

  • coexistence_allowed

    boolean

  • display_name_hint

    string

Request example
{
  "return_url": "https://example.com/settings?tact=whatsapp",
  "coexistence_allowed": true,
  "display_name_hint": "string"
}
Response example · 201
{
  "id": "wss_01JB6ZK8TQ0000000000000000",
  "object": "whatsapp_signup_session",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "status": "open",
  "return_url": "https://example.com/settings?tact=whatsapp",
  "coexistence_allowed": true,
  "channel_id": "string",
  "error_code": "string",
  "expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00",
  "launch": {
    "app_id": "string",
    "config_id": "string",
    "state": "string",
    "extras": {}
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/channels/whatsapp/signup_sessions/{id}/complete

Finish the Embedded Signup with the code returned by Meta

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • coderequired

    string

    Code returned by Meta

  • staterequired

    string

  • messaging_account_idrequired

    string

  • phone_number_idrequired

    string

Request example
{
  "code": "482913",
  "state": "string",
  "messaging_account_id": "string",
  "phone_number_id": "string"
}
Response example · 200
{
  "id": "wss_01JB6ZK8TQ0000000000000000",
  "object": "whatsapp_signup_session",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "status": "open",
  "return_url": "https://example.com/settings?tact=whatsapp",
  "coexistence_allowed": true,
  "channel_id": "string",
  "error_code": "string",
  "expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00",
  "channel": {
    "id": "chn_01JB6ZK8TQ0000000000000000",
    "object": "channel",
    "account_id": "acc_01JB6ZK8TQ0000000000000000",
    "channel": "whatsapp",
    "provider": "string",
    "address": "+353871234567",
    "status": "pending",
    "shared": true,
    "coexistence": true,
    "messaging_account_id": "string",
    "phone_number_id": "string",
    "created_at": "2026-11-02T09:30:00+00:00"
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/channels

List the account channels

Tact-Account requiredaccounts:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • channel

    query · "whatsapp" | "sms" | "email" | "voice" | "telegram" | "in_app" | "imessage"

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "chn_01JB6ZK8TQ0000000000000000",
      "object": "channel",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "channel": "whatsapp",
      "provider": "string",
      "address": "+353871234567",
      "status": "pending",
      "shared": true,
      "coexistence": true,
      "messaging_account_id": "string",
      "phone_number_id": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/channels/{id}/templates

List channel templates

Tact-Account optionalaccounts:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "tpl_01JB6ZK8TQ0000000000000000",
      "object": "channel_template",
      "channel_id": "chn_01JB6ZK8TQ0000000000000000",
      "name": "Harbour Physio",
      "locale": "en-IE",
      "category": "utility",
      "status": "string",
      "variables": [
        null
      ]
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/channels/{id}/templates/sync

Submit the pack templates to Meta for this channel

Tact-Account optionalaccounts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 202
{
  "object": "templates_sync",
  "channel_id": "chn_01JB6ZK8TQ0000000000000000",
  "status": "queued",
  "job_id": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Knowledge10 routes

GET/v1/knowledge

List knowledge items

Tact-Account requiredknowledge:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • kind

    query · string

  • include_deleted

    query · boolean

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "kni_01JB6ZK8TQ0000000000000000",
      "object": "knowledge_item",
      "kind": "profile",
      "external_ref": "cust_4821",
      "data": {},
      "visibility": "all",
      "authority": "tenant_system",
      "source_updated_at": "2026-11-02T09:30:00+00:00",
      "content_sha256": "string",
      "confirmed_by": "string",
      "deleted": true,
      "deleted_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "updated_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PUT/v1/knowledge/{kind}/{ref}

Write one knowledge item

Tact-Account requiredknowledge:write

Parameters

  • kindrequired

    path · string

  • refrequired

    path · string

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

Request body

  • source_updated_atrequired

    string (date-time)

    Version in the tenant system; older writes are ignored

  • datarequired

    object

    Validated by the pack schema of the kind

  • visibility

    "all" | "assistant_only"

Request example
{
  "source_updated_at": "2026-11-02T09:30:00+00:00",
  "data": {},
  "visibility": "all"
}
Response example · 200
{
  "id": "kni_01JB6ZK8TQ0000000000000000",
  "object": "knowledge_item",
  "kind": "profile",
  "external_ref": "cust_4821",
  "data": {},
  "visibility": "all",
  "authority": "tenant_system",
  "source_updated_at": "2026-11-02T09:30:00+00:00",
  "content_sha256": "string",
  "confirmed_by": "string",
  "deleted": true,
  "deleted_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "updated_at": "2026-11-02T09:30:00+00:00",
  "result": "upserted",
  "knowledge_version": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
DELETE/v1/knowledge/{kind}/{ref}

Tombstone one knowledge item

Tact-Account requiredknowledge:write

Parameters

  • kindrequired

    path · string

  • refrequired

    path · string

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

Response example · 200
{
  "object": "knowledge_item",
  "kind": "profile",
  "external_ref": "cust_4821",
  "deleted": true,
  "knowledge_version": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/knowledge/syncs

Snapshot or delta sync (up to 1,000 items per call; parts for bigger snapshots)

In snapshot mode, items of the listed kinds that did not arrive become tombstones once the last part arrives.

Tact-Account requiredknowledge:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • moderequired

    "snapshot" | "delta"

  • kinds

    "profile" | "location" | "hours" | "holiday" | "service" | "staff" | "price" | "insurance" | "policy" | "faq" | "tone" | "document"[]

  • sync_ref

    string

    Tenant id of the sync; required with parts

  • part

    integer

  • total_parts

    integer

  • items

    object[]

  • deletes

    object[]

Request example
{
  "mode": "snapshot",
  "kinds": [
    "profile"
  ],
  "sync_ref": "string",
  "part": 1,
  "total_parts": 1,
  "items": [
    {
      "kind": "profile",
      "external_ref": "cust_4821",
      "source_updated_at": "2026-11-02T09:30:00+00:00",
      "data": {},
      "visibility": "all"
    }
  ],
  "deletes": [
    {
      "kind": "profile",
      "external_ref": "cust_4821"
    }
  ]
}
Response example · 202
{
  "id": "ksy_01JB6ZK8TQ0000000000000000",
  "object": "knowledge_sync",
  "mode": "string",
  "kinds": [
    "profile"
  ],
  "sync_ref": "string",
  "status": "processing",
  "parts_expected": 1,
  "parts_received": 1,
  "counts": {},
  "knowledge_version": 1,
  "started_at": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00",
  "sync_id": "ksy_01JB6ZK8TQ0000000000000000",
  "rejected": [
    {
      "index": 1,
      "external_ref": "cust_4821",
      "code": "482913",
      "param": "string",
      "message": "Contact has no active consent for purpose 'recall' on channel 'whatsapp'."
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/knowledge/syncs/{id}

Retrieve a sync

Tact-Account optionalknowledge:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "ksy_01JB6ZK8TQ0000000000000000",
  "object": "knowledge_sync",
  "mode": "string",
  "kinds": [
    "profile"
  ],
  "sync_ref": "string",
  "status": "processing",
  "parts_expected": 1,
  "parts_received": 1,
  "counts": {},
  "knowledge_version": 1,
  "started_at": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/knowledge/digest

Digest per kind for the daily reconciliation

sha256 of the lines `external_ref TAB content_sha256 LF`, sorted by external_ref in byte order.

Tact-Account requiredknowledge:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

Response example · 200
{
  "object": "knowledge_digest",
  "algorithm": "string",
  "knowledge_version": 1,
  "kinds": {
    "key": {
      "count": 1,
      "sha256": "string"
    }
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/knowledge/teach

Teach the agent (free text or structured proposals)

Tact-Account requiredknowledge:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • principal_idrequired

    string

  • text

    string

  • kind

    "profile" | "location" | "hours" | "holiday" | "service" | "staff" | "price" | "insurance" | "policy" | "faq" | "tone" | "document"

  • proposals

    object[]

Request example
{
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "text": "Can I move Thursday to Friday?",
  "kind": "profile",
  "proposals": [
    {
      "kind": "profile",
      "data": {},
      "summary": {},
      "external_ref": "cust_4821"
    }
  ]
}
Response example · 202
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "kpr_01JB6ZK8TQ0000000000000000",
      "object": "knowledge_proposal",
      "kind": "string",
      "proposed_data": {},
      "summary": {},
      "source": "string",
      "status": "pending",
      "conflict_with": "string",
      "decided_by": "string",
      "decided_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "item": {
        "id": "kni_01JB6ZK8TQ0000000000000000",
        "object": "knowledge_item",
        "kind": "profile",
        "external_ref": "cust_4821",
        "data": {},
        "visibility": "all",
        "authority": "tenant_system",
        "source_updated_at": "2026-11-02T09:30:00+00:00",
        "content_sha256": "string",
        "confirmed_by": "string",
        "deleted": true,
        "deleted_at": "2026-11-02T09:30:00+00:00",
        "created_at": "2026-11-02T09:30:00+00:00",
        "updated_at": "2026-11-02T09:30:00+00:00"
      }
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/knowledge/proposals

List knowledge proposals

Tact-Account requiredknowledge:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "kpr_01JB6ZK8TQ0000000000000000",
      "object": "knowledge_proposal",
      "kind": "string",
      "proposed_data": {},
      "summary": {},
      "source": "string",
      "status": "pending",
      "conflict_with": "string",
      "decided_by": "string",
      "decided_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "item": {
        "id": "kni_01JB6ZK8TQ0000000000000000",
        "object": "knowledge_item",
        "kind": "profile",
        "external_ref": "cust_4821",
        "data": {},
        "visibility": "all",
        "authority": "tenant_system",
        "source_updated_at": "2026-11-02T09:30:00+00:00",
        "content_sha256": "string",
        "confirmed_by": "string",
        "deleted": true,
        "deleted_at": "2026-11-02T09:30:00+00:00",
        "created_at": "2026-11-02T09:30:00+00:00",
        "updated_at": "2026-11-02T09:30:00+00:00"
      }
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/knowledge/proposals/{id}/confirm

Confirm a proposal (conflicts with tenant data are reported)

Tact-Account optionalknowledge:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • principal_idrequired

    string

  • data

    object

    Overrides the proposed data

  • external_ref

    string

Request example
{
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "data": {},
  "external_ref": "cust_4821"
}
Response example · 200
{
  "id": "kpr_01JB6ZK8TQ0000000000000000",
  "object": "knowledge_proposal",
  "kind": "string",
  "proposed_data": {},
  "summary": {},
  "source": "string",
  "status": "pending",
  "conflict_with": "string",
  "decided_by": "string",
  "decided_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "item": {
    "id": "kni_01JB6ZK8TQ0000000000000000",
    "object": "knowledge_item",
    "kind": "profile",
    "external_ref": "cust_4821",
    "data": {},
    "visibility": "all",
    "authority": "tenant_system",
    "source_updated_at": "2026-11-02T09:30:00+00:00",
    "content_sha256": "string",
    "confirmed_by": "string",
    "deleted": true,
    "deleted_at": "2026-11-02T09:30:00+00:00",
    "created_at": "2026-11-02T09:30:00+00:00",
    "updated_at": "2026-11-02T09:30:00+00:00"
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/knowledge/proposals/{id}/reject

Reject a proposal

Tact-Account optionalknowledge:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • principal_idrequired

    string

Request example
{
  "principal_id": "prn_01JB6ZK8TQ0000000000000000"
}
Response example · 200
{
  "id": "kpr_01JB6ZK8TQ0000000000000000",
  "object": "knowledge_proposal",
  "kind": "string",
  "proposed_data": {},
  "summary": {},
  "source": "string",
  "status": "pending",
  "conflict_with": "string",
  "decided_by": "string",
  "decided_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "item": {
    "id": "kni_01JB6ZK8TQ0000000000000000",
    "object": "knowledge_item",
    "kind": "profile",
    "external_ref": "cust_4821",
    "data": {},
    "visibility": "all",
    "authority": "tenant_system",
    "source_updated_at": "2026-11-02T09:30:00+00:00",
    "content_sha256": "string",
    "confirmed_by": "string",
    "deleted": true,
    "deleted_at": "2026-11-02T09:30:00+00:00",
    "created_at": "2026-11-02T09:30:00+00:00",
    "updated_at": "2026-11-02T09:30:00+00:00"
  }
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Contacts9 routes

GET/v1/contacts

List contacts

Tact-Account requiredcontacts:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • external_ref

    query · string

  • created_after

    query · string (date-time)

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "con_01JB6ZK8TQ0000000000000000",
      "object": "contact",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "external_ref": "cust_4821",
      "kind": "string",
      "display_name": "Niamh Byrne",
      "locale": "en-IE",
      "timezone": "Europe/Dublin",
      "country": "IE",
      "is_minor": true,
      "guardian_contact_id": "string",
      "identity_level": "string",
      "do_not_contact": true,
      "channels": [
        {
          "id": "cch_01JB6ZK8TQ0000000000000000",
          "channel": "whatsapp",
          "address": "+353871234567",
          "is_preferred": true,
          "verified_at": "2026-11-02T09:30:00+00:00"
        }
      ],
      "consents": [
        {
          "id": "cst_01JB6ZK8TQ0000000000000000",
          "object": "consent",
          "contact_id": "con_01JB6ZK8TQ0000000000000000",
          "purpose": "string",
          "channel": "string",
          "lawful_basis": "string",
          "granted_at": "2026-11-02T09:30:00+00:00",
          "source": "string",
          "evidence": {},
          "revoked_at": "2026-11-02T09:30:00+00:00",
          "revoked_via": "string",
          "created_at": "2026-11-02T09:30:00+00:00"
        }
      ],
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/contacts

Create or update a contact (upsert by external_ref or channel address)

Tact-Account requiredcontacts:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • external_ref

    string

  • display_name

    string

  • kind

    "person" | "organization" | "agent"

  • locale

    string

  • timezone

    string

  • country

    string

  • is_minor

    boolean

  • guardian_contact_id

    string

  • channels

    object[]

  • consents

    object[]

Request example
{
  "external_ref": "cust_4821",
  "display_name": "Niamh Byrne",
  "kind": "person",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "con_01JB6ZK8TQ0000000000000000",
  "channels": [
    {
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true
    }
  ],
  "consents": [
    {
      "purpose": "reminder",
      "channel": "whatsapp",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "lawful_basis": "string"
    }
  ]
}
Response example · 201
{
  "id": "con_01JB6ZK8TQ0000000000000000",
  "object": "contact",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "external_ref": "cust_4821",
  "kind": "string",
  "display_name": "Niamh Byrne",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "string",
  "identity_level": "string",
  "do_not_contact": true,
  "channels": [
    {
      "id": "cch_01JB6ZK8TQ0000000000000000",
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "consents": [
    {
      "id": "cst_01JB6ZK8TQ0000000000000000",
      "object": "consent",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "purpose": "string",
      "channel": "string",
      "lawful_basis": "string",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "revoked_via": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/contacts/batch

Upsert up to 500 contacts

Tact-Account requiredcontacts:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • contactsrequired

    object[]

Request example
{
  "contacts": [
    {
      "external_ref": "cust_4821",
      "display_name": "Niamh Byrne",
      "kind": "person",
      "locale": "en-IE",
      "timezone": "Europe/Dublin",
      "country": "IE",
      "is_minor": true,
      "guardian_contact_id": "con_01JB6ZK8TQ0000000000000000",
      "channels": [
        {
          "channel": "whatsapp",
          "address": "+353871234567",
          "is_preferred": true
        }
      ],
      "consents": [
        {
          "purpose": "reminder",
          "channel": "whatsapp",
          "granted_at": "2026-11-02T09:30:00+00:00",
          "source": "string",
          "evidence": {},
          "lawful_basis": "string"
        }
      ]
    }
  ]
}
Response example · 200
{
  "object": "contact_batch",
  "results": [
    {
      "index": 1,
      "status": "created",
      "id": "con_01JB6ZK8TQ0000000000000000",
      "external_ref": "cust_4821",
      "error": {}
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/contacts/{id}

Retrieve a contact

Tact-Account optionalcontacts:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "con_01JB6ZK8TQ0000000000000000",
  "object": "contact",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "external_ref": "cust_4821",
  "kind": "string",
  "display_name": "Niamh Byrne",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "string",
  "identity_level": "string",
  "do_not_contact": true,
  "channels": [
    {
      "id": "cch_01JB6ZK8TQ0000000000000000",
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "consents": [
    {
      "id": "cst_01JB6ZK8TQ0000000000000000",
      "object": "consent",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "purpose": "string",
      "channel": "string",
      "lawful_basis": "string",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "revoked_via": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/contacts/{id}

Update a contact

Tact-Account optionalcontacts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • external_ref

    string

  • display_name

    string

  • kind

    "person" | "organization" | "agent"

  • locale

    string

  • timezone

    string

  • country

    string

  • is_minor

    boolean

  • guardian_contact_id

    string

  • channels

    object[]

  • consents

    object[]

Request example
{
  "external_ref": "cust_4821",
  "display_name": "Niamh Byrne",
  "kind": "person",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "con_01JB6ZK8TQ0000000000000000",
  "channels": [
    {
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true
    }
  ],
  "consents": [
    {
      "purpose": "reminder",
      "channel": "whatsapp",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "lawful_basis": "string"
    }
  ]
}
Response example · 200
{
  "id": "con_01JB6ZK8TQ0000000000000000",
  "object": "contact",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "external_ref": "cust_4821",
  "kind": "string",
  "display_name": "Niamh Byrne",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "string",
  "identity_level": "string",
  "do_not_contact": true,
  "channels": [
    {
      "id": "cch_01JB6ZK8TQ0000000000000000",
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "consents": [
    {
      "id": "cst_01JB6ZK8TQ0000000000000000",
      "object": "consent",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "purpose": "string",
      "channel": "string",
      "lawful_basis": "string",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "revoked_via": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/contacts/{id}/do_not_contact

Block proactive contact (survives contact erasure)

Tact-Account optionalcontacts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • channel

    "whatsapp" | "sms" | "email" | "voice" | "whatsapp_call" | "imessage" | "any"

  • reason

    "opt_out" | "complaint" | "legal"

Request example
{
  "channel": "whatsapp",
  "reason": "opt_out"
}
Response example · 200
{
  "id": "con_01JB6ZK8TQ0000000000000000",
  "object": "contact",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "external_ref": "cust_4821",
  "kind": "string",
  "display_name": "Niamh Byrne",
  "locale": "en-IE",
  "timezone": "Europe/Dublin",
  "country": "IE",
  "is_minor": true,
  "guardian_contact_id": "string",
  "identity_level": "string",
  "do_not_contact": true,
  "channels": [
    {
      "id": "cch_01JB6ZK8TQ0000000000000000",
      "channel": "whatsapp",
      "address": "+353871234567",
      "is_preferred": true,
      "verified_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "consents": [
    {
      "id": "cst_01JB6ZK8TQ0000000000000000",
      "object": "consent",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "purpose": "string",
      "channel": "string",
      "lawful_basis": "string",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "revoked_via": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/contacts/{id}/consents

List consents

Tact-Account optionalcontacts:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "cst_01JB6ZK8TQ0000000000000000",
      "object": "consent",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "purpose": "string",
      "channel": "string",
      "lawful_basis": "string",
      "granted_at": "2026-11-02T09:30:00+00:00",
      "source": "string",
      "evidence": {},
      "revoked_at": "2026-11-02T09:30:00+00:00",
      "revoked_via": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/contacts/{id}/consents

Record a consent

Tact-Account optionalcontacts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • purposerequired

    "reminder" | "recall" | "followup" | "marketing" | "recording" | "automated_call"

  • channelrequired

    "whatsapp" | "sms" | "email" | "voice" | "whatsapp_call" | "any"

  • granted_atrequired

    string (date-time)

  • source

    string

  • evidence

    object

  • lawful_basis

    string

    Defaults to the account lawful basis for the purpose

Request example
{
  "purpose": "reminder",
  "channel": "whatsapp",
  "granted_at": "2026-11-02T09:30:00+00:00",
  "source": "string",
  "evidence": {},
  "lawful_basis": "string"
}
Response example · 201
{
  "id": "cst_01JB6ZK8TQ0000000000000000",
  "object": "consent",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "purpose": "string",
  "channel": "string",
  "lawful_basis": "string",
  "granted_at": "2026-11-02T09:30:00+00:00",
  "source": "string",
  "evidence": {},
  "revoked_at": "2026-11-02T09:30:00+00:00",
  "revoked_via": "string",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/consents/{id}/revoke

Revoke a consent

Tact-Account optionalcontacts:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • via

    string

Request example
{
  "via": "string"
}
Response example · 200
{
  "id": "cst_01JB6ZK8TQ0000000000000000",
  "object": "consent",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "purpose": "string",
  "channel": "string",
  "lawful_basis": "string",
  "granted_at": "2026-11-02T09:30:00+00:00",
  "source": "string",
  "evidence": {},
  "revoked_at": "2026-11-02T09:30:00+00:00",
  "revoked_via": "string",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Privacy4 routes

GET/v1/contacts/{id}/export

Export everything held about a contact

Tact-Account optionalprivacy:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "object": "contact_export",
  "generated_at": "2026-11-02T09:30:00+00:00",
  "contact": {
    "id": "con_01JB6ZK8TQ0000000000000000",
    "object": "contact",
    "account_id": "acc_01JB6ZK8TQ0000000000000000",
    "external_ref": "cust_4821",
    "kind": "string",
    "display_name": "Niamh Byrne",
    "locale": "en-IE",
    "timezone": "Europe/Dublin",
    "country": "IE",
    "is_minor": true,
    "guardian_contact_id": "string",
    "identity_level": "string",
    "do_not_contact": true,
    "channels": [
      {
        "id": "cch_01JB6ZK8TQ0000000000000000",
        "channel": "whatsapp",
        "address": "+353871234567",
        "is_preferred": true,
        "verified_at": "2026-11-02T09:30:00+00:00"
      }
    ],
    "consents": [
      {
        "id": "cst_01JB6ZK8TQ0000000000000000",
        "object": "consent",
        "contact_id": "con_01JB6ZK8TQ0000000000000000",
        "purpose": "string",
        "channel": "string",
        "lawful_basis": "string",
        "granted_at": "2026-11-02T09:30:00+00:00",
        "source": "string",
        "evidence": {},
        "revoked_at": "2026-11-02T09:30:00+00:00",
        "revoked_via": "string",
        "created_at": "2026-11-02T09:30:00+00:00"
      }
    ],
    "created_at": "2026-11-02T09:30:00+00:00"
  },
  "threads": [
    {
      "id": "thr_01JB6ZK8TQ0000000000000000",
      "object": "thread",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "mode": "assistant",
      "status": "open",
      "channels": [
        "whatsapp"
      ],
      "window_open_until": "2026-11-02T09:30:00+00:00",
      "disclosed_at": "2026-11-02T09:30:00+00:00",
      "last_inbound_at": "2026-11-02T09:30:00+00:00",
      "last_outbound_at": "2026-11-02T09:30:00+00:00",
      "last_message_at": "2026-11-02T09:30:00+00:00",
      "open_goals": [
        {
          "id": "gol_01JB6ZK8TQ0000000000000000",
          "kind": "string",
          "status": "string"
        }
      ],
      "contact": {},
      "agent": {},
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "messages": [
    {
      "id": "msg_01JB6ZK8TQ0000000000000000",
      "object": "message",
      "thread_id": "thr_01JB6ZK8TQ0000000000000000",
      "direction": "in",
      "author": "string",
      "channel": "whatsapp",
      "kind": "string",
      "text": "Can I move Thursday to Friday?",
      "provider_message_id": "string",
      "proactive": true,
      "generated_by_ai": true,
      "delivery_status": "string",
      "run_id": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "messages_truncated": true,
  "memories": [
    {
      "id": "mem_01JB6ZK8TQ0000000000000000",
      "object": "memory",
      "subject": {
        "type": "contact",
        "id": "msg_9001"
      },
      "kind": "string",
      "content": "string",
      "origin": "string",
      "trust": "low",
      "confidence": 1.5,
      "sensitivity": "string",
      "valid_from": "2026-11-02T09:30:00+00:00",
      "valid_until": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "result": "string"
    }
  ],
  "actions": [
    {
      "id": "act_01JB6ZK8TQ0000000000000000",
      "object": "action",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "run_id": "string",
      "thread_id": "string",
      "action_type": "string",
      "tool": "string",
      "action_class": "string",
      "risk": "string",
      "status": "string",
      "policy_decision": "allow",
      "guardian_verdict": "string",
      "approval_id": "string",
      "target_contact_id": "string",
      "args_sha256": "string",
      "generated_by_ai": true,
      "result_summary": {},
      "cost_micros": 1,
      "seq": 1,
      "row_hash": "string",
      "created_at": "2026-11-02T09:30:00+00:00",
      "executed_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
DELETE/v1/contacts/{id}/data

Request the cascade erasure of a contact

Tact-Account optionalprivacy:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • reason

    string

  • requested_at

    string (date-time)

  • keep_legal_hold

    boolean

Request example
{
  "reason": "requested by the account",
  "requested_at": "2026-11-02T09:30:00+00:00",
  "keep_legal_hold": true
}
Response example · 202
{
  "id": "era_01JB6ZK8TQ0000000000000000",
  "object": "erasure_request",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "scope": "contact",
  "contact_id": "string",
  "status": "queued",
  "requested_via": "string",
  "receipt_sha256": "string",
  "items": [
    null
  ],
  "requested_at": "2026-11-02T09:30:00+00:00",
  "due_by": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00",
  "erasure_request_id": "era_01JB6ZK8TQ0000000000000000"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/accounts/{id}/erase

Request the cascade erasure of an account

privacy:write

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Request body

  • reason

    string

  • requested_at

    string (date-time)

  • keep_legal_hold

    boolean

Request example
{
  "reason": "requested by the account",
  "requested_at": "2026-11-02T09:30:00+00:00",
  "keep_legal_hold": true
}
Response example · 202
{
  "id": "era_01JB6ZK8TQ0000000000000000",
  "object": "erasure_request",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "scope": "contact",
  "contact_id": "string",
  "status": "queued",
  "requested_via": "string",
  "receipt_sha256": "string",
  "items": [
    null
  ],
  "requested_at": "2026-11-02T09:30:00+00:00",
  "due_by": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00",
  "erasure_request_id": "era_01JB6ZK8TQ0000000000000000"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/erasure_requests/{id}

Retrieve an erasure request and its receipt

Tact-Account optionalprivacy:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "era_01JB6ZK8TQ0000000000000000",
  "object": "erasure_request",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "scope": "contact",
  "contact_id": "string",
  "status": "queued",
  "requested_via": "string",
  "receipt_sha256": "string",
  "items": [
    null
  ],
  "requested_at": "2026-11-02T09:30:00+00:00",
  "due_by": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Threads8 routes

GET/v1/threads

List threads

Tact-Account requiredthreads:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

  • mode

    query · "assistant" | "representative"

  • contact_id

    query · string

  • expand[]

    query · "contact" | "agent"

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "thr_01JB6ZK8TQ0000000000000000",
      "object": "thread",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "contact_id": "con_01JB6ZK8TQ0000000000000000",
      "mode": "assistant",
      "status": "open",
      "channels": [
        "whatsapp"
      ],
      "window_open_until": "2026-11-02T09:30:00+00:00",
      "disclosed_at": "2026-11-02T09:30:00+00:00",
      "last_inbound_at": "2026-11-02T09:30:00+00:00",
      "last_outbound_at": "2026-11-02T09:30:00+00:00",
      "last_message_at": "2026-11-02T09:30:00+00:00",
      "open_goals": [
        {
          "id": "gol_01JB6ZK8TQ0000000000000000",
          "kind": "string",
          "status": "string"
        }
      ],
      "contact": {},
      "agent": {},
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/threads/{id}

Retrieve a thread

Tact-Account optionalthreads:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • expand[]

    query · "contact" | "agent"

Response example · 200
{
  "id": "thr_01JB6ZK8TQ0000000000000000",
  "object": "thread",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "mode": "assistant",
  "status": "open",
  "channels": [
    "whatsapp"
  ],
  "window_open_until": "2026-11-02T09:30:00+00:00",
  "disclosed_at": "2026-11-02T09:30:00+00:00",
  "last_inbound_at": "2026-11-02T09:30:00+00:00",
  "last_outbound_at": "2026-11-02T09:30:00+00:00",
  "last_message_at": "2026-11-02T09:30:00+00:00",
  "open_goals": [
    {
      "id": "gol_01JB6ZK8TQ0000000000000000",
      "kind": "string",
      "status": "string"
    }
  ],
  "contact": {},
  "agent": {},
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/threads/{id}/handoff

Hand the thread to the team

Tact-Account optionalthreads:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • reason

    string

  • note

    string

  • notify_contact

    boolean

Request example
{
  "reason": "requested by the account",
  "note": "string",
  "notify_contact": true
}
Response example · 200
{
  "id": "thr_01JB6ZK8TQ0000000000000000",
  "object": "thread",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "mode": "assistant",
  "status": "open",
  "channels": [
    "whatsapp"
  ],
  "window_open_until": "2026-11-02T09:30:00+00:00",
  "disclosed_at": "2026-11-02T09:30:00+00:00",
  "last_inbound_at": "2026-11-02T09:30:00+00:00",
  "last_outbound_at": "2026-11-02T09:30:00+00:00",
  "last_message_at": "2026-11-02T09:30:00+00:00",
  "open_goals": [
    {
      "id": "gol_01JB6ZK8TQ0000000000000000",
      "kind": "string",
      "status": "string"
    }
  ],
  "contact": {},
  "agent": {},
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/threads/{id}/release

Give the thread back to the agent

Tact-Account optionalthreads:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "thr_01JB6ZK8TQ0000000000000000",
  "object": "thread",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "mode": "assistant",
  "status": "open",
  "channels": [
    "whatsapp"
  ],
  "window_open_until": "2026-11-02T09:30:00+00:00",
  "disclosed_at": "2026-11-02T09:30:00+00:00",
  "last_inbound_at": "2026-11-02T09:30:00+00:00",
  "last_outbound_at": "2026-11-02T09:30:00+00:00",
  "last_message_at": "2026-11-02T09:30:00+00:00",
  "open_goals": [
    {
      "id": "gol_01JB6ZK8TQ0000000000000000",
      "kind": "string",
      "status": "string"
    }
  ],
  "contact": {},
  "agent": {},
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/threads/import

Import message history (legacy_import)

Tact-Account requiredthreads:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • contact_id

    string

  • contact_external_ref

    string

  • from

    string

    Channel address when the contact is new

  • channelrequired

    "whatsapp" | "sms" | "email" | "voice" | "telegram" | "in_app" | "imessage"

  • origin

    "legacy_import"

  • messagesrequired

    object[]

Request example
{
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "contact_external_ref": "string",
  "from": "string",
  "channel": "whatsapp",
  "origin": "legacy_import",
  "messages": [
    {
      "direction": "in",
      "author": "string",
      "text": "Can I move Thursday to Friday?",
      "sent_at": "2026-11-02T09:30:00+00:00",
      "provider_message_id": "string",
      "generated_by_ai": true
    }
  ]
}
Response example · 201
{
  "object": "thread_import",
  "origin": "string",
  "thread_id": "thr_01JB6ZK8TQ0000000000000000",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "imported": 1,
  "skipped": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/threads/{id}/messages

List messages, newest first

Tact-Account optionalthreads:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "msg_01JB6ZK8TQ0000000000000000",
      "object": "message",
      "thread_id": "thr_01JB6ZK8TQ0000000000000000",
      "direction": "in",
      "author": "string",
      "channel": "whatsapp",
      "kind": "string",
      "text": "Can I move Thursday to Friday?",
      "provider_message_id": "string",
      "proactive": true,
      "generated_by_ai": true,
      "delivery_status": "string",
      "run_id": "string",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/threads/{id}/messages

Send a human message from the team through the thread

The thread moves to handoff, so the agent stops answering until release.

Tact-Account optionalthreads:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • author

    "staff" | "principal"

  • textrequired

    string

  • channel

    "whatsapp" | "sms" | "email" | "voice" | "telegram" | "in_app" | "imessage"

Request example
{
  "author": "staff",
  "text": "Can I move Thursday to Friday?",
  "channel": "whatsapp"
}
Response example · 202
{
  "id": "msg_01JB6ZK8TQ0000000000000000",
  "object": "message",
  "thread_id": "thr_01JB6ZK8TQ0000000000000000",
  "direction": "in",
  "author": "string",
  "channel": "whatsapp",
  "kind": "string",
  "text": "Can I move Thursday to Friday?",
  "provider_message_id": "string",
  "proactive": true,
  "generated_by_ai": true,
  "delivery_status": "string",
  "run_id": "string",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/inbound

Deliver a message from the tenant's own channel; shadow mode drafts without sending

Tact-Account requiredthreads:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • idrequired

    string

    Tenant message id, used for deduplication

  • channel

    "whatsapp" | "sms" | "email" | "voice" | "telegram" | "in_app" | "imessage"

  • contact_id

    string

  • contact_external_ref

    string

  • from

    string

  • textrequired

    string

  • sent_at

    string (date-time)

  • shadow

    boolean

    Draft without sending (shadow mode)

Request example
{
  "id": "msg_9001",
  "channel": "whatsapp",
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "contact_external_ref": "string",
  "from": "string",
  "text": "Can I move Thursday to Friday?",
  "sent_at": "2026-11-02T09:30:00+00:00",
  "shadow": false
}
Response example · 202
{
  "object": "inbound",
  "inbound_event_id": 1,
  "contact_id": "con_01JB6ZK8TQ0000000000000000",
  "deduplicated": true,
  "shadow": false
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Goals5 routes

GET/v1/goals

List goals

Tact-Account requiredgoals:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "gol_01JB6ZK8TQ0000000000000000",
      "object": "goal",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "title": "string",
      "kind": "string",
      "params": {},
      "status": "active",
      "created_by": "string",
      "deadline": "2026-11-02T09:30:00+00:00",
      "thread_id": "string",
      "root_task_id": "tsk_01JB6ZK8TQ0000000000000000",
      "created_at": "2026-11-02T09:30:00+00:00",
      "completed_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/goals

Create a durable goal

Tact-Account requiredgoals:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • agent_id

    string

  • kindrequired

    string

  • title

    string

  • params

    object

  • deadline

    string (date-time)

  • created_by

    "principal" | "tenant_api"

  • requested_by_principal_id

    string

  • thread_id

    string

Request example
{
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "kind": "string",
  "title": "string",
  "params": {},
  "deadline": "2026-11-02T09:30:00+00:00",
  "created_by": "principal",
  "requested_by_principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "thread_id": "thr_01JB6ZK8TQ0000000000000000"
}
Response example · 201
{
  "id": "gol_01JB6ZK8TQ0000000000000000",
  "object": "goal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "title": "string",
  "kind": "string",
  "params": {},
  "status": "active",
  "created_by": "string",
  "deadline": "2026-11-02T09:30:00+00:00",
  "thread_id": "string",
  "root_task_id": "tsk_01JB6ZK8TQ0000000000000000",
  "created_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/goals/{id}

Retrieve a goal

Tact-Account optionalgoals:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "gol_01JB6ZK8TQ0000000000000000",
  "object": "goal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "title": "string",
  "kind": "string",
  "params": {},
  "status": "active",
  "created_by": "string",
  "deadline": "2026-11-02T09:30:00+00:00",
  "thread_id": "string",
  "root_task_id": "tsk_01JB6ZK8TQ0000000000000000",
  "created_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/goals/{id}/cancel

Cancel a goal and its open tasks

Tact-Account optionalgoals:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "gol_01JB6ZK8TQ0000000000000000",
  "object": "goal",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "title": "string",
  "kind": "string",
  "params": {},
  "status": "active",
  "created_by": "string",
  "deadline": "2026-11-02T09:30:00+00:00",
  "thread_id": "string",
  "root_task_id": "tsk_01JB6ZK8TQ0000000000000000",
  "created_at": "2026-11-02T09:30:00+00:00",
  "completed_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/goals/{id}/tasks

List the tasks of a goal

Tact-Account optionalgoals:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "tsk_01JB6ZK8TQ0000000000000000",
      "object": "task",
      "goal_id": "string",
      "thread_id": "string",
      "kind": "string",
      "state": "open",
      "wake_at": "2026-11-02T09:30:00+00:00",
      "deadline_at": "2026-11-02T09:30:00+00:00",
      "attempts": 1,
      "created_at": "2026-11-02T09:30:00+00:00",
      "updated_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Memory4 routes

GET/v1/memories

List memories

Tact-Account requiredmemory:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • kind

    query · string

  • subject_type

    query · "contact" | "principal" | "account" | "agent"

  • subject_id

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "mem_01JB6ZK8TQ0000000000000000",
      "object": "memory",
      "subject": {
        "type": "contact",
        "id": "msg_9001"
      },
      "kind": "string",
      "content": "string",
      "origin": "string",
      "trust": "low",
      "confidence": 1.5,
      "sensitivity": "string",
      "valid_from": "2026-11-02T09:30:00+00:00",
      "valid_until": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "result": "string"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/memories

Write a memory with its origin

Tact-Account requiredmemory:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • subjectrequired

    object

  • kindrequired

    "preference" | "fact" | "commitment" | "instruction" | "knowledge"

  • contentrequired

    string

  • origin

    "contact" | "principal" | "staff" | "tenant"

    What a contact says never becomes an instruction

  • confidence

    number

  • sensitivity

    "none" | "personal" | "health"

  • source_ref

    string

  • valid_until

    string (date-time)

Request example
{
  "subject": {
    "type": "contact",
    "id": "msg_9001"
  },
  "kind": "preference",
  "content": "string",
  "origin": "contact",
  "confidence": 1.5,
  "sensitivity": "none",
  "source_ref": "msg_01JB6ZK8TQ0000000000000000",
  "valid_until": "2026-11-02T09:30:00+00:00"
}
Response example · 201
{
  "id": "mem_01JB6ZK8TQ0000000000000000",
  "object": "memory",
  "subject": {
    "type": "contact",
    "id": "msg_9001"
  },
  "kind": "string",
  "content": "string",
  "origin": "string",
  "trust": "low",
  "confidence": 1.5,
  "sensitivity": "string",
  "valid_from": "2026-11-02T09:30:00+00:00",
  "valid_until": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "result": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
DELETE/v1/memories/{id}

Forget one memory

Tact-Account optionalmemory:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "msg_9001",
  "object": "string",
  "deleted": true
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/memories/forget

Forget what matches a query about a subject

Tact-Account requiredmemory:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • subjectrequired

    object

  • query

    string

  • requested_by

    "contact" | "principal" | "staff" | "tenant"

Request example
{
  "subject": {
    "type": "contact",
    "id": "msg_9001"
  },
  "query": "string",
  "requested_by": "contact"
}
Response example · 200
{
  "object": "forget_result",
  "requested_by": "string",
  "forgotten": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Policy6 routes

GET/v1/policy_rules

List policy rules (tenant level, plus account and agent with Tact-Account)

Tact-Account optionalpolicies:read

Parameters

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

  • level

    query · "pack" | "tenant" | "account" | "agent" | "grant"

  • action_type

    query · string

  • include_expired

    query · boolean

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "pol_01JB6ZK8TQ0000000000000000",
      "object": "policy_rule",
      "level": "pack",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "action_type": "string",
      "decision": "allow",
      "otherwise": "ask",
      "min_effect": "string",
      "max_effect": "string",
      "locked": true,
      "conditions": [
        {
          "fact": "appointment.hours_until_start",
          "op": "eq",
          "value": null
        }
      ],
      "approver_role": "string",
      "source": "string",
      "explanation": null,
      "nl_text": "string",
      "priority": 1,
      "valid_from": "2026-11-02T09:30:00+00:00",
      "valid_until": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/policy_rules

Create a policy rule within the engine floor

Tact-Account optionalpolicies:write

Parameters

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • levelrequired

    "tenant" | "account" | "agent"

  • agent_id

    string

  • action_typerequired

    string

    Action type of the engine taxonomy (data.read, message.reply, schedule.cancel ...) or a pack tool name

  • decisionrequired

    "allow" | "ask" | "block"

  • conditions

    object[]

    Only for allow; when a condition fails the decision is ask

  • otherwise

    "ask"

  • locked

    boolean

    Lower levels cannot be more permissive

  • priority

    integer

  • valid_until

    string (date-time)

  • explanation

    object

    Text per locale shown to the principal

  • approver_role

    string

Request example
{
  "level": "tenant",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "action_type": "string",
  "decision": "allow",
  "conditions": [
    {
      "fact": "appointment.hours_until_start",
      "op": "eq",
      "value": null
    }
  ],
  "otherwise": "ask",
  "locked": true,
  "priority": 1,
  "valid_until": "2026-11-02T09:30:00+00:00",
  "explanation": {},
  "approver_role": "string"
}
Response example · 201
{
  "id": "pol_01JB6ZK8TQ0000000000000000",
  "object": "policy_rule",
  "level": "pack",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "action_type": "string",
  "decision": "allow",
  "otherwise": "ask",
  "min_effect": "string",
  "max_effect": "string",
  "locked": true,
  "conditions": [
    {
      "fact": "appointment.hours_until_start",
      "op": "eq",
      "value": null
    }
  ],
  "approver_role": "string",
  "source": "string",
  "explanation": null,
  "nl_text": "string",
  "priority": 1,
  "valid_from": "2026-11-02T09:30:00+00:00",
  "valid_until": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/policy_rules/{id}

Update a policy rule

Tact-Account optionalpolicies:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • decision

    "allow" | "ask" | "block"

  • conditions

    object[]

  • locked

    boolean

  • priority

    integer

  • valid_until

    string (date-time)

  • explanation

    object

Request example
{
  "decision": "allow",
  "conditions": [
    {
      "fact": "appointment.hours_until_start",
      "op": "eq",
      "value": null
    }
  ],
  "locked": true,
  "priority": 1,
  "valid_until": "2026-11-02T09:30:00+00:00",
  "explanation": {}
}
Response example · 200
{
  "id": "pol_01JB6ZK8TQ0000000000000000",
  "object": "policy_rule",
  "level": "pack",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "action_type": "string",
  "decision": "allow",
  "otherwise": "ask",
  "min_effect": "string",
  "max_effect": "string",
  "locked": true,
  "conditions": [
    {
      "fact": "appointment.hours_until_start",
      "op": "eq",
      "value": null
    }
  ],
  "approver_role": "string",
  "source": "string",
  "explanation": null,
  "nl_text": "string",
  "priority": 1,
  "valid_from": "2026-11-02T09:30:00+00:00",
  "valid_until": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
DELETE/v1/policy_rules/{id}

Expire a policy rule (history is kept)

Tact-Account optionalpolicies:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "pol_01JB6ZK8TQ0000000000000000",
  "object": "policy_rule",
  "level": "pack",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "action_type": "string",
  "decision": "allow",
  "otherwise": "ask",
  "min_effect": "string",
  "max_effect": "string",
  "locked": true,
  "conditions": [
    {
      "fact": "appointment.hours_until_start",
      "op": "eq",
      "value": null
    }
  ],
  "approver_role": "string",
  "source": "string",
  "explanation": null,
  "nl_text": "string",
  "priority": 1,
  "valid_from": "2026-11-02T09:30:00+00:00",
  "valid_until": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/policies/effective

Effective decision per action type

Tact-Account requiredpolicies:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • face

    query · "assistant" | "representative"

Response example · 200
{
  "object": "effective_policy",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "face": "string",
  "data": [
    {
      "action_type": "string",
      "action_class": "string",
      "decision": "allow",
      "otherwise": "allow",
      "binding": "string",
      "conditions": [
        {
          "fact": "appointment.hours_until_start",
          "op": "eq",
          "value": null
        }
      ],
      "rule_ids": [
        "string"
      ],
      "source": "floor"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/policies/simulate

Simulate a decision with given facts

Tact-Account requiredpolicies:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • agent_id

    string

  • action_typerequired

    string

    Action type of the engine taxonomy (data.read, message.reply, schedule.cancel ...) or a pack tool name

  • facts

    object

    Fact name to value

  • face

    "assistant" | "representative"

Request example
{
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "action_type": "string",
  "facts": {},
  "face": "assistant"
}
Response example · 200
{
  "object": "policy_simulation",
  "action_type": "string",
  "face": "string",
  "decision": "allow",
  "binding": "string",
  "reason": "requested by the account",
  "matched_rules": [
    {
      "id": "pol_01JB6ZK8TQ0000000000000000",
      "level": "string",
      "decision": "allow"
    }
  ],
  "conditions_failed": [
    "string"
  ],
  "trace": [
    {}
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Approvals3 routes

GET/v1/approvals

List approvals

Tact-Account requiredapprovals:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "apr_01JB6ZK8TQ0000000000000000",
      "object": "approval",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "status": "pending",
      "action": {
        "id": "act_01JB6ZK8TQ0000000000000000",
        "action_type": "string",
        "tool": "string"
      },
      "action_class": "string",
      "risk": "low",
      "binding": "loose_tap",
      "summary": {},
      "summary_hash": "string",
      "args": {},
      "requested_from": [
        "prn_01JB6ZK8TQ0000000000000000"
      ],
      "approver_role": "string",
      "channel": "string",
      "requested_at": "2026-11-02T09:30:00+00:00",
      "expires_at": "2026-11-02T09:30:00+00:00",
      "reminders_sent": 1,
      "decided_at": "2026-11-02T09:30:00+00:00",
      "decided_by": "string",
      "decided_via": "string",
      "rule_proposal": {}
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/approvals/{id}

Retrieve an approval

Tact-Account optionalapprovals:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "apr_01JB6ZK8TQ0000000000000000",
  "object": "approval",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "status": "pending",
  "action": {
    "id": "act_01JB6ZK8TQ0000000000000000",
    "action_type": "string",
    "tool": "string"
  },
  "action_class": "string",
  "risk": "low",
  "binding": "loose_tap",
  "summary": {},
  "summary_hash": "string",
  "args": {},
  "requested_from": [
    "prn_01JB6ZK8TQ0000000000000000"
  ],
  "approver_role": "string",
  "channel": "string",
  "requested_at": "2026-11-02T09:30:00+00:00",
  "expires_at": "2026-11-02T09:30:00+00:00",
  "reminders_sent": 1,
  "decided_at": "2026-11-02T09:30:00+00:00",
  "decided_by": "string",
  "decided_via": "string",
  "rule_proposal": {}
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/approvals/{id}/decide

Approve or reject on behalf of a principal

Approving requires summary_hash from GET /v1/approvals/{id} (400 parameter_missing without it), so the principal approves exactly the summary that was shown. Critical approvals (security or destructive) are decided only in the console with step-up.

Tact-Account optionalapprovals:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Request body

  • decisionrequired

    "approve" | "reject"

  • principal_idrequired

    string

  • note

    string

  • apply_as_rule

    boolean

    Proposes an account rule for the same case; the principal confirms it

  • summary_hash

    string

    summary_hash read from GET /v1/approvals/{id}. Required to approve: the decision binds to that exact summary and fails if it changed after the read. Optional to reject (without it the current summary applies)

Request example
{
  "decision": "approve",
  "principal_id": "prn_01JB6ZK8TQ0000000000000000",
  "note": "string",
  "apply_as_rule": true,
  "summary_hash": "string"
}
Response example · 200
{
  "id": "apr_01JB6ZK8TQ0000000000000000",
  "object": "approval",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "status": "pending",
  "action": {
    "id": "act_01JB6ZK8TQ0000000000000000",
    "action_type": "string",
    "tool": "string"
  },
  "action_class": "string",
  "risk": "low",
  "binding": "loose_tap",
  "summary": {},
  "summary_hash": "string",
  "args": {},
  "requested_from": [
    "prn_01JB6ZK8TQ0000000000000000"
  ],
  "approver_role": "string",
  "channel": "string",
  "requested_at": "2026-11-02T09:30:00+00:00",
  "expires_at": "2026-11-02T09:30:00+00:00",
  "reminders_sent": 1,
  "decided_at": "2026-11-02T09:30:00+00:00",
  "decided_by": "string",
  "decided_via": "string",
  "rule_proposal": {}
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Packs9 routes

GET/v1/packs

List packs visible to the tenant

packs:read

Parameters

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "pck_01JB6ZK8TQ0000000000000000",
      "object": "pack",
      "key": "principal_verified",
      "name": "Harbour Physio",
      "owner": "amplitude",
      "versions": [
        {
          "id": "pkv_01JB6ZK8TQ0000000000000000",
          "object": "pack_version",
          "pack_id": "pck_01JB6ZK8TQ0000000000000000",
          "pack_key": "string",
          "version": "string",
          "status": "draft",
          "manifest_sha256": "string",
          "eval_run_id": "string",
          "activated_at": "2026-11-02T09:30:00+00:00",
          "created_at": "2026-11-02T09:30:00+00:00",
          "tools": [
            "string"
          ],
          "playbooks": [
            "string"
          ]
        }
      ],
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/packs

Create a tenant pack

packs:write

Parameters

  • Idempotency-Key

    header · string

Request body

  • keyrequired

    string

  • namerequired

    string

Request example
{
  "key": "principal_verified",
  "name": "Harbour Physio"
}
Response example · 201
{
  "id": "pck_01JB6ZK8TQ0000000000000000",
  "object": "pack",
  "key": "principal_verified",
  "name": "Harbour Physio",
  "owner": "amplitude",
  "versions": [
    {
      "id": "pkv_01JB6ZK8TQ0000000000000000",
      "object": "pack_version",
      "pack_id": "pck_01JB6ZK8TQ0000000000000000",
      "pack_key": "string",
      "version": "string",
      "status": "draft",
      "manifest_sha256": "string",
      "eval_run_id": "string",
      "activated_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00",
      "tools": [
        "string"
      ],
      "playbooks": [
        "string"
      ]
    }
  ],
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/packs/{id}/versions

Create or replace a draft version with its manifest

packs:write

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Request body

  • versionrequired

    string

    SemVer

  • manifestrequired

    object

    Pack manifest: tools (JSON Schema 2020-12, strict), playbooks, prerequisites, knowledge_schemas, locales

Request example
{
  "version": "string",
  "manifest": {}
}
Response example · 201
{
  "id": "pkv_01JB6ZK8TQ0000000000000000",
  "object": "pack_version",
  "pack_id": "pck_01JB6ZK8TQ0000000000000000",
  "pack_key": "string",
  "version": "string",
  "status": "draft",
  "manifest_sha256": "string",
  "eval_run_id": "string",
  "activated_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "tools": [
    "string"
  ],
  "playbooks": [
    "string"
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/packs/{id}/versions/{v}/evaluate

Run the eval suites of a draft version

packs:write

Parameters

  • idrequired

    path · string

  • vrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 202
{
  "object": "eval_run",
  "id": "evr_01JB6ZK8TQ0000000000000000",
  "pack_version_id": "pkv_01JB6ZK8TQ0000000000000000",
  "status": "queued",
  "passed": true
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/packs/{id}/versions/{v}/activate

Activate a version whose evals passed

packs:write

Parameters

  • idrequired

    path · string

  • vrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "pkv_01JB6ZK8TQ0000000000000000",
  "object": "pack_version",
  "pack_id": "pck_01JB6ZK8TQ0000000000000000",
  "pack_key": "string",
  "version": "string",
  "status": "draft",
  "manifest_sha256": "string",
  "eval_run_id": "string",
  "activated_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "tools": [
    "string"
  ],
  "playbooks": [
    "string"
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/pack_installs

Install an active pack version on the account

Tact-Account requiredpacks:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • packrequired

    object

  • playbooks

    object

Request example
{
  "pack": {
    "id": "msg_9001",
    "key": "principal_verified",
    "version": "string"
  },
  "playbooks": {}
}
Response example · 200
{
  "id": "pin_01JB6ZK8TQ0000000000000000",
  "object": "pack_install",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string",
    "version_id": "pkv_01JB6ZK8TQ0000000000000000"
  },
  "playbooks": {}
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/pack_installs/{id}

Turn playbooks on or off

Tact-Account optionalpacks:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Request body

  • playbooks

    object

Request example
{
  "playbooks": {
    "key": "on"
  }
}
Response example · 200
{
  "id": "pin_01JB6ZK8TQ0000000000000000",
  "object": "pack_install",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "pack": {
    "id": "pck_01JB6ZK8TQ0000000000000000",
    "key": "principal_verified",
    "version": "string",
    "version_id": "pkv_01JB6ZK8TQ0000000000000000"
  },
  "playbooks": {}
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/tools

Effective tool catalog of the account

Tact-Account requiredpacks:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "object": "tool",
      "name": "Harbour Physio",
      "description": "string",
      "action_type": "string",
      "action_class": "string",
      "risk": "string",
      "modes": [
        "string"
      ],
      "input_schema": {},
      "output_schema": {},
      "facts": [
        "string"
      ],
      "timeout_ms": 1,
      "idempotent": true
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/tools/{name}/dry_run

Validate arguments against a tool schema without calling the tenant

Tact-Account requiredpacks:read

Parameters

  • namerequired

    path · string

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • args

    object

  • mode

    "assistant" | "representative"

Request example
{
  "args": {},
  "mode": "assistant"
}
Response example · 200
{
  "object": "tool_dry_run",
  "tool": "string",
  "action_type": "string",
  "mode": "string",
  "available_in_mode": true,
  "valid": true,
  "issues": [
    {
      "path": "string",
      "keyword": "string",
      "message": "Contact has no active consent for purpose 'recall' on channel 'whatsapp'."
    }
  ],
  "args_sha256": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Triggers5 routes

POST/v1/events

Send a business event (deduplicated by event id for 7 days)

knowledge.upsert and knowledge.delete events update the account knowledge right away.

Tact-Account requiredevents:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • idrequired

    string

    Tenant event id; deduplicated for 7 days

  • typerequired

    string

  • occurred_atrequired

    string (date-time)

  • data

    object

    knowledge.upsert: {kind, external_ref, source_updated_at, data}; knowledge.delete: {kind, external_ref}

Request example
{
  "id": "msg_9001",
  "type": "appointment.cancelled",
  "occurred_at": "2026-11-02T09:30:00+00:00",
  "data": {}
}
Response example · 202
{
  "object": "event_receipt",
  "trigger_id": "trg_01JB6ZK8TQ0000000000000000",
  "deduplicated": true,
  "applied": {}
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/schedules

List schedules

Tact-Account requiredevents:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "trg_01JB6ZK8TQ0000000000000000",
      "object": "schedule",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "kind": "string",
      "playbook_key": "string",
      "spec": {},
      "next_fire_at": "2026-11-02T09:30:00+00:00",
      "enabled": true,
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/schedules

Schedule a playbook (RRULE in the account time zone, or a single instant)

Tact-Account requiredevents:write

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • Idempotency-Key

    header · string

Request body

  • playbook_keyrequired

    string

  • rrule

    string

    RRULE:... in the time zone

  • at

    string (date-time)

  • timezone

    string

    Defaults to the account time zone

  • payload

    object

Request example
{
  "playbook_key": "string",
  "rrule": "string",
  "at": "2026-11-02T09:30:00+00:00",
  "timezone": "Europe/Dublin",
  "payload": {}
}
Response example · 201
{
  "id": "trg_01JB6ZK8TQ0000000000000000",
  "object": "schedule",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "kind": "string",
  "playbook_key": "string",
  "spec": {},
  "next_fire_at": "2026-11-02T09:30:00+00:00",
  "enabled": true,
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
DELETE/v1/schedules/{id}

Disable a schedule

Tact-Account optionalevents:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "trg_01JB6ZK8TQ0000000000000000",
  "object": "schedule",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "kind": "string",
  "playbook_key": "string",
  "spec": {},
  "next_fire_at": "2026-11-02T09:30:00+00:00",
  "enabled": true,
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/functions/v1/ingress-tenant/{tenant}

Push business events from the tenant outbox (signed)

Sign the raw body with the secret from POST /v1/tenant/outbox_secret: Tact-Signature: t=<unix>,v1=hex(hmac_sha256(secret, t + "." + body)). Tolerance 5 minutes. Body: {account, events: [...]} with up to 100 events; each event may carry its own account (acc_... or ext:<external_ref>).

No authentication

Parameters

  • tenantrequired

    path · string

    ten_ id or tenant slug

  • Tact-Signaturerequired

    header · string

Request body

  • account

    string

  • events

    object[]

Request example
{
  "account": "string",
  "events": [
    {
      "id": "msg_9001",
      "type": "appointment.cancelled",
      "occurred_at": "2026-11-02T09:30:00+00:00",
      "data": {},
      "account": "string"
    }
  ]
}
Response example · 202
{
  "object": "outbox_receipt",
  "received": 1,
  "deduplicated": 1,
  "rejected": [
    {}
  ]
}
Errors · 401
  • 401Authentication failed (key_invalid, key_revoked, key_expired)

Runs5 routes

GET/v1/runs

List runs

Tact-Account requiredthreads:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

  • thread_id

    query · string

  • created_after

    query · string (date-time)

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "run_01JB6ZK8TQ0000000000000000",
      "object": "run",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "thread_id": "string",
      "task_id": "string",
      "status": "queued",
      "outcome": "string",
      "trigger": {
        "kind": "string",
        "ref": "string"
      },
      "foreground": true,
      "step_count": 1,
      "models_used": [
        "string"
      ],
      "cost": {
        "model_usd_micros": 1,
        "channel_micros": 1,
        "voice_micros": 1,
        "tools_micros": 1,
        "channel": [
          {
            "currency": "EUR",
            "amount_micros": 1,
            "items": 1,
            "category": "string"
          }
        ]
      },
      "error_code": "string",
      "latency_ms": 1,
      "queued_at": "2026-11-02T09:30:00+00:00",
      "started_at": "2026-11-02T09:30:00+00:00",
      "finished_at": "2026-11-02T09:30:00+00:00",
      "steps": [
        {
          "n": 1,
          "kind": "string",
          "model": "string",
          "verdict": "string",
          "latency_ms": 1,
          "created_at": "2026-11-02T09:30:00+00:00"
        }
      ],
      "actions": [
        {
          "id": "act_01JB6ZK8TQ0000000000000000",
          "action_type": "string",
          "verdict": "string",
          "status": "string"
        }
      ]
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/runs/{id}

Retrieve a run with steps, actions and cost

Tact-Account optionalthreads:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "run_01JB6ZK8TQ0000000000000000",
  "object": "run",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "thread_id": "string",
  "task_id": "string",
  "status": "queued",
  "outcome": "string",
  "trigger": {
    "kind": "string",
    "ref": "string"
  },
  "foreground": true,
  "step_count": 1,
  "models_used": [
    "string"
  ],
  "cost": {
    "model_usd_micros": 1,
    "channel_micros": 1,
    "voice_micros": 1,
    "tools_micros": 1,
    "channel": [
      {
        "currency": "EUR",
        "amount_micros": 1,
        "items": 1,
        "category": "string"
      }
    ]
  },
  "error_code": "string",
  "latency_ms": 1,
  "queued_at": "2026-11-02T09:30:00+00:00",
  "started_at": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00",
  "steps": [
    {
      "n": 1,
      "kind": "string",
      "model": "string",
      "verdict": "string",
      "latency_ms": 1,
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "actions": [
    {
      "id": "act_01JB6ZK8TQ0000000000000000",
      "action_type": "string",
      "verdict": "string",
      "status": "string"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/runs/{id}/cancel

Cancel a queued or running run

Tact-Account optionalthreads:write

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "run_01JB6ZK8TQ0000000000000000",
  "object": "run",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "thread_id": "string",
  "task_id": "string",
  "status": "queued",
  "outcome": "string",
  "trigger": {
    "kind": "string",
    "ref": "string"
  },
  "foreground": true,
  "step_count": 1,
  "models_used": [
    "string"
  ],
  "cost": {
    "model_usd_micros": 1,
    "channel_micros": 1,
    "voice_micros": 1,
    "tools_micros": 1,
    "channel": [
      {
        "currency": "EUR",
        "amount_micros": 1,
        "items": 1,
        "category": "string"
      }
    ]
  },
  "error_code": "string",
  "latency_ms": 1,
  "queued_at": "2026-11-02T09:30:00+00:00",
  "started_at": "2026-11-02T09:30:00+00:00",
  "finished_at": "2026-11-02T09:30:00+00:00",
  "steps": [
    {
      "n": 1,
      "kind": "string",
      "model": "string",
      "verdict": "string",
      "latency_ms": 1,
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ],
  "actions": [
    {
      "id": "act_01JB6ZK8TQ0000000000000000",
      "action_type": "string",
      "verdict": "string",
      "status": "string"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/actions

Audit trail of actions

Tact-Account requiredthreads:read

Parameters

  • Tact-Accountrequired

    header · string

    acc_... or ext:<external_ref>

  • limit

    query · integer

  • cursor

    query · string

  • status

    query · string

  • action_type

    query · string

  • run_id

    query · string

  • thread_id

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "act_01JB6ZK8TQ0000000000000000",
      "object": "action",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "run_id": "string",
      "thread_id": "string",
      "action_type": "string",
      "tool": "string",
      "action_class": "string",
      "risk": "string",
      "status": "string",
      "policy_decision": "allow",
      "guardian_verdict": "string",
      "approval_id": "string",
      "target_contact_id": "string",
      "args_sha256": "string",
      "generated_by_ai": true,
      "result_summary": {},
      "cost_micros": 1,
      "seq": 1,
      "row_hash": "string",
      "created_at": "2026-11-02T09:30:00+00:00",
      "executed_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/actions/{id}

Retrieve an action

Tact-Account optionalthreads:read

Parameters

  • idrequired

    path · string

  • Tact-Account

    header · string

    When sent, the object must belong to this account

Response example · 200
{
  "id": "act_01JB6ZK8TQ0000000000000000",
  "object": "action",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "agent_id": "agt_01JB6ZK8TQ0000000000000000",
  "run_id": "string",
  "thread_id": "string",
  "action_type": "string",
  "tool": "string",
  "action_class": "string",
  "risk": "string",
  "status": "string",
  "policy_decision": "allow",
  "guardian_verdict": "string",
  "approval_id": "string",
  "target_contact_id": "string",
  "args_sha256": "string",
  "generated_by_ai": true,
  "result_summary": {},
  "cost_micros": 1,
  "seq": 1,
  "row_hash": "string",
  "created_at": "2026-11-02T09:30:00+00:00",
  "executed_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Usage3 routes

GET/v1/usage

Usage events

Tact-Account optionalusage:read

Parameters

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • limit

    query · integer

  • cursor

    query · string

  • account_id

    query · string

  • kind

    query · string

  • from

    query · string (date-time)

  • to

    query · string (date-time)

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "msg_9001",
      "object": "usage_event",
      "account_id": "acc_01JB6ZK8TQ0000000000000000",
      "agent_id": "agt_01JB6ZK8TQ0000000000000000",
      "thread_id": "string",
      "run_id": "string",
      "kind": "string",
      "purpose": "string",
      "quantity": 1.5,
      "cost_usd_micros": 1,
      "cost_source": {
        "amount": 1.5,
        "currency": "EUR"
      },
      "payer": "string",
      "within_free_quota": true,
      "occurred_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/usage/summary

Monthly summary per account (UTC month)

Tact-Account optionalusage:read

Parameters

  • Tact-Account

    header · string

    When sent, the object must belong to this account

  • period

    query · string

  • group_by

    query · "account" | "tenant"

Response example · 200
{
  "object": "usage_summary",
  "period": "string",
  "timezone": "UTC",
  "group_by": "account",
  "data": [
    {}
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PUT/v1/budgets/{account_id}

Set the monthly budget of an account

accounts:write

Parameters

  • account_idrequired

    path · string

Request body

  • monthly_usd_microsrequired

    integer

  • on_exceed

    "alert" | "degrade" | "block"

  • category

    "model" | "channel" | "voice" | "browser" | "all"

Request example
{
  "monthly_usd_micros": 1,
  "on_exceed": "alert",
  "category": "model"
}
Response example · 200
{
  "id": "bud_01JB6ZK8TQ0000000000000000",
  "object": "budget",
  "account_id": "acc_01JB6ZK8TQ0000000000000000",
  "period": "string",
  "category": "string",
  "currency": "EUR",
  "limit_usd_micros": 1,
  "spent_usd_micros": 1,
  "period_start": "string",
  "on_exceed": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After

Webhooks7 routes

GET/v1/webhook_endpoints

List webhook endpoints

admin

Parameters

  • limit

    query · integer

  • cursor

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "whe_01JB6ZK8TQ0000000000000000",
      "object": "webhook_endpoint",
      "url": "https://example.com/tact/webhooks",
      "events": [
        "string"
      ],
      "include_text": true,
      "api_version": "string",
      "description": "string",
      "status": "enabled",
      "failures": 1,
      "disabled_at": "2026-11-02T09:30:00+00:00",
      "previous_secret_expires_at": "2026-11-02T09:30:00+00:00",
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/webhook_endpoints

Create a webhook endpoint (secret shown once)

admin

Parameters

  • Idempotency-Key

    header · string

Request body

  • urlrequired

    string

    Public https URL

  • eventsrequired

    string[]

  • include_text

    boolean

    Include message text and approval summaries

  • api_version

    string

  • description

    string

Request example
{
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "api_version": "string",
  "description": "string"
}
Response example · 201
{
  "id": "whe_01JB6ZK8TQ0000000000000000",
  "object": "webhook_endpoint",
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "api_version": "string",
  "description": "string",
  "status": "enabled",
  "failures": 1,
  "disabled_at": "2026-11-02T09:30:00+00:00",
  "previous_secret_expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "secret": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/webhook_endpoints/{id}

Retrieve a webhook endpoint

admin

Parameters

  • idrequired

    path · string

Response example · 200
{
  "id": "whe_01JB6ZK8TQ0000000000000000",
  "object": "webhook_endpoint",
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "api_version": "string",
  "description": "string",
  "status": "enabled",
  "failures": 1,
  "disabled_at": "2026-11-02T09:30:00+00:00",
  "previous_secret_expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
PATCH/v1/webhook_endpoints/{id}

Update or re-enable a webhook endpoint

admin

Parameters

  • idrequired

    path · string

Request body

  • url

    string

  • events

    string[]

  • include_text

    boolean

  • description

    string

  • enabled

    boolean

    true re-enables and resets the failure count

Request example
{
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "description": "string",
  "enabled": true
}
Response example · 200
{
  "id": "whe_01JB6ZK8TQ0000000000000000",
  "object": "webhook_endpoint",
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "api_version": "string",
  "description": "string",
  "status": "enabled",
  "failures": 1,
  "disabled_at": "2026-11-02T09:30:00+00:00",
  "previous_secret_expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/webhook_endpoints/{id}/rotate_secret

Rotate the secret; the previous one stays valid for 24 h

admin

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Response example · 200
{
  "id": "whe_01JB6ZK8TQ0000000000000000",
  "object": "webhook_endpoint",
  "url": "https://example.com/tact/webhooks",
  "events": [
    "string"
  ],
  "include_text": true,
  "api_version": "string",
  "description": "string",
  "status": "enabled",
  "failures": 1,
  "disabled_at": "2026-11-02T09:30:00+00:00",
  "previous_secret_expires_at": "2026-11-02T09:30:00+00:00",
  "created_at": "2026-11-02T09:30:00+00:00",
  "secret": "string"
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
POST/v1/webhook_endpoints/{id}/replay

Redeliver the events of a time range

admin

Parameters

  • idrequired

    path · string

  • Idempotency-Key

    header · string

Request body

  • fromrequired

    string (date-time)

  • to

    string (date-time)

  • event_types

    string[]

Request example
{
  "from": "2026-11-02T09:30:00+00:00",
  "to": "2026-11-02T09:30:00+00:00",
  "event_types": [
    "string"
  ]
}
Response example · 200
{
  "object": "webhook_replay",
  "endpoint_id": "whe_01JB6ZK8TQ0000000000000000",
  "deliveries": 1
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After
GET/v1/webhook_deliveries

List deliveries

admin

Parameters

  • limit

    query · integer

  • cursor

    query · string

  • endpoint_id

    query · string

  • status

    query · string

  • event_type

    query · string

Response example · 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "id": "msg_9001",
      "object": "webhook_delivery",
      "endpoint_id": "whe_01JB6ZK8TQ0000000000000000",
      "event_id": "evt_01JB6ZK8TQ0000000000000000",
      "event_type": "string",
      "status": "pending",
      "attempt": 1,
      "next_attempt_at": "2026-11-02T09:30:00+00:00",
      "last_status_code": 1,
      "created_at": "2026-11-02T09:30:00+00:00"
    }
  ]
}
Errors · 400 401 403 404 409 422 429
  • 400Invalid request (parameter_missing, parameter_invalid, scope_in_body, unsupported_locale, phone_not_e164)
  • 401Authentication failed (key_invalid, key_revoked, key_expired)
  • 403Permission denied (scope_missing, account_not_in_tenant, dpa_not_signed, principal_not_allowed_to_approve)
  • 404Not found (resource_missing)
  • 409Conflict (idempotency_key_reused, approval_already_decided, pack_version_immutable)
  • 422Policy or pack error (blocked_by_floor, content_policy_violation, missing_prerequisite, evals_not_passed, tool_schema_invalid)
  • 429Rate limited (rate_limited, budget_exhausted); see Retry-After