{"openapi":"3.1.0","info":{"title":"MamontCall Click-to-Call API","version":"1.1.0","description":"Key-authenticated REST API for triggering calls from your CRM (\"click-to-call\"), checking outcomes, and receiving signed webhooks. Human-readable docs: https://api.mamontcall.com/"},"servers":[{"url":"https://api.mamontcall.com"}],"security":[{"bearerKey":[]}],"components":{"securitySchemes":{"bearerKey":{"type":"http","scheme":"bearer","description":"API key from the portal Developer page (mc_live_...)"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"CallSummary":{"type":"object","properties":{"call_id":{"type":"string"},"destination":{"type":"string"},"initiated_at":{"type":"string","format":"date-time"}},"required":["call_id","destination","initiated_at"]},"CallStatus":{"type":"object","properties":{"call_id":{"type":"string"},"destination":{"type":"string"},"initiated_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","answered","no_answer","busy","failed","canceled"]},"duration_seconds":{"type":"number","description":"Only present once resolved"},"cost":{"type":"number","description":"Only present once resolved"}},"required":["call_id","destination","initiated_at","status"]},"AgentStatus":{"type":"object","properties":{"device":{"type":"string"},"online":{"type":"boolean"},"on_call":{"type":"boolean"},"callback_ready":{"type":"boolean","description":"False when the device has no CallerID and no DID — click-to-call on it returns 422"},"destination":{"type":["string","null"]},"duration_seconds":{"type":["number","null"]},"last_call_end":{"type":["string","null"],"format":"date-time"}},"required":["device","online","on_call","callback_ready"]}}},"paths":{"/v1/click-to-call":{"post":{"summary":"Place a click-to-call","description":"Rings `device` first (via its CallerID/DID), then bridges to `destination`. Throttles: one call per device per 3 seconds, 60 requests per key per minute. A failed initiation does not consume the device throttle.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":128},"description":"Unique id per intended call (10-minute window). A retry with the same key replays the original call_id instead of dialing again; reuse with different parameters returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device":{"type":"string","description":"The device's SIP username/extension as shown on the portal Lines page"},"destination":{"type":"string","description":"Number to bridge to once the device answers"},"client_reference":{"type":"string","maxLength":128,"description":"Echoed back in the webhook"}},"required":["device","destination"]}}}},"responses":{"202":{"description":"Accepted (also used for idempotent replays, with `replayed: true`)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"call_id":{"type":"string"},"replayed":{"type":"boolean"}},"required":["ok"]}}}},"400":{"description":"device or destination missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Device not found on your account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key reused with different parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Device has no CallerID and no DID to ring back on","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Device throttle (3s) or per-key rate limit (60/min) — see Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The call could not be initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/calls":{"get":{"summary":"List placed calls (reconciliation)","parameters":[{"name":"since","in":"query","schema":{"type":"string"},"description":"ISO 8601 or epoch milliseconds"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Newest first","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"calls":{"type":"array","items":{"$ref":"#/components/schemas/CallSummary"}}},"required":["total","calls"]}}}},"400":{"description":"Invalid since","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/calls/{call_id}":{"get":{"summary":"Poll a call’s status","parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"pending until the call record lands, then the final status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallStatus"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown call_id (or not yours)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Status temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/calls/{call_id}/recording":{"get":{"summary":"Download the call recording","parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The recording","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key"},"404":{"description":"No recording (yet), or unknown call_id"},"502":{"description":"Recording temporarily unavailable"}}}},"/v1/calls/{call_id}/cost":{"get":{"summary":"Billed cost of a placed call","parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Resolved cost","content":{"application/json":{"schema":{"type":"object","properties":{"call_id":{"type":"string"},"destination":{"type":"string"},"duration_seconds":{"type":"number"},"cost":{"type":"number"},"status":{"type":"string","enum":["answered","no_answer","busy","failed","canceled"]}}}}}},"202":{"description":"Still pending"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown call_id"}}}},"/v1/agents/status":{"get":{"summary":"Agent/device presence","parameters":[{"name":"device","in":"query","schema":{"type":"string"},"description":"Comma-separated device filter"}],"responses":{"200":{"description":"One entry per device","content":{"application/json":{"schema":{"type":"object","properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/AgentStatus"}}},"required":["agents"]}}}},"401":{"description":"Missing or invalid API key"}}}},"/v1/rates/lookup":{"get":{"summary":"Per-minute rate for a destination","parameters":[{"name":"destination","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Longest-prefix match from your rate plan","content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string"},"destination":{"type":"string"},"rate":{"type":"number"},"connection_fee":{"type":"number"}}}}}},"400":{"description":"destination missing"},"401":{"description":"Missing or invalid API key"},"404":{"description":"No rate plan or no matching prefix"}}}}},"webhooks":{"call.completed":{"post":{"summary":"Delivered to your configured webhook URL when a call finishes","description":"HMAC-SHA256 signed (X-Mamontcall-Signature over `timestamp + \".\" + body`). Retries after 5s/30s/120s. After 10 consecutive failed deliveries to your URL, delivery is suspended account-wide until re-enabled on the portal Developer page (a warning banner is shown there).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"call.completed"},"call_id":{"type":"string"},"device":{"type":"string"},"destination":{"type":"string"},"client_reference":{"type":["string","null"]},"status":{"type":"string","enum":["answered","no_answer","busy","failed","canceled"]},"duration_seconds":{"type":"number"},"ended_at":{"type":"string","format":"date-time"},"recording_available":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Any 2xx acknowledges delivery"}}}}}}