API keys, authentication, and the error envelope

Creating keys, Bearer auth, pagination and rate limits, the standard error shape, and a first request in curl.

Everything the dashboard does is available over the REST API at /api/v1. Keys are created under Settings → API keys — name the key, and copy the secret when it's shown, because it's displayed exactly once and stored hashed. Keys are scoped to the workspace they're created in and act with that workspace's data only.

Authentication

Pass the key as a Bearer token on every request:

First request
curl https://app.sendcanyon.com/api/v1/campaigns \
  -H "Authorization: Bearer sc_live_9f2ab..." \
  -H "Content-Type: application/json"
Response
{
  "data": [
    {
      "id": "6b9d2c1e-8a44-4f0b-9c3a-2f1d5e7a0b8c",
      "name": "Q3 outbound — RevOps leaders",
      "status": "running",
      "created_at": "2026-07-02T09:14:33Z"
    }
  ],
  "next_cursor": "eyJpZCI6IjZiOWQi..."
}

Pagination and rate limits

List endpoints use cursor pagination: pass ?cursor= from the previous response's next_cursor until it comes back null, with ?limit= up to 100. Requests are rate-limited per key; every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers, and exceeding the limit returns 429 with a Retry-After header. Back off exponentially on 429 — the limit is per key, so a hot loop starves your own integration.

The error envelope

Every error, from any endpoint, has the same shape — an error object with a stable machine-readable code and a human-readable message:

Error response — 404
{
  "error": {
    "code": "not_found",
    "message": "No campaign with that id exists in this workspace."
  }
}
HTTPcodeMeaning
400validation_errorA field failed validation; the message names the field
401unauthorizedMissing, malformed, or revoked API key
403forbiddenKey is valid but the role can't perform this mutation
404not_foundNo such resource in this workspace (including other workspaces' ids)
409conflictState conflict, e.g. launching an already-running campaign
422limit_exceededA plan limit blocks the action; upgrade or reduce usage
429rate_limitedToo many requests for this key; honor Retry-After
500internal_errorOur fault; safe to retry with backoff

What's on the API

  • Domains: create, list, fetch generated DNS records, trigger verification.
  • Mailboxes: connect, test-connection, warmup start/stop/status.
  • Contacts and lists: CRUD, CSV import, validation, suppressions.
  • Campaigns: CRUD, launch/pause/resume/duplicate, per-campaign stats.
  • Messages and events: read endpoints for everything sent and everything observed.
  • Analytics, billing state, and outbound webhook configuration.

All request and response bodies are JSON; all timestamps are UTC ISO 8601; all ids are UUIDs. Mutating endpoints validate strictly and reject unknown fields with validation_error rather than ignoring them.