Skip to main content

Calls API reference

Base URL: https://pilotstatus.com.br/v1 Headers: Content-Type: application/json, x-api-key: <your_api_key> (or x-api-key-id).
Calling works on two provider kinds: META (Meta Cloud API numbers) and unofficial (Pilot Status web) QR-connected numbers. Any other provider returns 400 FEATURE_NOT_SUPPORTED. All endpoints require a number-scoped key. See the overview.
SDP handling differs by provider. META is WebRTC: you supply an SDP offer on POST /v1/calls and an SDP answer on accept — media flows browser ↔ WhatsApp. The unofficial (Pilot Status web) provider takes no SDP (sdpOffer/sdpAnswer stay null); media is handled server-side and you drive audio with the unofficial-only /play and /realtime-session endpoints.

Endpoints

{callId} accepts either the Pilot Status call id (call_...) or the provider call id (Meta wacid... on META).
Endpoints marked META only return 400 FEATURE_NOT_SUPPORTED on Unofficial numbers, and endpoints marked Unofficial only return 400 FEATURE_NOT_SUPPORTED on META numbers. Unofficial has no BIC permission model and no calling-settings surface. An Unofficial number that is not connected returns 409 WHATSAPP_INSTANCE_NOT_CONNECTED.

1. Enable calling on the number (META only)

Pilot Status tries to enable calling automatically when a Meta number connects. Read/adjust anytime:
  • PUT is partial: send only status, call_icon_visibility, callback_permission_status, call_hours, voicemail (the sip object is rejected).
  • A posted call_hours replaces the stored object entirely (Meta semantics).
  • Numbers with a messaging limit below 2,000/day cannot enable calling yet (Meta error 138015 → Pilot Status marks the number PENDING_TIER and retries as the tier climbs).
  • Enabling also requires the WABA to have the calls webhook field subscribed (or SIP configured); without it Meta returns 138018 and Pilot Status marks the number PENDING_WEBHOOK. Subscribe the calls field on the WABA (or set up SIP), then retry.
  • You can trigger enablement from the dashboard too — the Enable calling button under a number’s Meta details (Numbers page) reports back ENABLED, PENDING_TIER, or PENDING_WEBHOOK.
  • SIP credentials are never requested nor returned.
Unofficial numbers have no calling-settings surface — this endpoint returns 400 FEATURE_NOT_SUPPORTED. Calling is available whenever the Unofficial instance is connected.

2. Call permission (required before a BIC) (META only)

Probe response:
The user’s answer arrives as the call.permission_updated webhook event (status: NO_PERMISSION | TEMPORARY | PERMANENT). Meta rate-limits permission requests (error 138009) and BIC volume (100 calls/24h per number — error 138012).
Unofficial has no BIC permission model — the permissions endpoints return 400 FEATURE_NOT_SUPPORTED. Place BIC calls directly.

3. Start a call (BIC)

  • META: sdp is the RFC 8866 offer produced by YOUR WebRTC client. The business-side SDP must use a=setup:active. Without permission, Meta returns 138006 → the endpoint surfaces code: "META_CALL_PERMISSION_REQUIRED".
  • Unofficial: omit sdp/sdpType — media is server-side. Drive audio afterwards with /play or /realtime-session.
  • bizOpaqueCallbackData (optional) is echoed back on the terminate webhook.

4. Answer an inbound call (UIC)

When a user calls your number you receive the call.ringing webhook. Then:
accept/pre-accept/reject/terminate respond { "success": true, "id": "call_...", "status": "..." }. On META, pre-accept is optional (early SDP answer to reduce clipping) — the call connects only on accept; on Unofficial accept takes no body and pre-accept is unavailable.

5. Play audio into a call (Unofficial only)

Play a pre-recorded audio file into an active Unofficial call. The backend downloads the file (behind an SSRF guard) and streams it server-side into the call. When the call is not active yet, the audio is queued and starts as soon as the user answers.
  • mediaUrl — public http(s) URL of an .mp3, .wav or .opus file.
  • hangupAfterPlay (optional) — end the call automatically when playback finishes. Perfect for notification flows: POST /v1/calls + play with hangupAfterPlay: true is a complete “call, speak, hang up” bot with no client-side timer.
Host the audio on fast storage (S3/CDN): the backend downloads the file before handing it to the media server, so playback can only start after that download completes. A slow file host adds seconds of silence at the start of the call.
Returns 400 FEATURE_NOT_SUPPORTED on META numbers (use the WebRTC media stream instead).

6. Realtime audio session (Unofficial only)

Open a full-duplex PCM16 audio WebSocket for an active Unofficial call — ideal for streaming a live agent or a realtime voice model.
The returned wsUrl lives on a dedicated media host — connect to it directly, not through the API base URL. The token is single-use with a short TTL (~2 minutes). The HTTP layer does not upgrade WebSocket connections, so the realtime socket is not proxied through /v1.
Returns 400 FEATURE_NOT_SUPPORTED on META numbers.

7. Call object (DTO)

  • status: INITIATED | RINGING | ACCEPTED | REJECTED | COMPLETED | FAILED | MISSED.
  • direction: INBOUND (UIC) | OUTBOUND (BIC).
  • SDPs (sdpOffer/sdpAnswer) appear only with ?includeSdp=1 on GET /v1/calls/{callId} and only on META — on Unofficial they are always null.
  • durationSeconds is set only when the call was answered.

Webhooks

call.ringing, call.connected, call.ended (carries duration in seconds when the call was answered), and call.missed fire for both META and Unofficial numbers. call.permission_updated is META only — Unofficial numbers have no call-permission model. (In the REST call object returned by GET /v1/calls, the equivalent field is durationSeconds.)

Billing

  • META: business-initiated calls (BIC) are billed by Meta on the WABA — per minute, in 6-second pulses, only while the call is answered. User-initiated calls (UIC) are free.
  • Unofficial: no Meta per-minute charge.
  • Pilot Status charges nothing for calling on either provider.

Common errors

  • 400 FEATURE_NOT_SUPPORTED — the key’s number does not support this endpoint (wrong provider, e.g. a Meta-only endpoint on Unofficial or vice-versa, or a provider that is neither META nor Unofficial).
  • 400 NUMBER_NOT_FOUND — the key is not bound to a number.
  • 400 — body validation, INVALID_LIMIT, INVALID_BEFORE, MISSING_TO.
  • 401 — missing/invalid x-api-key / x-api-key-id.
  • 403 — tenant-scoped key (calls endpoints are number-scoped).
  • 404 CALL_NOT_FOUND — the callId/wacid does not belong to the key’s number.
  • 409 WHATSAPP_INSTANCE_NOT_CONNECTED — the Unofficial number is not connected.
  • Meta calling errors are forwarded with a mapped code — e.g. META_CALL_PERMISSION_REQUIRED (138006), permission-request limit (138009), BIC limit 100 calls/24h (138012), calling not enabled (138000), messaging tier too low to enable (138015 → PENDING_TIER), calling prerequisites not met — subscribe the calls webhook field or configure SIP (138018 → PENDING_WEBHOOK), META_CALLING_PAYMENT_REQUIRED (131044 — the WABA has no payment method; business-initiated calls are billed by Meta, add a card under Payment settings in WhatsApp Manager).