CallMyCall
Quickstart

Base URL: https://call-my-call-backend.fly.dev

Quickstart request (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/start-call \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"+46700000000","task":"Confirm my booking","language":"en","voice_gender":"female","webhook":"https://example.com/cmc","metadata":{"client_request_id":"req_123"}}'
Quickstart success response
{
  "success": true,
  "sid": "CA1234567890abcdef"
}
share_policy example
"share_policy": {
  "name_voice": true,
  "phone_voice": false,
  "phone_dtmf": true,
  "pnr_voice": false,
  "pnr_dtmf": true
}

Idempotency guidance: send your own metadata.client_request_id and dedupe retries in your system.

Result flow: keep returned sid, handle webhook events, then fetch call details by ID if needed.

Endpoints
Core endpoints
POST /v1/start-call

Start an outbound AI call.

Field / ParamTypeRequiredDescription
phone_numberstringyesWho to call. Must be E.164 format (for example +46700000000).
taskstringyesWhat the AI should do/say on this call (your main instruction).
userPhonestringconditionalPhone number of your human operator/user (E.164) who will be added to the call once the call has connected. Used with userOnCall where AI and user are on the call flow at the same time.
additionalPromptstringnoExtra instructions appended to task. Default: empty string.
languagestringnoLanguage code (e.g. sv/en/de) for the language the AI will speak. Default: sv (normalized aliases supported).
tts_providerstringnoWhich TTS engine to use: auto | openai | elevenlabs | azure. If omitted, auto is used (Swedish -> ElevenLabs, English -> OpenAI).
voice_genderstringnoVoice gender selector for defaults. Allowed: female | male (alias: voiceGender). Defaults to male when omitted. Used to auto-select default OpenAI + ElevenLabs voices when explicit voice IDs are not provided.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/start-call \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"+46700000000","task":"Confirm booking","language":"en","voice_gender":"female","webhook":"https://example.com/cmc"}'
Success response
{
  "success": true,
  "sid": "CA1234567890abcdef"
}
Error response
{
  "error": "Insufficient credits",
  "credits_balance": 3,
  "minimum_required": 5
}
GET /v1/calls/:callId

Fetch call details and recent transcripts by call id/sid.

Field / ParamTypeRequiredDescription
callIdstringyesCall SID from start-call response.
Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "call": {
    "call_id": "CA1234567890abcdef",
    "status": "completed",
    "to": "+46700000000",
    "created_at": "2026-02-14T10:00:00.000Z"
  },
  "transcripts": [
    { "role": "assistant", "text": "Hello.", "seq": 1 }
  ]
}
GET /v1/calls/:callId/transcripts/stream

Subscribe to realtime transcript updates using Server-Sent Events.

Field / ParamTypeRequiredDescription
callIdstringyesCall SID from start-call response.
Request example (cURL)
curl -N https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/transcripts/stream
Example stream event payload
event: added
data: {"role":"assistant","text":"Hello.","seq":1}

event: ping
data: {"ts":1739511142}
GET /v1/calls/:callSid/recording

Get a signed recording URL for completed calls (if recording enabled).

Field / ParamTypeRequiredDescription
formatstringnoAudio format for signed URL. Allowed: mp3 or wav. Default: mp3.
Request example (cURL)
curl -X GET "https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/recording?format=mp3" \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "recording_url": "https://call-my-call-backend.fly.dev/v1/recordings/RE123.mp3?token=...",
  "expires_at": "2026-02-14T12:00:00.000Z"
}
Error response
{
  "error": "Recording not found for this call"
}
POST /v1/verify-caller-id

Start caller ID verification for custom from_number usage.

Field / ParamTypeRequiredDescription
phone_numberstringyesE.164 number to verify.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/verify-caller-id \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"+46123456789"}'
GET /v1/verification-status/:id

Check verification state (pending, verified, failed).

Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/v1/verification-status/CA_VERIFICATION_ID \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /v1/verified-caller-ids

