Skip to main content
API & MCP

REST API

imatic products ship REST APIs you can automate from your own code. The conventions on this page — how you authenticate, how API keys work, how webhooks are signed, and how pagination, rate limits, and errors behave — are the same across products. What differs is the URL shape and the resources each product exposes: Calendar uses versioned /v1 paths, while Survey uses verb-style POST endpoints. Each product's developer page documents its exact surface.

Examples are illustrative

The request and response snippets below show the shape of calls — headers, auth, error envelopes — not an exact field-by-field schema. For the precise endpoints, parameters, and field names of a product, follow the links to that product's developer page.

Authentication​

imatic uses two kinds of credentials, for two different callers:

  • JWT (session token) — what the web app uses after you sign in with email and password. It represents you in the browser and is short-lived. You don't manage this directly; the app does.
  • Scoped API key — what your code uses to call the v1 REST API. You create it yourself, it carries explicit scopes, and it doesn't expire with a browser session.

For server-to-server calls, always use an API key — never your password or a copied session token.

Sending an API key​

Pass the key as a Bearer token in the Authorization header:

curl https://<product-host>/v1/event-types \
-H "Authorization: Bearer cal_abc123.s3cr3t_keymaterial" \
-H "Content-Type: application/json"

How API keys work​

You create and manage API keys in each product's developer area — for example Calendar's Developers → API keys and Survey's Developers → API keys. A key has three properties worth understanding:

  • prefix.secret format — a key has a public prefix and a secret part, joined by a dot (for example cal_abc123.s3cr3t_keymaterial — Calendar keys use a short cal_ prefix). The prefix lets imatic identify the key in lists and logs; the secret is what proves it's yours.
  • Shown once — the full key value is displayed only at the moment you create it. After that, only the prefix is visible.
  • Scopes — each key is limited to the actions you grant it. Calendar's scopes are slots:read, bookings:read, bookings:write, and mcp (the mcp scope is what an AI agent's key needs — see MCP for AI agents). A request that exceeds a key's scope is rejected.
Treat API keys like passwords

A key's secret is shown only once, at creation. Copy it then and store it in a secret manager or environment variable — never in source control, a screenshot, or a shared doc. If a key is exposed, revoke it in the developer area and create a replacement. Revocation takes effect immediately.

Webhooks​

Rather than polling for changes, register a webhook URL and imatic will POST an event to it when something happens — for example a booking is created in Calendar or a response is submitted in Survey. You manage webhook endpoints in each product's Developers → Webhooks area, where you can also send a test delivery.

A delivery looks roughly like this:

POST /your/webhook/endpoint HTTP/1.1
Content-Type: application/json
X-Imatic-Signature: t=1718900000,v1=9f86d081884c7d659a2feaa0c55ad015...

{
"event": "booking.created",
"data": { "...": "event-specific payload" }
}

Verifying the signature​

Each delivery is signed with HMAC-SHA256 using your endpoint's signing secret, in a Stripe-style X-Imatic-Signature header. The header carries two fields: t, the unix-epoch seconds at send time, and v1, the hex HMAC of the string ${t}.${body} (the timestamp, a literal dot, then the exact raw request body). To verify, split the header, recompute v1 over t + "." + rawBody with your signing secret, and compare in constant time. Reject if they don't match — and optionally reject when t is older than a few minutes to guard against replay.

import crypto from "node:crypto";

function isValid(rawBody, signatureHeader, signingSecret) {
// Header shape: "t=<epoch-seconds>,v1=<hex hmac>"
const parts = Object.fromEntries(
signatureHeader.split(",").map((kv) => kv.split("=")),
);
const { t, v1 } = parts;
if (!t || !v1) return false;

// Sign the timestamped body: `${t}.${rawBody}` — NOT the raw body alone.
const expected = crypto
.createHmac("sha256", signingSecret)
.update(`${t}.${rawBody}`)
.digest("hex");

// Constant-time comparison to avoid timing attacks.
const a = Buffer.from(v1);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Exact scheme per product

The t=…,v1=… scheme above is Calendar's. Confirm header name, fields, and the signed string on each product's developer page before you ship a verifier.

Respond fast, process later

Return a 2xx quickly to acknowledge receipt, then do any slow work asynchronously. If your endpoint is slow or errors, deliveries may be retried.

Pagination​

List endpoints return results in pages so a single call never has to load everything. Pass paging parameters on the request and read the paging metadata on the response to fetch the next page.

curl "https://<product-host>/v1/bookings?limit=25" \
-H "Authorization: Bearer cal_abc123.s3cr3t_keymaterial"
{
"success": true,
"data": [ { "...": "one item per result" } ],
"pagination": { "page": 1, "limit": 20, "total": 0, "pages": 0 }
}

Keep requesting the next page until there are no more results.

Rate limiting​

API keys are rate limited to keep the platform fair and stable. If you exceed the limit, the API responds with HTTP 429 Too Many Requests. Back off and retry — ideally with exponential backoff and jitter — rather than hammering the endpoint.

{
"success": false,
"error": "rate_limited",
"message": "Too many requests. Please retry after a short delay."
}

Error handling​

Errors use standard HTTP status codes with a JSON body that describes what went wrong. Codes you'll see most often:

  • 400 — the request was malformed or failed validation.
  • 401 — missing or invalid API key.
  • 403 — the key is valid but lacks the scope (or org access) for this action.
  • 404 — the resource doesn't exist or isn't visible to this key.
  • 409 — a conflict, such as trying to book a slot that was just taken.
  • 429 — rate limited; back off and retry.
  • 5xx — a server-side error; retry transient failures.

A typical error envelope:

{
"success": false,
"error": "validation_failed",
"message": "A human-readable explanation of the problem."
}

Resources by product​

The conventions above are shared, but each product exposes its own endpoints. Start from the product's developer page for exact resources, parameters, and field names:

  • Calendar — event types, availability slots, bookings (create, reschedule, cancel), calendars, webhooks, API keys, and event links. Webhook events are booking.created, booking.cancelled, booking.rescheduled, and booking.no_show. See Calendar for developers.
  • Survey — forms, responses, response aggregation, AI form generation, and webhooks (response.created, response.flagged, response.updated, form.published, form.closed). See Survey for developers.
  • Voice Portal — agents, campaigns, and contacts, plus tools and MCP server registration. See Tools & MCP for agents.