Two things worth knowing
A 202 means the message is durably stored and queued. Only the status field claims WhatsApp delivered anything, and queued, submitted, sent, delivered and read stay distinct.
Send Idempotency-Key on every send. A replay returns the original response; a concurrent duplicate is told to retry rather than allowed to race.
This page is generated from the same OpenAPI document the API serves at /v1/openapi.json, and every request shape below is the schema the endpoint actually validates with.
Messages
Sending, delivery state and export.
/v1/messages
List messages
API key · messages:read
Newest first, cursor paginated. Offsets are not offered: they skip and duplicate.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
limit | query | integer | optional | 1 to 100; default 25 |
cursor | query | string | optional | length 0–200 |
connection | query | string | optional | length 1–40 |
status | query | scheduled | accepted | queued | submitting | submitted | sent | delivered | read | failed | canceled | optional | |
direction | query | inbound | outbound | optional |
Request
curl -X GET https://api.chatrail.dev/v1/messages \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | A page of messages and a next_cursor. |
/v1/messages/export
Export delivery metadata as CSV
API key · messages:read
Streamed row by row. Message bodies are not included — this is delivery metadata, not content.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | query | string | optional | length 1–40 |
status | query | string | optional | length 1–20 |
direction | query | inbound | outbound | optional | |
days | query | integer | optional | 1 to 365; default 30 |
Request
curl -X GET https://api.chatrail.dev/v1/messages/export \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | A CSV stream. |
/v1/messages/text
Send a message
API key · messages:write
Accepts a message for delivery and returns 202. 202 means accepted, never delivered — the message is durably stored and queued, and only the status field ever claims delivery. Send media or location for an attachment, send_at to defer it. Supply Idempotency-Key so a retry cannot send twice.
Body
| Field | Type | Notes | |
|---|---|---|---|
connection | string | required | length 1–40 |
to | one of several shapes | required | |
body | string | optional | length 0–4096 |
media | object | optional | |
location | object | optional | |
context | object | optional | |
metadata | object | optional | |
context_sensitivity | normal | sensitive | restricted | optional | |
send_at | string (date-time) | optional | date-time format |
timezone | string | optional | length 1–64 |
Request
curl -X POST https://api.chatrail.dev/v1/messages/text \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"connection": "main",
"to": "+15551234567",
"body": "Order CR-2048 has shipped.",
"context": {
"order_id": "CR-2048",
"status": "dispatched"
}
}'Responses
| Status | Meaning |
|---|---|
202 | Accepted and queued. |
400 | The body, recipient or attachment was rejected. |
402 | The plan does not include this. The message names what would allow it. |
409 | The connection is not ready, or an identical Idempotency-Key is in flight. |
422 | The Idempotency-Key was reused with a different body. |
429 | Quota or rate limit. |
/v1/messages/{id}
Get a message
API key · messages:read
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Message id. |
Request
curl -X GET https://api.chatrail.dev/v1/messages/:id \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The message and its delivery timeline. |
404 | No such message. |
/v1/messages/{id}/cancel
Cancel a message
API key · messages:write
Only while it has not reached the provider. Once submitted the message exists on somebody's phone and cancelling would be a lie.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Message id. |
Request
curl -X POST https://api.chatrail.dev/v1/messages/:id/cancel \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Cancelled. |
404 | No such message. |
409 | Already handed to the provider. |
/v1/messages/{id}/reschedule
Move a scheduled message
API key · messages:write
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Message id. |
Body
| Field | Type | Notes | |
|---|---|---|---|
send_at | string (date-time) | required | date-time format |
timezone | string | optional | length 1–64 |
Request
curl -X POST https://api.chatrail.dev/v1/messages/:id/reschedule \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"send_at": "2026-10-01T09:00:00Z",
"timezone": "Europe/London"
}'Responses
| Status | Meaning |
|---|---|
200 | Rescheduled. |
409 | No longer scheduled. |
/v1/numbers/check
Check whether a number is on WhatsApp
API key · messages:read
Answers checked: false when the engine cannot say. Treat that as "send anyway": refusing a message because a check failed turns a missing provider feature into a delivery failure.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
phone | query | string | required | length 5–40 |
connection | query | string | required | length 1–40 |
Request
curl -X GET https://api.chatrail.dev/v1/numbers/check \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The answer, or checked: false. |
404 | No such connection. |
Connections
WhatsApp numbers and their pairing lifecycle.
/v1/connections
List connections
API key · connections:read
Request
curl -X GET https://api.chatrail.dev/v1/connections \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Every live connection in the workspace. |
/v1/connections
Create a connection
API key · connections:write
Returns callback_token exactly once. It cannot be retrieved again; store it when you receive it.
Body
| Field | Type | Notes | |
|---|---|---|---|
slug | string | required | pattern ^[a-z0-9][a-z0-9-]{0,38}[a-z0-9]$ |
name | string | optional | length 1–80 |
Request
curl -X POST https://api.chatrail.dev/v1/connections \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "operations",
"name": "Operations line"
}'Responses
| Status | Meaning |
|---|---|
201 | Created, with the one-time callback token. |
402 | The plan has no room for another number. |
409 | That slug is taken. |
/v1/connections/{connection}
Get a connection
API key · connections:read
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X GET https://api.chatrail.dev/v1/connections/:connection \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The connection and its state. |
404 | No such connection. |
/v1/connections/{connection}
Delete a connection
API key · connections:write
Soft deletes it and queues removal of its data.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X DELETE https://api.chatrail.dev/v1/connections/:connection \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
204 | Deleted. |
404 | No such connection. |
/v1/connections/{connection}/pair
Begin pairing
API key · connections:write
Issues a short-lived, single-use QR grant. The QR itself is fetched with the grant id — it is a pairing credential, so anyone who scans it links *their* device to the number.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X POST https://api.chatrail.dev/v1/connections/:connection/pair \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | A grant id and its expiry. |
409 | The connection cannot be paired from its current state. |
503 | No transport is configured on this deployment. |
/v1/connections/{connection}/qr/{grantId}
Redeem a QR grant
API key · connections:write
Single use. A redeemed or expired grant is gone; ask for another.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
grantId | path | string | required | Grant id. |
Request
curl -X GET https://api.chatrail.dev/v1/connections/:connection/qr/:grantId \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The pairing payload. |
404 | Unknown, used or expired. |
/v1/connections/{connection}/resume
Resume a suspended connection
API key · connections:write
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X POST https://api.chatrail.dev/v1/connections/:connection/resume \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Resumed. |
409 | Not suspended. |
/v1/connections/{connection}/suspend
Suspend a connection
API key · connections:write
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X POST https://api.chatrail.dev/v1/connections/:connection/suspend \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Suspended. |
409 | Not in a suspendable state. |
Schedules
Recurring sends.
/v1/schedules
List schedules
API key · schedules:read
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
status | query | active | paused | completed | canceled | optional |
Request
curl -X GET https://api.chatrail.dev/v1/schedules \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Every schedule in the workspace. |
/v1/schedules
Create a recurring schedule
API key · schedules:write
Daily, weekly or monthly, resolved in the given IANA timezone. A schedule that fell behind fires once and drops the backlog rather than delivering days of stale messages.
Body
| Field | Type | Notes | |
|---|---|---|---|
name | string | required | length 1–80 |
timezone | string | required | length 1–64 |
recurrence | one of several shapes | required | |
message | object | required | |
starts_at | string (date-time) | optional | date-time format |
ends_at | string (date-time) | optional | date-time format |
max_occurrences | integer | optional | 1 to 10000 |
Request
curl -X POST https://api.chatrail.dev/v1/schedules \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Friday digest",
"timezone": "Europe/London",
"recurrence": {
"type": "weekly",
"hour": 9,
"minute": 0,
"days_of_week": [
5
]
},
"message": {
"connection": "main",
"to": "+15551234567",
"body": "Your weekly digest is ready."
}
}'Responses
| Status | Meaning |
|---|---|
201 | Created, with the resolved next_run_at. |
400 | Unknown timezone, or a recurrence that would never fire. |
402 | The plan does not include scheduling. |
/v1/schedules/{id}
Get a schedule
API key · schedules:read
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Schedule id. |
Request
curl -X GET https://api.chatrail.dev/v1/schedules/:id \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The schedule. |
404 | No such schedule. |
/v1/schedules/{id}/cancel
Cancel a schedule
API key · schedules:write
Permanent. A cancelled schedule cannot be restarted.
Request
curl -X POST https://api.chatrail.dev/v1/schedules/:id/cancel \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The updated schedule. |
409 | Not in a state that allows it. |
/v1/schedules/{id}/pause
Pause a schedule
API key · schedules:write
Keeps the schedule and stops it firing.
Request
curl -X POST https://api.chatrail.dev/v1/schedules/:id/pause \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The updated schedule. |
409 | Not in a state that allows it. |
/v1/schedules/{id}/resume
Resume a schedule
API key · schedules:write
The next run is computed from now. A schedule paused for a month does not fire the month it missed.
Request
curl -X POST https://api.chatrail.dev/v1/schedules/:id/resume \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The updated schedule. |
409 | Not in a state that allows it. |
Webhooks
Where inbound events and delivery updates are sent.
/v1/webhook-endpoints
List webhook endpoints
Dashboard session
Request
curl -X GET https://api.chatrail.dev/v1/webhook-endpointsResponses
| Status | Meaning |
|---|---|
200 | Endpoints, without their signing secrets. |
/v1/webhook-endpoints
Register a webhook endpoint
Dashboard session
Returns the signing secret exactly once. Every delivery is signed with HMAC-SHA256 over ${timestamp}.${rawBody}; verify it and reject stale timestamps. The URL is validated at registration and the connection pinned at delivery, so an endpoint pointing at a private address is refused.
Body
| Field | Type | Notes | |
|---|---|---|---|
url | string (uri) | required | length 0–2048 |
description | string | optional | length 0–200 |
events | array of string | required | |
connection | string | optional | length 1–40 |
Request
curl -X POST https://api.chatrail.dev/v1/webhook-endpoints \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/chatrail",
"events": [
"message.received",
"message.delivered",
"message.failed"
],
"description": "Order updates"
}'Responses
| Status | Meaning |
|---|---|
201 | Created, with the one-time signing secret. |
400 | The URL is not publicly reachable over https. |
402 | Scoping to one connection is not on this plan. |
/v1/webhook-endpoints/{id}
Delete a webhook endpoint
Dashboard session
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Endpoint id. |
Request
curl -X DELETE https://api.chatrail.dev/v1/webhook-endpoints/:idResponses
| Status | Meaning |
|---|---|
204 | Deleted. |
404 | No such endpoint. |
AI
Optional, per connection, off by default.
/v1/ai/credentials
List credentials
API key · ai:read
Fingerprints and metadata only; the key itself is never returned.
Request
curl -X GET https://api.chatrail.dev/v1/ai/credentials \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Credential metadata. |
/v1/ai/credentials
Store a model provider credential
API key · ai:write
Encrypted at rest and never returned. AI is off by default and enabled per connection.
Body
| Field | Type | Notes | |
|---|---|---|---|
provider | openai_compatible | anthropic | required | |
label | string | required | length 1–80 |
api_key | string | required | length 8–8192 |
base_url | string (uri) | optional |
Request
curl -X POST https://api.chatrail.dev/v1/ai/credentials \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "anthropic",
"label": "Production key",
"api_key": "sk-ant-replace-with-your-own-key"
}'Responses
| Status | Meaning |
|---|---|
201 | Stored. |
402 | AI is not on this plan. |
/v1/ai/credentials/{id}
Delete a credential
API key · ai:write
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Credential id. |
Request
curl -X DELETE https://api.chatrail.dev/v1/ai/credentials/:id \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
204 | Deleted. |
404 | No such credential. |
/v1/ai/policies/{connection}
Get the AI policy for a connection
API key · ai:read
Absent policy means AI is off for that connection, which is the default.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Request
curl -X GET https://api.chatrail.dev/v1/ai/policies/:connection \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The policy. |
404 | No policy is set. |
/v1/ai/policies/{connection}
Set the AI policy for a connection
API key · ai:write
Draft or auto mode, with token, rate and monthly cost ceilings. Absent policy means AI is off for that connection.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
connection | path | string | required | Connection slug. |
Body
| Field | Type | Notes | |
|---|---|---|---|
credential_id | string (uuid) | required | uuid format |
enabled | boolean | required | |
mode | draft | auto | required | |
model | string | required | length 1–120 |
system_instruction | string | required | length 1–4000 |
max_context_bytes | integer | optional | 256 to 32768; default 8192 |
max_output_tokens | integer | optional | 32 to 2000; default 300 |
monthly_cost_limit_micros | one of several shapes | optional | default null |
input_cost_micros_per_million | integer | optional | 0 to 9007199254740991; default 0 |
output_cost_micros_per_million | integer | optional | 0 to 9007199254740991; default 0 |
Request
curl -X PUT https://api.chatrail.dev/v1/ai/policies/:connection \
-H "Authorization: Bearer $CHATRAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"credential_id": "019bf4a1-0000-7000-8000-000000000000",
"enabled": true,
"mode": "draft",
"model": "claude-sonnet-4-5",
"system_instruction": "Answer only from the attached context. If the answer is not there, say so."
}'Responses
| Status | Meaning |
|---|---|
200 | The policy. |
402 | AI is not on this plan. |
/v1/ai/runs
List AI runs
API key · ai:read
Prompt hashes, usage, cost and outcome. Never prompt or completion text.
Request
curl -X GET https://api.chatrail.dev/v1/ai/runs \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | Recent runs. |
Team
Membership and invitations. Dashboard sessions only.
/v1/members
List members and pending invitations
Dashboard session
Request
curl -X GET https://api.chatrail.dev/v1/membersResponses
| Status | Meaning |
|---|---|
200 | Members, invitations, and the roles this caller may assign. |
/v1/members/accept
Accept an invitation
Dashboard session
Requires a signed-in session whose address matches the invited one. Possessing the token is not enough — a forwarded invitation email must not be a way into a workspace.
Body
| Field | Type | Notes | |
|---|---|---|---|
token | string | required | length 20–200 |
Request
curl -X POST https://api.chatrail.dev/v1/members/accept \
-H "Content-Type: application/json" \
-d '{
"token": "the token from the invitation link"
}'Responses
| Status | Meaning |
|---|---|
200 | Joined. |
401 | Sign in as the invited address first. |
403 | The invitation was sent to a different address. |
404 | The invitation is not valid. |
/v1/members/invitations
Invite somebody
Dashboard session
Emails a single-use link bound to that address. The token is never returned in the response. Nobody may invite to a role above their own.
Body
| Field | Type | Notes | |
|---|---|---|---|
email | string (email) | required | length 0–254; email format |
role | owner | admin | developer | viewer | billing | required |
Request
curl -X POST https://api.chatrail.dev/v1/members/invitations \
-H "Content-Type: application/json" \
-d '{
"email": "colleague@company.com",
"role": "viewer"
}'Responses
| Status | Meaning |
|---|---|
201 | Invited. |
402 | Member management is not on this plan. |
403 | You cannot assign that role. |
409 | Already a member. |
/v1/members/invitations/{id}
Revoke an invitation
Dashboard session
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Invitation id. |
Request
curl -X DELETE https://api.chatrail.dev/v1/members/invitations/:idResponses
| Status | Meaning |
|---|---|
204 | Revoked. |
404 | No such invitation. |
/v1/members/{id}
Change a member's role
Dashboard session
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | User id. |
Body
| Field | Type | Notes | |
|---|---|---|---|
role | owner | admin | developer | viewer | billing | required |
Request
curl -X PATCH https://api.chatrail.dev/v1/members/:id \
-H "Content-Type: application/json" \
-d '{
"role": "developer"
}'Responses
| Status | Meaning |
|---|---|
200 | The updated member. |
403 | You cannot assign or act on that role. |
409 | A workspace must keep an owner. |
/v1/members/{id}
Remove a member
Dashboard session
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | User id. |
Request
curl -X DELETE https://api.chatrail.dev/v1/members/:idResponses
| Status | Meaning |
|---|---|
204 | Removed. |
409 | A workspace must keep an owner. |
Workspace
Identity, credentials, plan and usage.
/v1/api-keys
List API keys
Dashboard session
Request
curl -X GET https://api.chatrail.dev/v1/api-keysResponses
| Status | Meaning |
|---|---|
200 | Key metadata and prefixes, never the keys. |
/v1/api-keys
Issue an API key
Dashboard session
Returns the key exactly once. It is stored only as a hash and cannot be recovered. A key may never hold more than the person issuing it.
Body
| Field | Type | Notes | |
|---|---|---|---|
name | string | required | length 1–80 |
scopes | array of messages:read | messages:write | connections:read | connections:write | webhooks:read | webhooks:write | schedules:read | schedules:write | ai:read | ai:write | mcp:read | mcp:write | required | |
environment | live | test | optional | default "live" |
Request
curl -X POST https://api.chatrail.dev/v1/api-keys \
-H "Content-Type: application/json" \
-d '{
"name": "Order service",
"scopes": [
"messages:write",
"messages:read"
],
"environment": "live"
}'Responses
| Status | Meaning |
|---|---|
201 | The key, once. |
403 | Your role cannot grant those scopes. |
/v1/api-keys/{id}/revoke
Revoke an API key
Dashboard session
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Key id. |
Request
curl -X POST https://api.chatrail.dev/v1/api-keys/:id/revokeResponses
| Status | Meaning |
|---|---|
200 | Revoked, immediately. |
404 | No such key. |
/v1/api-keys/{id}/rotate
Rotate an API key
Dashboard session
Issues a replacement and revokes the old one.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
id | path | string | required | Key id. |
Request
curl -X POST https://api.chatrail.dev/v1/api-keys/:id/rotateResponses
| Status | Meaning |
|---|---|
200 | The new key, once. |
404 | No such key. |
/v1/usage
Usage counts
Dashboard session
Counts only. A count of messages is not a message; no content is reachable here.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
days | query | integer | optional | 1 to 365 |
Request
curl -X GET https://api.chatrail.dev/v1/usageResponses
| Status | Meaning |
|---|---|
200 | Aggregated counts for the workspace. |
/v1/whoami
Confirm a credential
API key
Shows exactly what the presented credential can do. The first call to make.
Request
curl -X GET https://api.chatrail.dev/v1/whoami \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The principal, its scopes and its workspace. |
/v1/workspace
Get the current workspace
Dashboard session
Includes the plan and what has been used against it.
Request
curl -X GET https://api.chatrail.dev/v1/workspaceResponses
| Status | Meaning |
|---|---|
200 | The workspace, the caller role and the plan. |
Auth
Dashboard sign-in. Not used by API clients.
/v1/auth/logout
End the session
Dashboard session
Request
curl -X POST https://api.chatrail.dev/v1/auth/logoutResponses
| Status | Meaning |
|---|---|
204 | Signed out. |
/v1/auth/request-code
Request a sign-in code
No credential
Always answers 202, whether or not the address has an account. It is not an existence check and must not be presented as one.
Body
| Field | Type | Notes | |
|---|---|---|---|
email | string (email) | required | length 0–320; email format |
Request
curl -X POST https://api.chatrail.dev/v1/auth/request-code \
-H "Content-Type: application/json" \
-d '{
"email": "you@company.com"
}'Responses
| Status | Meaning |
|---|---|
202 | A code has been sent if that address has an account. |
/v1/auth/session
Read the current session
Dashboard session
Request
curl -X GET https://api.chatrail.dev/v1/auth/sessionResponses
| Status | Meaning |
|---|---|
200 | The signed-in user and workspace. |
401 | Not signed in. |
/v1/auth/verify
Exchange a code for a session
No credential
Every failure returns the same error — no code, wrong code, expired, too many attempts. Distinguishing them would reintroduce an oracle.
Body
| Field | Type | Notes | |
|---|---|---|---|
email | string (email) | required | length 0–320; email format |
code | string | required | pattern ^\d{6}$ |
Request
curl -X POST https://api.chatrail.dev/v1/auth/verify \
-H "Content-Type: application/json" \
-d '{
"email": "you@company.com",
"code": "123456"
}'Responses
| Status | Meaning |
|---|---|
200 | A session cookie is set. |
401 | That code is not valid. |
MCP
Workspace tools for a coding assistant.
/v1/mcp
MCP endpoint
API key · mcp:read
Model Context Protocol over a stateless streamable HTTP transport. Read-only by default; mutating tools preview and apply only when called again with confirm: true. No tool returns message content.
Request
curl -X POST https://api.chatrail.dev/v1/mcp \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | An MCP response. |
402 | MCP is not on this plan. |
/v1/mcp/tools
List MCP tools
API key · mcp:read
Request
curl -X GET https://api.chatrail.dev/v1/mcp/tools \
-H "Authorization: Bearer $CHATRAIL_API_KEY"Responses
| Status | Meaning |
|---|---|
200 | The tools this credential may call. |
Operational
Health and metrics.
/healthz
Liveness
No credential
Never checks dependencies. Point a restart policy here, not a traffic probe.
Request
curl -X GET https://api.chatrail.dev/healthzResponses
| Status | Meaning |
|---|---|
200 | The process is alive. |
/metrics
Prometheus metrics
No credential
Not registered unless METRICS_TOKEN is configured. No label carries a workspace, connection, number or session name.
Request
curl -X GET https://api.chatrail.dev/metricsResponses
| Status | Meaning |
|---|---|
200 | Exposition format. |
401 | Missing or wrong token. |
/readyz
Readiness
No credential
Checks dependencies. Point the load balancer here.
Request
curl -X GET https://api.chatrail.dev/readyzResponses
| Status | Meaning |
|---|---|
200 | Ready. |
503 | A dependency is unavailable. |
/v1/openapi.json
This document
No credential
Request
curl -X GET https://api.chatrail.dev/v1/openapi.jsonResponses
| Status | Meaning |
|---|---|
200 | The OpenAPI document. |
Internal
Called by the transport, not by you.
/v1/provider/{providerName}/{token}
Provider callback
No credential
Called by the WhatsApp transport, not by you. Authenticated by the per-connection token returned once when the connection was created. Redeliveries are deduplicated.
Parameters
| Name | In | Type | Notes | |
|---|---|---|---|---|
providerName | path | string | required | Transport name, e.g. `waha`. |
token | path | string | required | The connection callback token. |
Request
curl -X POST https://api.chatrail.dev/v1/provider/:providerName/:tokenResponses
| Status | Meaning |
|---|---|
202 | Handled or ignored. |
404 | Unknown callback. |