List verified caller IDs for your API key/account.

Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/v1/verified-caller-ids \
  -H "Authorization: Bearer YOUR_API_KEY"
DELETE /v1/verified-caller-ids/:phone_number

Remove a verified caller ID owned by your API key.

Request example (cURL)
curl -X DELETE https://call-my-call-backend.fly.dev/v1/verified-caller-ids/+46123456789 \
  -H "Authorization: Bearer YOUR_API_KEY"
POST /v1/webhook/test

Send a synthetic webhook payload to your endpoint.

Field / ParamTypeRequiredDescription
webhook_urlstringyesHTTPS URL to receive test event.
eventstringnoDefaults to call_completed.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/webhook/test \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url":"https://example.com/cmc","event":"call_completed"}'
GET /auth/google/calendar

Start Google Calendar OAuth authorization flow.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key. You may also pass api_key as query param, but header is recommended.
formatquery stringnoSet format=json to receive auth_url in JSON instead of HTTP redirect.
Request example (cURL)
curl -X GET "https://call-my-call-backend.fly.dev/auth/google/calendar?format=json" \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "success": true,
  "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "state": "a1b2c3..."
}
Error response
{
  "error": "Failed to initiate calendar authorization",
  "details": "API key required for calendar authorization"
}
GET /auth/google/callback

OAuth callback consumed after Google consent; usually opened by browser redirect.

Field / ParamTypeRequiredDescription
codequery stringyesOAuth authorization code from Google.
statequery stringyesState value from /auth/google/calendar to prevent CSRF.
errorquery stringnoIf user denied consent, Google returns error instead of code.
Request example (cURL)
curl -X GET "https://call-my-call-backend.fly.dev/auth/google/callback?code=GOOGLE_CODE&state=OAUTH_STATE"
Success response
<!DOCTYPE html>
<html>...Calendar Authorization Successful...</html>
Error response
{
  "error": "Invalid or expired authorization request"
}
GET /calendar/status

Check whether this API key has active Google Calendar authorization.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key.
Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/calendar/status \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "authorized": true,
  "scopes": ["https://www.googleapis.com/auth/calendar"],
  "expires_at": "2026-02-16T20:00:00.000Z"
}
Error response
{
  "error": "Failed to check calendar authorization status",
  "details": "..."
}
POST /auth/google/revoke

Revoke Google Calendar authorization for this API key.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/auth/google/revoke \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "success": true,
  "message": "Calendar authorization revoked successfully"
}
Error response
{
  "error": "Failed to revoke calendar authorization",
  "details": "..."
}
GET /v1/recordings/:sid.:ext

Stream recording bytes via signed short-lived token URL.

Field / ParamTypeRequiredDescription
sidstringyesRecording SID.
extstringyesmp3 or wav.
tokenstringyesSigned token query parameter.
Request example (cURL)
curl -L "https://call-my-call-backend.fly.dev/v1/recordings/RE123.mp3?token=SIGNED_TOKEN"
POST /v1/elevenlabs/voices

Proxy endpoint for ElevenLabs voice cloning via multipart upload.

Field / ParamTypeRequiredDescription
namestringyesVoice name label.
filesfile[]yesOne or more audio sample files.
remove_background_noisebooleannoNoise removal hint for cloning.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/elevenlabs/voices \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "name=My Voice" \
  -F "files=@sample1.wav" \
  -F "files=@sample2.wav"
Ongoing call endpoints
POST /v1/end-call

End an active call.

Field / ParamTypeRequiredDescription
callSidstringyesCall SID returned by start-call (the call you want to end).
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/end-call \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"callSid":"CA1234567890abcdef"}'
Success response
{
  "ok": true,
  "alreadyClosed": false,
  "transcript": []
}
Error response
{
  "error": "Missing callSid"
}
POST /v1/calls/:callSid/transfer

Transfer an active call to another destination.

