Skip to main content

Calling the API

Calling the API

  • Base URL: https://{{HUBTALK_FQDN}} — every path below starts with /v1. Substitute the host your own dashboard runs on for {{HUBTALK_FQDN}} — for example app.hubtalk.ai.
  • Format: JSON in the request and in the response. Time values are epoch seconds.
  • Machine-readable schema: GET https://{{HUBTALK_FQDN}}/openapi.json, with an interactive explorer at https://{{HUBTALK_FQDN}}/docs. The schema is authoritative for requests; success responses are published there as untyped objects, so the tables on this page are the response contract.

Authentication

Every /v1 request carries the key:
The secret (cfk_ + hex) is issued in the dashboard and shown once (The access key); the platform stores only a SHA-256 hash. A revoked key stops working immediately — the key record is re-read on every request. A key is scoped to the organization it was issued in: anything outside that boundary is indistinguishable from missing (404), never 403. None of the endpoints in this guide require a privileged key. Per-key rate limit. Each key has a sliding 60-second window over all its /v1 requests. The limit is set per key at creation and can be changed later in the dashboard without rotating the secret (it applies from the next request). A key limit of 0 means the platform default — a deployment setting, 60 requests per minute unless the operator changed it; an operator may also disable the limit. This is one of four distinct 429 sources.

One error envelope

All /v1 errors look the same:
error.code names the exact cause within the type and is always present: when no more specific cause is registered, code equals type. New codes are added over time — handle an unrecognized code by falling back to type + status. Two additive fields appear only on specific campaign refusals and nowhere else: error.blockers on 409 launch_blocked and error.import on 422 calls_rejected / 422 calls_dnc_matched. Every other error carries exactly the four fields above.
Classify the error on error.type + error.status, and the exact cause on error.code. Never match on error.message — it is a human-readable English diagnostic, looked up by code at the API boundary, and not part of the contract. On 422 schema-validation errors (code: "invalid_request") message is an array of field-level issues in FastAPI/pydantic form ({"type", "loc", "msg", "input"}) rather than a string.
Refusals carry their headers through the envelope: Retry-After on 429s is always delivered.

Rate limits and 429

A 429 comes from four independent sources. All carry error.type: "rate_limit_error" — distinguish them by error.code: Subgroup limits default to 10 concurrent calls and 30 initiations per minute unless the administrator configured other values; for a trunk used under a grant the effective limit is the smaller of the subgroup’s and the grant’s.

Request map

Campaigns Uploads Lines Individual calls