Skip to main content
The endpoints under https://app.haloagents.ai/api/v1 are for integrations that act on behalf of a workspace: the Zapier app is built on them. They differ from the SDK endpoints in one way: they take an OAuth 2.0 access token, never the publishable widget key.
The REST API is the API access capability (Pro and up). A token for a workspace on another plan gets 403 upgrade_required.

Authentication

Halo’s authorization server is the one the MCP connector uses. Discovery lives at /.well-known/oauth-authorization-server; the flow is authorization code with PKCE, refresh tokens rotate, and the consent screen lets the person pick the scopes they grant. To get a token that works here, bind the grant to this API with the RFC 8707 resource parameter on both the authorize and the token request:
Then send it on every call:
Register a client with POST /api/mcp/oauth/register (dynamic client registration; use token_endpoint_auth_method: client_secret_post for a confidential client).

Scopes

A call the token’s scopes do not cover returns 403 insufficient_scope. Every call is also limited to what the person who granted the token can do in the dashboard.

Errors

Errors are { "error": "<code>", "error_description": "<message>" }. 401 invalid_token carries a WWW-Authenticate challenge; 429 rate_limited carries Retry-After (300 requests per minute per token).

Endpoints

GET /api/v1/me

The workspace, the person who granted the token and the scopes it holds.

GET /api/v1/tools and POST /api/v1/tools/{name}

The tools the token may call, with their JSON Schema, and a way to run one: the body is the tool’s arguments, the response is { "tool": "<name>", "result": … }. These are the same tools the MCP connector exposes (inbox_create_ticket, inbox_reply_ticket_email, data_create_user, data_update_company, cs_create_deal, cs_move_deal_stage, create_task, cs_create_issue, workflow_enroll_records, …), run through the same validation, permission checks and audit log.
A tool that ran but failed at the business level (not found, validation, not allowed) is a 4xx with the tool’s message.

GET /api/v1/records/{type}

The newest records of one kind, in the same shape webhook deliveries carry them, with simple filters. limit is 1–50 (default 3). Response: { "records": [ … ] }.

GET /api/v1/lookups/{kind}

Short { id, name } lists for pickers: members, agents, inboxes, pipelines, stages (?pipeline_id= narrows), workflows, ticket_statuses, issue_priorities. Response: { "items": [ … ] }.

Webhooks

A webhook subscription asks Halo to POST events to a URL. Subscriptions are per workspace and per token’s OAuth client: deliveries stop while that client holds no live token (the person disconnected it).

GET /api/v1/webhooks/events

The catalog. Each event needs its object’s read scope to subscribe.

POST /api/v1/webhooks

Returns 201 with { "webhook": { … }, "secret": "whsec_…" }. The secret is shown once. url must be https on a public host. A workspace may hold 100 active subscriptions.

GET /api/v1/webhooks, GET /api/v1/webhooks/{id}, DELETE /api/v1/webhooks/{id}

List, read, and remove the subscriptions this token’s OAuth client registered; another client’s are never visible. DELETE answers 204, or 404 when it was already gone.

Deliveries

Each delivery is a POST with the envelope:
id is stable across retries of the same event: deduplicate on it. Headers: Verify by recomputing the HMAC over <timestamp>.<raw body> with the subscription’s secret and comparing in constant time; reject timestamps older than a few minutes. Answer 2xx within 10 seconds. A 5xx, 408, 429 or timeout is retried with backoff; any other 4xx is final for that event. After 10 consecutive failed events the subscription is switched off (disabled_reason: too_many_failures); a 410 Gone switches it off at once (receiver_gone).