Graine AI

Graine API

A voice-AI calling API — build an agent, place a call, and follow that one call from the dial to the transcript with a single id.

The Graine API places real phone calls conducted by a conversational voice agent, and gives you everything the call produced afterwards — status, duration, cost, transcript and recording.

Four resources cover the whole surface:

  • Agents — the configuration that decides what the agent says and how it sounds.
  • Calls — one outbound call, now or scheduled, tracked end to end.
  • Campaigns — a contact list dialled by one agent, with the policy that governs it: caller IDs, calling hours, retries and follow-ups. Pause, resume and cancel.
  • Account — who your key belongs to, what it has spent, and key management.

Base URL

https://api.graine.ai/v2

Every path in these docs is relative to that URL. The version lives in the path, so /v2 is a stable prefix — not a header, not a query parameter.

Your first request

curl https://api.graine.ai/v2/user/me \
  -H "Authorization: Bearer gat_7f3c9a21b4e85d0c6a19f2734b8e5c60"

If that returns your organization, your key works and you are ready for the Quickstart.

Explore

Conventions

These hold on every endpoint, so they are stated once here rather than repeated on each page.

ConcernRule
AuthenticationAuthorization: Bearer gat_... — the only accepted form. X-API-Key and X-API-DEV are not read on /v2.
OrganizationTaken from the key. The optional ?organization_id= query parameter must match the key's own organization or the request is refused.
ErrorsAlways {"error": <integer>, "message": "<sentence>"}. A success response never carries error.
TimestampsISO-8601 UTC, millisecond precision, literal Z2026-08-26T10:15:30.123Z.
Phone numbersE.164, 7 to 15 digits, for example +14155550123.
Request bodiesUnknown keys are rejected with error 1001, so a typo'd field name fails loudly instead of silently doing nothing.
Rate limit headersX-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset are on every response, success or failure.

Pagination

Every list endpoint takes page (1-indexed, default 1) and page_size (default 20, maximum 100), and returns the same envelope:

{
  "data": [],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 137,
    "total_pages": 7,
    "has_more": true
  }
}

Page until has_more is false rather than dividing total yourself. On very large collections total is a capped estimate, and on GET /v2/agents it is corrected for hidden internal records on the page being returned.

Identifiers

IdWhere it comes fromWhat it is for
agent_idPOST /v2/agentsNaming the agent on a call, a campaign, or a clone.
execution_idPOST /v2/calls, or a contact in a campaignOne call, for its whole life — scheduled, ringing, in progress, finished. Transcript, recording and stop all key off it.
campaign_idPOST /v2/campaignsPausing, resuming, cancelling and reporting on a contact list.
key_idGET /v2/api-keysRevoking a key. Never the key itself.

execution_id is minted before the call is placed and handed back immediately, which is what makes the API safe to integrate against: even if a dial request times out, the id you already hold answers GET /v2/calls/{execution_id}. Poll it — never redial.

Rate limits at a glance

Limits are per organization, not per key, so minting more keys does not buy more quota.

BucketEndpointsLimit
calls.createPOST /v2/calls, POST /v2/campaigns500 / minute
executions.listGET /v2/calls, GET /v2/agents/{id}/executions500 / minute
defaultEverything else1000 / minute

Exceeding a limit returns 429 with error code 1300 and a Retry-After header. See Rate limits for the sliding-window details.

On this page