Examples
Send WhatsApp messages and OTP codes with curl
Every Oxtro endpoint as a curl command you can paste into a terminal.
You need an API key and the ID of a connected number. The quickstart covers both.
export OXTRO_API_KEY="wa_live_..."Send a message
The API answers 202 with status: "queued". The Idempotency-Key header makes a retry safe. Full reference: Messages API.
curl https://api.getoxtro.com/v1/messages \
-H "Authorization: Bearer $OXTRO_API_KEY" \
-H "Idempotency-Key: order-4821-confirmation" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "conn_123",
"to": "+213555123456",
"text": "Your order ORD-4821 has been confirmed."
}'{
"id": "msg_123",
"status": "queued",
"queued_at": "2026-10-10T09:41:07.000Z"
}Send a one-time code
Oxtro generates the code and sends it on WhatsApp. You only keep the request_id. Full reference: OTP API.
curl https://api.getoxtro.com/v1/otp/send \
-H "Authorization: Bearer $OXTRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "conn_123",
"to": "+213555123456",
"code_length": 6,
"expires_in_minutes": 5
}'{
"request_id": "otp_123",
"expires_in": 300,
"status": "sent"
}Verify the code
A correct code returns 200. A wrong, expired or locked code returns 400 with the code OTP_INVALID, OTP_EXPIRED or OTP_MAX_ATTEMPTS.
curl https://api.getoxtro.com/v1/otp/verify \
-H "Authorization: Bearer $OXTRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_id": "otp_123",
"code": "492821"
}'{
"verified": true,
"request_id": "otp_123",
"phone_number": "+213555123456",
"verified_at": "2026-10-10T09:42:31.000Z"
}Register a webhook
Needs a key with the webhooks:manage scope. The response includes the signing secret once. Full reference: Webhooks.
curl https://api.getoxtro.com/v1/webhooks \
-H "Authorization: Bearer $OXTRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/oxtro",
"events": ["message.received", "message.failed"]
}'{
"id": "whk_123",
"url": "https://example.com/webhooks/oxtro",
"events": ["message.received", "message.failed"],
"is_active": true,
"created_at": "2026-10-10T09:00:00.000Z",
"secret": "whsec_..."
}