MamontCall API
Trigger outbound calls from your CRM, look up rates, check what a call cost, and get a webhook when it finishes — without ever touching the underlying phone system directly.
Already a MamontCall customer? Log in to the portal and open Developer to generate your API key.
Open the portal →Authentication
Every request needs a Bearer key in the Authorization header:
Authorization: Bearer mc_live_...
The portal's Developer page can hold two active keys at once: generating a new key keeps the previous one working until you revoke it, so you can rotate keys with zero downtime. A machine-readable contract for this whole API lives at GET /v1/openapi.json (OpenAPI 3.1).
Place a call
POST/v1/click-to-call
Rings device first; once answered, bridges to destination. Limited to one call per device every 3 seconds.
curl -X POST https://api.mamontcall.com/v1/click-to-call \
-H "Authorization: Bearer mc_live_..." \
-H "Content-Type: application/json" \
-d '{
"device": "101",
"destination": "+15551234567",
"client_reference": "lead-42"
}'
# 202 Accepted
{"ok": true, "call_id": "17834168392648973"}
Request body
| Field | Required | Description |
|---|---|---|
device | Yes | The device's SIP username / extension exactly as shown on the portal's Lines page (e.g. 9995552426) — not its numeric id |
destination | Yes | The number to bridge to once device answers |
client_reference | No | Your own id, echoed back in the webhook (max 128 chars) |
Idempotency & rate limits
Send an Idempotency-Key header (any unique string per intended call, max 128 chars) and a retried request within 10 minutes returns the original call_id with "replayed": true instead of dialing twice. Reusing a key with a different device/destination returns 409.
Limits: one call per device every 3 seconds, and 60 requests per key per minute — both answer 429 with Retry-After. A failed initiation does not consume the device throttle, so an immediate retry is allowed.
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
400 | device or destination missing |
404 | device not found on your account |
409 | Idempotency-Key reused with different parameters |
422 | The device has no CallerID and no DID, so there is no number to ring it back on — set one in the portal or contact support |
429 | Device used within the last 3 seconds, or the key exceeded 60 requests/minute — see Retry-After |
502 | The call could not be initiated |
Fetch a recording
GET/v1/calls/{call_id}/recording
Returns the call's audio as audio/mpeg once available, scoped to your own account. Returns 404 if there's no recording yet or the id doesn't belong to you.
List & poll your calls
GET/v1/calls
Every click-to-call your account has placed, newest first — use it to reconcile against missed webhooks. Query params: since (ISO 8601 or epoch milliseconds), limit (1–200, default 50), offset.
curl "https://api.mamontcall.com/v1/calls?since=2026-07-30T00:00:00Z" \
-H "Authorization: Bearer mc_live_..."
# 200 OK
{
"total": 2,
"calls": [
{ "call_id": "17854030425788856", "destination": "+16473035551", "initiated_at": "2026-07-30T09:17:22.720Z" },
{ "call_id": "17854029866509020", "destination": "+14378898460", "initiated_at": "2026-07-30T09:16:26.804Z" }
]
}
GET/v1/calls/{call_id}
Poll one call's outcome without webhooks. status is pending until the call record lands, then the same vocabulary as the webhook, plus duration_seconds and cost.
curl https://api.mamontcall.com/v1/calls/17854030425788856 \
-H "Authorization: Bearer mc_live_..."
# 200 OK
{
"call_id": "17854030425788856",
"destination": "+16473035551",
"initiated_at": "2026-07-30T09:17:22.720Z",
"status": "answered",
"duration_seconds": 34,
"cost": 0.025
}
Check agent status
GET/v1/agents/status
Which of your own devices are online and which are currently on a call — for routing a click-to-call before dialing, or a live dashboard. Poll it; there's no per-request rate limit.
curl https://api.mamontcall.com/v1/agents/status \
-H "Authorization: Bearer mc_live_..."
# optionally filter to specific devices:
curl "https://api.mamontcall.com/v1/agents/status?device=101,102" \
-H "Authorization: Bearer mc_live_..."
# 200 OK
{
"agents": [
{
"device": "101",
"online": true,
"on_call": true,
"callback_ready": true,
"destination": "+15551234567",
"duration_seconds": 42,
"last_call_end": "2026-07-07T09:34:41.000Z"
},
{
"device": "102",
"online": false,
"on_call": false,
"callback_ready": false,
"destination": null,
"duration_seconds": null,
"last_call_end": null
}
]
}
destination/duration_seconds are only non-null while on_call is true. last_call_end is when the device last finished a call, or null if it never has. callback_ready is false when the device has no CallerID and no DID — a click-to-call on it would return 422, so grey the button out instead.
Look up a rate
GET/v1/rates/lookup
The per-minute rate for a destination number on your account's rate plan, matched to the most specific dial prefix on file (e.g. a city code beats its country code when both exist).
curl "https://api.mamontcall.com/v1/rates/lookup?destination=15551234567" \
-H "Authorization: Bearer mc_live_..."
# 200 OK
{
"destination": "15551234567",
"destination_name": "United States / Canada",
"prefix": "1",
"rate_per_minute": 0.012,
"connection_fee": 0
}
Errors
| Status | Meaning |
|---|---|
400 | destination query param missing |
404 | No rate plan on your account, or no prefix matches this destination |
Look up a call's cost
GET/v1/calls/{call_id}/cost
The actual billed cost of a call already placed through POST /v1/click-to-call — not an estimate. call_id is the value returned when you placed the call.
curl https://api.mamontcall.com/v1/calls/17834168392648973/cost \
-H "Authorization: Bearer mc_live_..."
# 200 OK — call has finished
{
"call_id": "17834168392648973",
"destination": "+15551234567",
"duration_seconds": 184,
"cost": 0.037,
"status": "answered"
}
# 202 Accepted — call hasn't resolved yet, poll again shortly
{"call_id": "17834168392648973", "status": "pending"}
status is one of answered, no_answer, busy, failed, canceled — same vocabulary as the webhook below. Returns 404 if call_id is unknown or doesn't belong to your account.
Webhooks
When a call finishes, we POST a call.completed event to the webhook URL you configure in the portal:
POST <your webhook url>
Content-Type: application/json
X-MamontCall-Signature: sha256=<hmac>
X-MamontCall-Timestamp: <unix ms>
{
"event": "call.completed",
"event_id": "evt_17834168392648973",
"call_id": "17834168392648973",
"client_reference": "lead-42",
"device": "101",
"destination": "+15551234567",
"status": "answered",
"duration_seconds": 42,
"initiated_at": "2026-07-07T09:33:59.000Z",
"ended_at": "2026-07-07T09:34:41.000Z",
"recording_available": true
}
status is one of answered, no_answer, busy, failed, canceled. We retry a failed delivery after 5s, 30s, then 120s. After 10 consecutive failed deliveries to your URL, delivery is suspended for the whole account — the portal's Developer page shows a warning with a one-click Re-enable delivery button once your endpoint is fixed. Saving a new webhook URL also resets the counter.
Verifying the signature
The webhook secret is shown in the portal's Developer page. Recompute the signature and compare:
const signed = timestamp + '.' + rawRequestBody
const expected = 'sha256=' + hmacSha256Hex(signed, webhookSecret)
// compare to the X-MamontCall-Signature header (constant-time compare)