Field / ParamTypeRequiredDescription
destinationstringyesWhere to transfer the active call (E.164 phone number).
warmbooleannoTransfer mode. true = warm transfer (default), false = cold transfer.
reasonstringnoOptional note for audit/logging (not spoken to caller).
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/transfer \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"destination":"+46123456789","warm":true,"reason":"human_requested"}'
Success response
{
  "success": true,
  "transferType": "warm",
  "callSid": "CA1234567890abcdef"
}
PATCH /v1/calls/:callSid

Update active call parameters while the call is running.

Field / ParamTypeRequiredDescription
taskstringnoReplace current AI task for this active call.
transfer_numberstringnoUpdate transfer destination for this active call (E.164).
additional_promptstringnoAppend extra instructions to current prompt context.
max_durationnumbernoUpdate maximum connected duration (seconds).
Request example (cURL)
curl -X PATCH https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"task":"Updated task","transfer_number":"+46123456789"}'
User-on-call endpoints
POST /v1/calls/:callSid/activate

Activate AI takeover for user-on-call sessions.

Field / ParamTypeRequiredDescription
taskstringnoNew instruction for AI at takeover time. If omitted, existing task is used.
drop_userbooleannoWhether to disconnect the human user when AI takes over. Default: true.
additional_promptstringnoExtra instruction appended during activation.
transfer_numberstringnoOverrides/sets the handoff destination used by transfer logic during AI phase.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/activate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"task":"Take over now","drop_user":true}'
Success response
{
  "success": true,
  "ai_activated": true,
  "user_dropped": true,
  "message": "Call redirected to AI bidirectional stream"
}
Error response
{
  "error": "Call not found or not a userOnCall session"
}
GET /v1/calls/:callSid/conference-status

Get user-on-call conference state and participants.

Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/conference-status \
  -H "Authorization: Bearer YOUR_API_KEY"
POST /v1/calls/:callSid/drop-user

Disconnect the user leg from a user-on-call session.

Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/v1/calls/CA1234567890abcdef/drop-user \
  -H "Authorization: Bearer YOUR_API_KEY"
Calendar auth endpoints
Calendar auth flow

For calls with enable_calendar=true, authorize once per API key: start OAuth, approve consent, verify status, and revoke if needed.

GET /auth/google/calendar

Start Google Calendar OAuth authorization flow.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key. You may also pass api_key as query param, but header is recommended.
formatquery stringnoSet format=json to receive auth_url in JSON instead of HTTP redirect.
Request example (cURL)
curl -X GET "https://call-my-call-backend.fly.dev/auth/google/calendar?format=json" \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "success": true,
  "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "state": "a1b2c3..."
}
Error response
{
  "error": "Failed to initiate calendar authorization",
  "details": "API key required for calendar authorization"
}
GET /auth/google/callback

OAuth callback consumed after Google consent; usually opened by browser redirect.

Field / ParamTypeRequiredDescription
codequery stringyesOAuth authorization code from Google.
statequery stringyesState value from /auth/google/calendar to prevent CSRF.
errorquery stringnoIf user denied consent, Google returns error instead of code.
Request example (cURL)
curl -X GET "https://call-my-call-backend.fly.dev/auth/google/callback?code=GOOGLE_CODE&state=OAUTH_STATE"
Success response
<!DOCTYPE html>
<html>...Calendar Authorization Successful...</html>
Error response
{
  "error": "Invalid or expired authorization request"
}
GET /calendar/status

Check whether this API key has active Google Calendar authorization.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key.
Request example (cURL)
curl -X GET https://call-my-call-backend.fly.dev/calendar/status \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "authorized": true,
  "scopes": ["https://www.googleapis.com/auth/calendar"],
  "expires_at": "2026-02-16T20:00:00.000Z"
}
Error response
{
  "error": "Failed to check calendar authorization status",
  "details": "..."
}
POST /auth/google/revoke

Revoke Google Calendar authorization for this API key.

Field / ParamTypeRequiredDescription
AuthorizationheaderyesBearer API key.
Request example (cURL)
curl -X POST https://call-my-call-backend.fly.dev/auth/google/revoke \
  -H "Authorization: Bearer YOUR_API_KEY"
