Request Log
An audit trail of every authenticated API call made with your keys, newest first. The row is written the moment your key is accepted — before anything that can fail: before the rate limit check, before the body is parsed, before we ever talk to a provider. That means it can answer "what happened to my request?" even for calls that never reached a provider at all.
# Last 20 calls, newest first
curl -X GET "https://api.sendcomms.com/api/v1/requests?limit=20" \
-H "Authorization: Bearer sc_live_your_api_key_here"
# Only the calls that failed at the provider
curl -X GET "https://api.sendcomms.com/api/v1/requests?outcome=provider_error&limit=50" \
-H "Authorization: Bearer sc_live_your_api_key_here"
# Page through everything you sent to one endpoint
curl -X GET "https://api.sendcomms.com/api/v1/requests?endpoint=/api/v1/sms/send&limit=100&offset=100" \
-H "Authorization: Bearer sc_live_your_api_key_here"Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | Optional | Rows to return. Default 50, maximum 200. Values outside 1–200 are clamped, not rejected. |
| offset | integer | Optional | Rows to skip. Default 0. Combine with limit and total to page. |
| outcome | string | Optional | Exact-match filter on one of the outcome values below. |
| endpoint | string | Optional | Exact-match filter on the path, e.g. /api/v1/sms/send. No prefix or wildcard matching. |
Rows are always ordered by started_at descending, and are always scoped to the account that owns the API key — you never see another customer's calls.
Response Codes
Response
Success Response
requests holds the page of rows, and total is the number of rows matching your filters — not the number returned.
{
"success": true,
"data": {
"requests": [
{
"id": "6f2a1c74-1a0e-4b1f-9b6d-0a2f5e7c9d31",
"endpoint": "/api/v1/sms/send",
"method": "POST",
"service": "sms",
"sandbox": false,
"outcome": "provider_error",
"status_code": 503,
"error_code": "SMS_SEND_FAILED",
"error_message": "Failed to send SMS. Please try again in a few minutes.",
"transaction_id": "sms_mjhw8xkw_6f97ab63ff91",
"request_summary": {
"to": "+233540800994",
"from": "SendComms",
"reference": "order-12345",
"message_length": 24
},
"duration_ms": 1843,
"started_at": "2026-08-22T09:14:02.118Z",
"finished_at": "2026-08-22T09:14:03.961Z"
},
{
"id": "b91d0f30-7c44-4f0e-8a5a-1c3d9f2b6e70",
"endpoint": "/api/v1/sms/send",
"method": "POST",
"service": "sms",
"sandbox": false,
"outcome": "rate_limited",
"status_code": 429,
"error_code": "RATE_LIMIT_EXCEEDED",
"error_message": null,
"transaction_id": null,
"request_summary": {
"to": "+233540800994",
"from": null,
"reference": null,
"message_length": 18
},
"duration_ms": 12,
"started_at": "2026-08-22T09:13:58.402Z",
"finished_at": "2026-08-22T09:13:58.414Z"
},
{
"id": "0c5b8e12-30a7-49d5-b2c1-77e4a1f0b8aa",
"endpoint": "/api/v1/email/send",
"method": "POST",
"service": "email",
"sandbox": true,
"outcome": "success",
"status_code": 200,
"error_code": null,
"error_message": null,
"transaction_id": "email_test_1935f2c0a11_9f3b21c4",
"request_summary": {
"to": ["customer@example.com"],
"subject_length": 27,
"recipients": 1
},
"duration_ms": 96,
"started_at": "2026-08-22T09:11:44.007Z",
"finished_at": "2026-08-22T09:11:44.103Z"
}
],
"total": 1487,
"limit": 20,
"offset": 0
}
}Request Fields
| Field | Type | Description |
|---|---|---|
| id | uuid | Identifier for this attempt. Quote it when you contact support. |
| endpoint | string | Public path that was called, e.g. /api/v1/sms/send |
| method | string | HTTP method |
| service | string | null | sms, email, data, airtime, usage or webhooks |
| sandbox | boolean | True when the call used an sc_test_ key |
| outcome | string | What happened. See the table below. |
| status_code | integer | null | HTTP status we returned. Null while the row is still started. |
| error_code | string | null | Our error code, e.g. INVALID_PHONE_NUMBER |
| error_message | string | null | Short sanitised message, truncated to 500 characters |
| transaction_id | string | null | Set once the call got far enough to create a transaction |
| request_summary | object | Redacted summary of what you sent. Never message bodies — see below. |
| duration_ms | integer | null | Wall-clock time we spent on the request |
| started_at | timestamp | When your key was accepted. Rows are sorted on this. |
| finished_at | timestamp | null | When the response was produced. Null for started rows. |
Outcome Values
| Outcome | What it means |
|---|---|
| success | The response was a 2xx. The call did what you asked. |
| client_error | A 4xx we attributed to the request itself — validation failures, missing fields, unknown transaction, insufficient balance. Check error_code. |
| rate_limited | A 429. You exceeded a per-minute, per-day or per-month limit for that service. Nothing was sent and nothing was charged. |
| provider_error | A 502/503, or a 5xx carrying a provider error code (SMS_SEND_FAILED, EMAIL_SEND_FAILED, DATA_PURCHASE_FAILED, PROVIDER_ERROR, SERVICE_UNAVAILABLE). We reached the downstream network or carrier and it refused or timed out. |
| internal_error | A 5xx on our side that was not a provider failure. Safe to retry; if it repeats, quote the id when you contact support. |
| unauthorized | A 401. The key was rejected mid-request, or the account attached to it was suspended. |
| started | The row was opened but never finalised — the request crashed hard or the connection dropped before a response was produced. A row that stays started is the strongest signal to send us. |
What request_summary Contains
request_summary is deliberately redacted. It records only what is needed to identify a call — the destination, your reference, and sizes such as message length or recipient count. It never contains message bodies, email HTML, subjects, attachments or credentials. Routes write it before validation runs, so a rejected request is still traceable: you can see who you tried to reach and why it was refused.
"request_summary": {
"to": "+233540800994",
"from": "SendComms",
"reference": "order-12345",
"message_length": 24
}The exact keys vary by endpoint. The client IP and user agent of each call are recorded too, but are not returned by this endpoint.
outcome=rate_limited to see exactly which calls were shed and when. See Rate Limits for the per-plan ceilings.