Overview
The base URL is https://api.chesly.app. Each call takes your key as Authorization: Bearer ck_live_…, except the ones marked as needing none. This page is built from the OpenAPI 3.1 document at api.chesly.app/v1/openapi.json, which the API's own code generates: point a client generator or an agent at it. Every operation can also answer the errors its list names, each linked to what to do; a call with a key can always meet invalid_api_key, rate_limited, api_paused, upstream_unavailable and internal_error.
Your key
GET /v1/me
The key in use: its scope, limits, plan and this month's calls.
Accounts
GET /v1/accounts
The accounts the user connected in Chesly, oldest first.
Chats
GET /v1/chats
The user's chats, a page at a time.
| Parameter |
In |
Type |
Description |
account_id |
query |
string |
Optional. |
network |
query |
string |
Only this network's chats, such as whatsapp. Email is listed only with email. Optional. |
updated_since |
query |
time (ISO 8601) |
Only chats whose last message is at or after this time. Optional. |
unread |
query |
true or false |
Optional. |
archived |
query |
true, false or all |
Optional. |
q |
query |
string |
Optional. |
sort |
query |
recent or unread |
Optional. |
limit |
query |
integer |
Optional. |
cursor |
query |
string |
Optional. |
GET /v1/chats/{chat_id}
One chat.
| Parameter |
In |
Type |
Description |
chat_id |
path |
string |
The chat's ID (chat_…). |
POST /v1/chats/{chat_id}/read
Mark a chat read up to its newest message.
| Parameter |
In |
Type |
Description |
chat_id |
path |
string |
The chat's ID (chat_…). |
Idempotency-Key |
header |
string |
1 to 255 characters from A-Za-z0-9._:- (or that, quoted). Repeat a request with the same key within 24 hours and get the first answer back. Optional. |
Messages
GET /v1/chats/{chat_id}/messages
A chat's messages, newest first, a page at a time.
| Parameter |
In |
Type |
Description |
chat_id |
path |
string |
The chat's ID (chat_…). |
before |
query |
time (ISO 8601) |
Only messages sent before this time. Optional. |
after |
query |
time (ISO 8601) |
Only messages sent after this time. Optional. |
limit |
query |
integer |
Optional. |
cursor |
query |
string |
Optional. |
POST /v1/chats/{chat_id}/messages
Send a message to a chat.
| Parameter |
In |
Type |
Description |
chat_id |
path |
string |
The chat's ID (chat_…). |
Idempotency-Key |
header |
string |
Sends at most once per key, however often the request is retried: 1 to 255 of A-Z, a-z, 0-9, ".", "_", ":" and "-". Kept 24 hours. A retry with the same key and body answers the first answer again, with Idempotent-Replayed: true. Optional. |
The body, application/json, is a SendMessage.
201: The message as sent. Its delivery is queued until the network takes it; GET /v1/messages/{message_id} follows it: Message.
- Errors: 400
invalid_request, text_too_long, invalid_reply_to, unsupported_chat, idempotency_key_invalid, media_too_large · 401 invalid_api_key · 402 api_plan_required · 403 insufficient_scope, signing_key_missing · 404 chat_not_found, media_not_found · 409 message_request, idempotency_in_progress · 410 media_expired · 422 idempotency_key_reused · 429 send_limit_reached, rate_limited · 500 internal_error · 503 network_unavailable, upstream_unavailable, api_paused.
GET /v1/messages/{message_id}
One message, with its delivery status.
| Parameter |
In |
Type |
Description |
message_id |
path |
string |
The message's ID (msg_…). |
GET /v1/messages/search
Search the text of the user's messages.
| Parameter |
In |
Type |
Description |
q |
query |
string |
|
chat_id |
query |
string |
Optional. |
account_id |
query |
string |
Optional. |
network |
query |
string |
Only this network's chats, such as whatsapp. Email is included only with email. Optional. |
limit |
query |
integer |
Optional. |
GET /v1/messages
Everything new across the user's chats since a time, a page at a time.
| Parameter |
In |
Type |
Description |
since |
query |
time (ISO 8601) |
|
network |
query |
string |
Only this network's chats, such as whatsapp. Email is included only with email. Optional. |
limit |
query |
integer |
Optional. |
cursor |
query |
string |
Optional. |
GET /v1/catch_up
The unread chats, newest first, each with its newest messages.
| Parameter |
In |
Type |
Description |
chats |
query |
integer |
Optional. |
per_chat |
query |
integer |
Optional. |
network |
query |
string |
Only this network's chats, such as whatsapp. Email is included only with email. Optional. |
POST /v1/media
Upload a file to send.
The body, multipart/form-data, is a MediaUpload.
POST /v1/messages/{message_id}/transcript
Transcribe a voice message.
| Parameter |
In |
Type |
Description |
message_id |
path |
string |
The voice message's ID (msg_…). |
A message's media, as bytes.
| Parameter |
In |
Type |
Description |
media_id |
path |
string |
The media's ID (media_…), from a message's media.id. |
Find the people of your direct chats by name.
| Parameter |
In |
Type |
Description |
q |
query |
string |
Part of the person's name, matched ignoring case and accents. |
limit |
query |
integer |
Optional. |
Events
GET /v1/events
Events after a cursor, oldest first.
| Parameter |
In |
Type |
Description |
after |
query |
string |
The last event ID you have (evt_…): events after it. Optional. |
types |
query |
string |
Event types, comma-separated. Without: every type. Optional. |
chat_id |
query |
string |
One chat's events (chat_…). Optional. |
account_id |
query |
string |
One account's events (acct_…); an email account's email too. Optional. |
networks |
query |
string |
Networks, comma-separated. Without: every network but email, which comes only when named here or by account_id. Optional. |
limit |
query |
integer |
Optional. |
GET /v1/events/stream
Events as they happen, as server-sent events.
| Parameter |
In |
Type |
Description |
after |
query |
string |
The last event ID you have (evt_…): events after it. Optional. |
types |
query |
string |
Event types, comma-separated. Without: every type. Optional. |
chat_id |
query |
string |
One chat's events (chat_…). Optional. |
account_id |
query |
string |
One account's events (acct_…); an email account's email too. Optional. |
networks |
query |
string |
Networks, comma-separated. Without: every network but email, which comes only when named here or by account_id. Optional. |
Last-Event-ID |
header |
string |
The last event ID you had: the stream resumes after it. Optional. |
Webhooks
GET /v1/webhooks
Your webhook endpoints.
POST /v1/webhooks
Add a webhook endpoint.
The body, application/json:
| Field |
Type |
Description |
url |
string |
|
event_types |
array of message.received, message.sent, message.edited, message.deleted, message.delivery_failed, chat.created, chat.updated, chat.read, account.connected, account.disconnected, account.needs_attention, reaction.added or reaction.removed |
Optional. |
networks |
array of email, whatsapp, telegram, discord, instagram, messenger, signal, slack, gmessages, googlechat, twitter, linkedin, reddit or imessage |
Optional. |
payload |
full or ids |
Optional. |
description |
string or null |
Optional. |
GET /v1/webhooks/{webhook_id}
A webhook endpoint.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
PATCH /v1/webhooks/{webhook_id}
Change a webhook endpoint, or turn it on or off.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
The body, application/json:
| Field |
Type |
Description |
url |
string |
Optional. |
event_types |
array of message.received, message.sent, message.edited, message.deleted, message.delivery_failed, chat.created, chat.updated, chat.read, account.connected, account.disconnected, account.needs_attention, reaction.added or reaction.removed |
Optional. |
networks |
array of email, whatsapp, telegram, discord, instagram, messenger, signal, slack, gmessages, googlechat, twitter, linkedin, reddit or imessage |
Optional. |
payload |
full or ids |
Optional. |
description |
string or null |
Optional. |
enabled |
boolean |
Optional. |
DELETE /v1/webhooks/{webhook_id}
Delete a webhook endpoint and its pending deliveries.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
POST /v1/webhooks/{webhook_id}/rotate_secret
A new signing secret; the old one signs too for 24 hours.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
POST /v1/webhooks/{webhook_id}/test
Send the endpoint a webhook.test event.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
GET /v1/webhooks/{webhook_id}/deliveries
An endpoint's deliveries, newest first.
| Parameter |
In |
Type |
Description |
webhook_id |
path |
string |
The webhook's ID (wh_…). |
status |
query |
pending, succeeded, failed or discarded |
Optional. |
limit |
query |
integer |
Optional. |
cursor |
query |
string |
Optional. |
Keys
GET /v1/keys
List your API keys.
DELETE /v1/keys/{key_id}
Revoke an API key, this one included.
| Parameter |
In |
Type |
Description |
key_id |
path |
string |
The key's ID, from GET /v1/keys. |
Sign-in
POST /v1/cli/sessions
Start a CLI sign-in: a code for the user to approve on web.chesly.app.
No key needed.
The body, application/json, which you can leave out, is a CliSessionRequest.
POST /v1/cli/sessions/token
Poll a CLI sign-in for its key, every interval seconds.
No key needed.
The body, application/json, is a CliTokenRequest.
The OpenAPI document
GET /v1/openapi.json
This OpenAPI 3.1 document.
No key needed.
200: The OpenAPI 3.1 document of /v1, events included as webhooks: JSON.
- Errors: 500
internal_error.
Schemas
The objects the operations take and answer with.
| Field |
Type |
Description |
id |
string |
The person's ID (contact_…): the same for them every time. |
name |
string |
Their name, as their direct chat is named. |
network |
string |
|
account_id |
string or null |
The account their chat is on (acct_…), when Chesly can tell. |
chat_id |
string |
Their direct chat with the user (chat_…). |
| Field |
Type |
Description |
contacts |
array of Contact |
Exact names first, then the most recent chat. |
Problem
| Field |
Type |
Description |
type |
URL |
The code's entry in the error docs. |
title |
string |
|
status |
integer |
|
detail |
string |
Optional. |
code |
string |
Stable: branch on it. |
request_id |
string |
|
retry_after |
integer |
Seconds, on a 429 or 503 that says when to retry. Optional. |
errors |
array of object |
Each problem with the request, on a 400 invalid_request. Optional. |
errors[].detail |
string |
|
errors[].pointer |
string |
|
ApiEvent
| Field |
Type |
Description |
id |
string |
The event's ID (evt_…): dedupe by it. |
type |
message.received, message.sent, message.edited, message.deleted, message.delivery_failed, chat.created, chat.updated, chat.read, account.connected, account.disconnected, account.needs_attention, reaction.added or reaction.removed |
|
timestamp |
time (ISO 8601) |
|
data |
object |
The type's data: see the webhooks of this document. |
EventPage
| Field |
Type |
Description |
events |
array of ApiEvent |
|
next_cursor |
string or null |
The last event's ID, or after when none came back. |
has_more |
boolean |
|
Webhook
| Field |
Type |
Description |
id |
string |
The webhook's ID (wh_…). |
url |
string |
|
description |
string or null |
|
event_types |
array of message.received, message.sent, message.edited, message.deleted, message.delivery_failed, chat.created, chat.updated, chat.read, account.connected, account.disconnected, account.needs_attention, reaction.added or reaction.removed |
Empty: every type. |
networks |
array of string |
Empty: every network but email. |
payload |
full or ids |
|
status |
enabled or disabled |
|
disabled_reason |
user, failing, gone, key_revoked or null |
Why it is off: you turned it off (user), it failed for 3 days (failing), it answered 410 (gone), or an API key that made it, changed it or set its URL was revoked for leaking (key_revoked). |
failing_since |
time (ISO 8601) or null |
|
created_at |
time (ISO 8601) |
|
updated_at |
time (ISO 8601) |
|
WebhookList
| Field |
Type |
Description |
webhooks |
array of Webhook |
|
WebhookCreated
object.
WebhookSecret
| Field |
Type |
Description |
secret |
string |
The new signing secret (whsec_…): shown this once. |
previous_secret_expires_at |
time (ISO 8601) |
Until then, deliveries carry a signature by the old secret too. One old secret is kept: rotating again before then ends the overlap of the one before. |
WebhookTest
| Field |
Type |
Description |
delivery_id |
string |
|
WebhookDelivery
| Field |
Type |
Description |
id |
string |
The delivery's ID (dlv_…). |
event_id |
string or null |
|
event_type |
string |
|
status |
pending, succeeded, failed or discarded |
|
attempts |
integer |
|
next_attempt_at |
time (ISO 8601) or null |
|
last_attempt_at |
time (ISO 8601) or null |
|
last_status_code |
integer or null |
|
last_error |
string or null |
|
last_response_excerpt |
string or null |
The start of your endpoint's last answer. |
created_at |
time (ISO 8601) |
|
delivered_at |
time (ISO 8601) or null |
|
WebhookDeliveryPage
| Field |
Type |
Description |
deliveries |
array of WebhookDelivery |
|
next_cursor |
string or null |
|
Key
| Field |
Type |
Description |
id |
string |
The key's ID, for DELETE /v1/keys/{key_id}. |
name |
string |
|
scope |
full or read |
|
prefix |
string |
The key's first 12 characters. |
last4 |
string |
The key's last 4 characters. |
created_via |
string |
Where it was made: cli (chesly login) or web (the dashboard). |
created_at |
time (ISO 8601) |
|
last_used_at |
time (ISO 8601) or null |
Recorded at most every 5 minutes. |
KeyList
| Field |
Type |
Description |
keys |
array of Key |
|
SendLimit
| Field |
Type |
Description |
account_id |
string or null |
|
network |
string |
|
per_hour |
integer |
|
per_day |
integer |
|
used_last_hour |
integer |
|
used_last_day |
integer |
|
PlanSummary
| Field |
Type |
Description |
plan |
personal, pro or null |
The plan bought; a comp reads pro; null without one. |
status |
none, trialing, active, past_due, unpaid, canceled or comped |
unpaid: Stripe stopped retrying a failed payment; no access until the card is updated. |
trial_ends_at |
time (ISO 8601) or null |
|
period_start |
time (ISO 8601) or null |
|
period_end |
time (ISO 8601) or null |
|
cancel_at |
time (ISO 8601) or null |
When a canceled plan ends (the end of the period paid for); null while it renews. |
calls_this_period |
integer |
Counted, never billed. |
transcription_seconds_this_period |
integer |
|
transcription_seconds_included |
integer |
The period's minutes, in seconds: 36,000 on Personal, 180,000 on Pro, 0 without a plan. |
scheduled_change |
object or null |
A downgrade waiting for the end of the period paid for: the plan, and when it starts. null without one. |
scheduled_change.plan |
personal or pro |
|
scheduled_change.at |
time (ISO 8601) |
|
Me
| Field |
Type |
Description |
key |
object |
|
key.id |
string |
|
key.name |
string |
|
key.scope |
full or read |
|
key.api_version |
string |
|
limits |
object |
|
limits.requests_per_second |
integer |
Per key, and for all of your keys together: your plan's. |
limits.requests_per_minute |
integer |
Per key, and for all of your keys together: your plan's. |
limits.api_keys |
integer |
Active API keys your plan allows. |
limits.webhooks |
integer |
Webhooks your plan allows. |
limits.sends |
array of SendLimit |
|
limits.event_streams |
integer |
Event streams (GET /v1/events/stream) your plan lets you hold open at once. |
limits.event_retention_days |
integer |
How many days your plan keeps your events: an after (or Last-Event-ID) older than that is 410 events_expired. |
usage |
object |
|
usage.period_start |
time (ISO 8601) |
|
usage.calls |
integer |
This key's calls this UTC month, before this one. |
plan |
PlanSummary |
|
Account
| Field |
Type |
Description |
id |
string |
The account's ID (acct_…). |
network |
string |
|
display_name |
string or null |
|
status |
connected, disconnected or needs_attention |
|
connected_at |
time (ISO 8601) or null |
|
AccountList
| Field |
Type |
Description |
accounts |
array of Account |
|
Chat
| Field |
Type |
Description |
id |
string |
The chat's ID (chat_…). |
account_id |
string or null |
|
network |
string |
|
name |
string or null |
|
type |
dm or group |
|
unread_count |
integer |
|
last_message_at |
time (ISO 8601) or null |
|
is_archived |
boolean |
|
is_pinned |
boolean |
|
is_muted |
boolean |
|
is_message_request |
boolean |
A pending request: readable, never answered or marked read. |
member_count |
integer |
|
ChatPage
| Field |
Type |
Description |
chats |
array of Chat |
Pinned chats first, then the newest. |
next_cursor |
string or null |
The next page's cursor, or null on the last page. |
| Field |
Type |
Description |
id |
string |
The media's ID (media_…), for GET /v1/media/{media_id}. |
mime_type |
string |
Optional. |
file_name |
string |
Optional. |
DeliveryError
| Field |
Type |
Description |
code |
network_rejected, not_logged_in, rate_limited_by_network, unsupported, timeout or unknown |
|
message |
string |
A fixed sentence for the code. |
certain |
boolean |
Whether the message certainly didn't arrive (false: it may have). |
Delivery
How a message sent through the API in the last 30 days is getting on; null for any other.
| Field |
Type |
Description |
status |
queued, sent, delivered or failed |
|
error |
DeliveryError or null |
|
updated_at |
time (ISO 8601) |
|
EmailAddress
| Field |
Type |
Description |
name |
string or null |
|
address |
string |
|
An email's headers, on network email only.
Message
| Field |
Type |
Description |
id |
string |
The message's ID (msg_…). |
chat_id |
string |
|
sender |
object |
|
sender.name |
string |
|
sender.is_me |
boolean |
|
text |
string |
|
truncated |
boolean |
|
type |
text, image, video, audio, file or other |
|
media |
MessageMedia or null |
|
sent_at |
time (ISO 8601) or null |
|
edited |
boolean |
|
deleted |
boolean |
|
reply_to |
string or null |
The message this one replies to, in the same chat. |
delivery |
Delivery or null |
|
email |
EmailHeaders |
Optional. |
MessagePage
| Field |
Type |
Description |
messages |
array of Message |
Newest first. A page can be short, or empty, while next_cursor still leads to older ones. |
next_cursor |
string or null |
|
ReadResult
| Field |
Type |
Description |
read |
true |
|
receipt_sent |
boolean |
Whether the network got a read receipt (never for a message request). |
SearchHit
object.
SearchResults
| Field |
Type |
Description |
messages |
array of SearchHit |
Newest first. |
MessagesSince
| Field |
Type |
Description |
messages |
array of Message |
Chats newest first; each chat's messages newest first. |
next_cursor |
string or null |
|
until |
time (ISO 8601) |
Where this walk ends: start the next one from here. |
CatchUp
| Field |
Type |
Description |
chats |
array of object |
|
chats[].chat |
Chat |
|
chats[].messages |
array of Message |
|
truncated |
boolean |
Whether some messages were left out, or a chat's messages couldn't be read. |
CliSession
| Field |
Type |
Description |
device_code |
string |
|
user_code |
string |
|
verification_uri |
URL |
|
verification_uri_complete |
URL |
The approval page with the code filled in. |
expires_in |
integer |
Seconds until the code expires. |
interval |
integer |
Seconds to wait between polls. |
CliSessionRequest
| Field |
Type |
Description |
client_name |
string |
Labels the key, such as the computer's name. Optional. |
CliToken
| Field |
Type |
Description |
api_key |
string |
|
token_type |
Bearer |
|
CliTokenError
| Field |
Type |
Description |
error |
authorization_pending, slow_down, access_denied, expired_token or invalid_request |
|
CliTokenRequest
| Field |
Type |
Description |
device_code |
string |
|
SendMessage
| Field |
Type |
Description |
text |
string |
The text, or a file's caption. At most 1,000 characters on Instagram, 2,000 on Discord, 4,096 on Telegram, 100,000 by email and 10,000 elsewhere, counted in UTF-16 code units. In a Google Messages RCS chat, which takes no captions, it follows the file as a message of its own. Optional. |
reply_to |
string |
The message this one replies to: a message ID (msg_…) of the same chat. Optional. |
media_id |
string |
A file to send: the ID POST /v1/media answered (media_…). Optional. |
| Field |
Type |
Description |
id |
string |
The upload's media ID (media_…): send it as media_id. Kept 24 hours. |
mime_type |
string |
|
size |
integer |
In bytes. |
file_name |
string |
|
| Field |
Type |
Description |
file |
bytes |
The file, at most 50 MB (50,000,000 bytes). |
Transcript
| Field |
Type |
Description |
message_id |
string |
The voice message's ID (msg_…). |
text |
string |
|
language |
string or null |
The language heard, as an ISO 639 code, when it was detected. |
duration_seconds |
number or null |
The voice message's length, to a tenth of a second. |
cached |
boolean |
Transcribed before: this answer used none of your plan's minutes. |