Success response
{
  "success": true,
  "message": "Calendar authorization revoked successfully"
}
Error response
{
  "error": "Failed to revoke calendar authorization",
  "details": "..."
}
User-on-call explained

Use userOnCall: true when the AI should wait through IVR/queue flow until a real human answers, while your operator can stay on the call and trigger AI takeover via /activate at the right moment.

PhaseWho hears what
Before activateUser and target are connected. AI can stay silent/listen.
Activate calledBackend redirects the target leg to AI realtime stream. If drop_user=true, user leg is disconnected.
After activateAI handles the live call (including queue/IVR progression). If drop_user=true and transfer_number is set, AI can reconnect/transfer the call to that number when transfer logic is triggered.
Typical API sequence:
1) POST /v1/start-call { userOnCall: true, userPhone, ... }
2) Wait until call is connected
3) POST /v1/calls/:callSid/activate { drop_user?: true|false, task?: string }
4) Optional: GET /v1/calls/:callSid/conference-status
5) Optional: POST /v1/calls/:callSid/drop-user
Common failures: call not found/not user-on-call session (404), already active AI (400), Twilio redirect/connect issues (500).
User-on-call state model
StateBehaviorNext
initiatedTarget + user legs are dialed.connected or failed
connectedUser and target talk while AI can listen silently.ai_takeover or completed
ai_takeover/activate redirects call to AI realtime stream.active
activeAI handles queue/IVR + conversation flow; it may transfer to transfer_number based on task/logic.transferred or completed
completedCall ends and completion webhook fires.-
Webhooks

Set webhook and optional webhook_events in the start-call payload.

EventWhenNotes
call_startedRealtime stream startsBest-effort signal
transcript_updatedNew transcript segmentsCan fire multiple times
price_updatedPost-call price enrichmentMay arrive after completion
call_completedCall closesDefault if events list omitted
Webhook payload example
{
  "event": "call_completed",
  "call_id": "CA1234567890abcdef",
  "sid": "CA1234567890abcdef",
  "timestamp": 1739511142,
  "data": {
    "status": "completed",
    "to": "+46700000000",
    "summary": { "goal_completed": true },
    "transcripts": [
      {
        "role": "assistant",
        "content": "Hello.",
        "timestamp": "2026-02-14T10:00:00.000Z",
        "seq": 1
      }
    ]
  }
}
Delivery contractCurrent behavior
Success conditionAny HTTP 2xx response.
RetriesUp to 3 attempts total.
Retry policyRetry on network errors and 5xx. No retry on 4xx.
Backoff600ms then 1200ms between retries.
Request timeout10 seconds per attempt.
SignatureX-Callmycall-Signature: t=TIMESTAMP,v1=HMAC_SHA256 when signing secret is configured.
Errors

Some errors are global (can happen on many endpoints), while others are endpoint-specific.

HTTPScopeExampleCause
400Endpoint-specificMissing phone_numberValidation failed for that endpoint payload.
401GlobalAuthorization header with API key is requiredMissing/invalid API key or Firebase auth token.
402Global (billing-gated endpoints)Subscription inactive / Insufficient creditsBilling pre-check failed before call execution.
404Endpoint-specificCall not foundUnknown SID/resource id, or resource already closed.
429GlobalToo Many RequestsRate limit exceeded; apply client backoff and retry.
500GlobalFailed to ...Provider/internal error while handling the request.
Billing & credits

Provider usage cost is converted to credits with margin, then rounded up per call.

RuleBehavior
What countsConnected call time, Twilio media stream, transcription, realtime tokens, and TTS.
RoundingTotal call charge is rounded up to nearest whole credit.
Minimum chargeNo fixed minimum fee. Rounded totals can still become 1 credit.
Queue waitQueue/hold time counts once the call is connected.
Credit guardStart-call may reject when balance is below minimum.
ScenarioTypical credits
2-minute call with transcription + TTSAbout 4 credits
8-minute queue + 2-minute conversationAbout 10 credits
45-second short confirmation callAbout 2 credits