API Documentation
Trigger AI phone calls from your code, automation platform, or CRM. Receive a webhook when each call completes with transcript, summary, and cost.
On this page
Authentication
All API requests require an API key. Create one in your profile settings under Integrations.
Pass your key in the X-API-Key header:
curl https://api.mio.gg/api/v1/me \
-H "X-API-Key: sk_live_your_key_here"
API keys carry your full account permissions. Keep them secret — don't commit them to version control or expose them in client-side code.
Profile
Returns your account info. Useful for verifying your API key works.
Returns your user profile. No request body needed.
Response
{
"id": "a1b2c3d4-...",
"name": "Jane",
"phoneNumber": "+15551234567",
"balance": 450
}
The balance field is in cents. 450 = $4.50.
Make a call
Initiate an AI phone call. Mio calls the number, follows your instructions, and delivers results via webhook when done.
Creates and initiates a phone call. Returns 201 with the call object.
Request body
| Parameter | Description |
|---|---|
| phoneNumber required | Phone number in E.164 format (e.g. +15551234567) |
| instructions required | What the AI should accomplish on the call. Max 5,000 characters. |
| firstMessage optional | The first thing the AI says when the call connects. Max 1,000 characters. |
| callAt optional | ISO 8601 UTC timestamp to schedule the call (e.g. 2026-03-21T14:00:00Z). Omit for immediate. |
| name optional | Name of the person or business being called. |
Example
curl https://api.mio.gg/api/v1/calls \
-X POST \
-H "X-API-Key: sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+15551234567",
"instructions": "Call Joe'\''s Pizza and order a large pepperoni for pickup at 7pm.",
"firstMessage": "Hi, I'\''d like to place an order for pickup please."
}'
Response 201
{
"id": "d4e5f6a7-...",
"status": "initiated",
"direction": "outbound",
"toNumber": "+15551234567",
"fromNumber": "+15559876543",
"instructions": "Call Joe's Pizza and order...",
"createdAt": "2026-03-20T18:30:00.000Z"
}
For scheduled calls, status will be "scheduled" and the callAt field will be set.
Webhooks
Webhooks notify your server when a call completes. You get the transcript, summary, cost, and duration — everything you need to process the result.
Managing webhooks
List all your webhooks.
Create a webhook. Requires HTTPS URL. A signing secret is generated and returned once.
| Parameter | Description |
|---|---|
| url required | HTTPS endpoint that will receive POST requests. |
| events optional | Array of event types. Default: ["call.completed"] |
Update a webhook's URL, events, or active status.
Delete a webhook.
Send a test payload to verify your endpoint is receiving events correctly.
Webhook payload
When a call completes, Mio sends a POST request to each active webhook:
{
"event": "call.completed",
"timestamp": "1711000000",
"call": {
"id": "d4e5f6a7-...",
"direction": "outbound",
"status": "completed",
"name": "Joe's Pizza",
"toNumber": "+15551234567",
"fromNumber": "+15559876543",
"instructions": "Order a large pepperoni...",
"summary": "Ordered a large pepperoni pizza for pickup at 7pm. Total $18.50.",
"transcript": [
{ "role": "agent", "text": "Hi, I'd like to place an order..." },
{ "role": "human", "text": "Sure, what can I get for you?" }
],
"cost": 42,
"duration": 45,
"attempt": 1,
"startedAt": "2026-03-20T18:30:05.000Z",
"endedAt": "2026-03-20T18:30:50.000Z",
"createdAt": "2026-03-20T18:30:00.000Z"
}
}
cost is in cents, duration is in seconds.
Webhook security
Each webhook gets a signing secret (prefixed whsec_) returned when you create it.
Mio signs every delivery so you can verify it came from us.
Headers
| Header | Description |
|---|---|
| X-Mio-Signature | HMAC-SHA256 signature of the payload. |
| X-Mio-Timestamp | Unix timestamp (seconds) of when the event was sent. |
| X-Mio-Event | Event type, e.g. call.completed |
| X-Mio-Delivery | Unique delivery ID (UUID). |
Verifying signatures
The signature is computed as HMAC-SHA256(secret, "{timestamp}.{body}")
where body is the raw JSON request body.
import crypto from 'crypto';
function verifyWebhook(secret, timestamp, body, signature) {
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Always use constant-time comparison to prevent timing attacks. Reject requests where the timestamp is more than 5 minutes old to prevent replay attacks.
Failure handling
If your endpoint returns a non-2xx status or times out (10s), Mio retries with exponential backoff up to 10 times. After 10 consecutive failures, the webhook is automatically disabled. You can re-enable it via the API.
Errors
The API uses standard HTTP status codes. Error responses include a JSON body with an error field.
| Status | Meaning |
|---|---|
| 400 | Invalid request body or parameters. |
| 401 | Missing or invalid API key. |
| 402 | Insufficient balance. Add funds to continue. |
| 409 | Conflict — e.g. a call is already active on this chat. |
| 500 | Server error. Try again or contact support. |
// Example error response
{
"error": "Insufficient balance. Please top up to make calls."
}
Ready to build?
Create your API key and make your first call in under a minute.
Get your API keyFree $5 credit on signup. No card required.