For developers

real API. And docs your coding agent can read directly. 

Everything the console does once a quarter stays in the console. Everything you call ten thousand times a day is on the API — a small, flat, versioned REST surface with signed webhooks pushing the other way.

14

webhook events

11

API scopes

120/min

per key, headers included

66

pages of public docs

The API

Send a message. Place a call. Read the transcript.

Base URL services.amomic.in/api/v1, authenticated with a workspace-scoped key, server-side only. Every response is one envelope, every id is stable, and every failure carries a code you can branch on plus a request id you can quote.

  • Messages, calls, conversations, tickets, contacts, campaigns and payments
  • Idempotency keys, so a retry after a timeout never double-sends
  • Cursor pagination designed for incremental warehouse sync
  • A dry-run endpoint that tells you whether a campaign launch would be allowed
POST/api/v1/messages
Authorization: Bearer amk_live_…
Idempotency-Key: order-4471-shipped

{ "to": "+919876543210",
  "template": { "name": "order_shipped",
                "variables": ["4471","6 PM"] } }
201 Createdmsg_01J9…

Retry after a timeout and you get this same response, not a second message.

The whole surface

Small enough to read in one sitting.

No agent-building routes and no plans to grow them — configuration belongs where a person can review it. Traffic belongs here.

Selected routes

POST/messagesSend WhatsApp text or an approved template
POST/callsPlace an outbound AI voice call
GET/conversationsList conversations, newest first
GET/conversations/{id}/messagesPull a full transcript
POST/ticketsOpen a support ticket
PATCH/tickets/{id}Update one, with a version check
POST/contactsUpsert someone in the directory
POST/campaignsCreate, evaluate and launch a campaign

Every webhook event

message.receivedmessage.statusconversation.startedconversation.endedcall.startedcall.endedticket.createdticket.updatedlead.createdcampaign.launchedcampaign.completedpayment.due_createdpayment.paidpayment.declinedping

Null fields are omitted rather than sent as null, and the field lists are allow-lists — so a new field can never break a strict consumer.

Webhooks

We push, with retries and a replay button.

Every delivery carries a timestamped HMAC-SHA256 signature over the raw body. Four attempts, dead-letter records for what never landed, a delivery log you can read, and auto-disable if your endpoint stays broken.

  • Verify the signature against the exact bytes, in constant time
  • At-least-once delivery — deduplicate on the event id
  • Replay a failed event from the console after you've fixed your side
  • A documented reconciliation path for gaps after an outage

Return 2xx fast and do the work afterwards. A slow endpoint looks identical to a broken one from our side.

lead.created200
call.ended200
ticket.created500 → retry 1
ticket.created200 · recovered
payment.paid200

Four attempts, a dead-letter record, and replay from the console.

Keys & scopes

One key per system, carrying the least it needs.

Eleven scopes, and a new key starts read-only. Build the analytics job against a key that structurally cannot send a message — then the worst case for that key leaking is an information problem, not a customer-facing one.

  • Separate read and write scopes for contacts and campaigns
  • Secrets stored hashed — shown once, then a masked hint. Nobody can recover one
  • Roll with a grace period, or revoke immediately
  • Rate limited per key, so a backfill can't starve production sends
amk_live_7f2…warehouse-sync
conversations:readcontacts:readmessages:sendcalls:writecampaigns:write

This key can read every transcript and cannot send anything — not to a customer, not by accident, not ever.

Coding agents

Point Claude Code at the real contract.

An agent that has read the actual documentation writes working code on the first attempt. One that's guessing from a vague memory of 'some WhatsApp API' invents endpoints that never existed. So the docs ship in machine-readable form, publicly, with no key required.

  • An MCP server your agent can query mid-task instead of ingesting everything
  • llms.txt for a curated index, llms-full.txt for the whole corpus in one fetch
  • Append .md to any docs URL for clean markdown with no navigation
  • OpenAPI 3.1, generated from the running service — feed it to a client generator
one command
claude mcp add --transport http amomic \
  https://docs.amomic.in/mcp
/llms.txt — curated index
/llms-full.txt — the whole corpus
any page + .md — clean markdown
/openapi.json — generated from the live service
Running it in production

The parts you'll care about at 3 a.m.

All of it written down before you needed it.

Test and live, kept apart

A test key pointed at the live host fails loudly. Integrate without texting a real customer.

Idempotency

An Idempotency-Key on the POSTs that matter replays the stored response for 24 hours.

Cursor pagination

One envelope, one cursor, one rule — a short page ends the walk. Built for incremental sync.

No CORS, deliberately

Keys are workspace-scoped, so /api/v1 is server-side only. Use the headless widget client in the browser.

A versioning policy

What /api/v1 promises, what can change without notice, and how to write client code that survives both.

Errors, indexed by symptom

Nine codes and every details.reason value, listed by what you actually see in your logs.

Mint a key and send a real message in a minute.

The quickstart is one authenticated request. No sales call, no sandbox request form.