Convoly API
Read your Instagram conversations, send DMs and check your automations from your own application, over a plain REST API.
Introduction
The Convoly API is organised around REST. It uses predictable, resource-oriented URLs, returns JSON for every response including errors, and relies on standard HTTP status codes.
https://www.convoly.in/api/v1What you can do
- Read the contacts who have messaged your Instagram account
- Read full conversation history, including shared reels and posts
- Send a DM, with Instagram’s 24-hour window enforced for you
- Inspect your automations and their run statistics
- Track how many messages you have sent this month
Authentication
Authenticate with an API key, sent in the Authorization header of every request. Create keys in Settings → API keys inside Convoly.
Authorization: Bearer cvy_live_YOUR_KEYA bare Authorization: cvy_live_… without the Bearer prefix is also accepted.
curl https://www.convoly.in/api/v1/account \
-H "Authorization: Bearer cvy_live_YOUR_KEY"Errors & status codes
Every error returns the same envelope: a stable machine-readable error you can branch on, and a message written for a person.
{
"error": "send_not_allowed",
"message": "More than 24 hours have passed since this person's last message, so an automated reply cannot be sent."
}| Status | Error | Meaning |
|---|---|---|
400 | invalid_request | A required field is missing or malformed. The message says which. |
401 | missing_api_key | No Authorization header was sent. |
401 | invalid_api_key | The key is wrong, or it has been revoked. |
403 | account_inactive | The Instagram account behind this key is disconnected. Reconnect it in Convoly. |
404 | contact_not_found | No contact with that identifier belongs to this account. |
422 | send_not_allowed | Instagram's messaging window forbids this send. Check reason and messaging_window. |
500 | internal_error | Something went wrong on our side. Safe to retry with backoff. |
Get account
GET https://www.convoly.in/api/v1/accountReturns the Instagram account this API key belongs to. Useful as a health check and to confirm which account a key acts on.
curl https://www.convoly.in/api/v1/account \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"account": {
"id": "3f0c…",
"instagram_user_id": "17841444482386124",
"username": "languageiquanta",
"display_name": "Language With iQuanta",
"account_type": "BUSINESS",
"followers_count": 222,
"status": "active"
}
}List contacts
GET https://www.convoly.in/api/v1/contactsPeople who have messaged your account. Each contact carries its current messaging_window, so you can tell whether a send would be permitted without reimplementing Instagram's rules.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | No | How many to return. Default 50, maximum 200. |
curl "https://www.convoly.in/api/v1/contacts?limit=2" \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"contacts": [
{
"id": "b71e…",
"instagram_user_id": "1099883142544299",
"name": "Lakshay Panwar",
"tags": ["lead"],
"opted_out": false,
"last_inbound_at": "2026-08-30T10:20:11.000Z",
"messaging_window": "open"
}
],
"has_more": true
}- messaging_window is one of: open (you may reply freely), human_agent_only (past 24h — only a human-typed reply is lawful), closed (past 7 days), no_conversation (they have never messaged you).
List conversations
GET https://www.convoly.in/api/v1/conversationsEvery conversation with a message count and a preview of the most recent message.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | No | How many to return. Default 50, maximum 200. |
curl https://www.convoly.in/api/v1/conversations \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"conversations": [
{
"contact_id": "b71e…",
"instagram_user_id": "1099883142544299",
"name": "Lakshay Panwar",
"message_count": 24,
"last_message": {
"direction": "in",
"text": "Hey",
"sent_at": "2026-08-30T10:20:11.000Z"
}
}
],
"has_more": false
}Get messages
GET https://www.convoly.in/api/v1/conversations/:contact_id/messagesThe message history for one conversation, oldest first. Shared reels and posts arrive as attachments with an instagram.com permalink and an empty text field.
| Parameter | Type | Required | Description |
|---|---|---|---|
contact_id | string | Yes | The contact's Convoly id. |
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Most recent N messages. Default 50, maximum 200. |
curl https://www.convoly.in/api/v1/conversations/b71e.../messages \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"contact_id": "b71e…",
"messages": [
{ "id": "…", "direction": "in", "text": "Hey", "attachments": [],
"source": "dm", "sent_at": "2026-08-30T10:20:11.000Z" },
{ "id": "…", "direction": "in", "text": "", "source": "dm",
"attachments": [
{ "kind": "share", "media": "reel", "title": null,
"url": "https://www.instagram.com/reel/DWVusbwDQba/" }
],
"sent_at": "2026-08-30T10:21:02.000Z" }
]
}{
"error": "conversation_not_found",
"message": "No conversation with that contact id."
}Send a DM
POST https://www.convoly.in/api/v1/messagesSends a direct message. This runs the same 24-hour window check as the rest of Convoly, so a send that Instagram would reject is refused here first, with a reason you can act on.
| Parameter | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The message. 1–1000 characters. |
contact_id | string | No | The contact's Convoly id. Provide this or instagram_user_id. |
instagram_user_id | string | No | The contact's Instagram-scoped id. Provide this or contact_id. |
curl -X POST https://www.convoly.in/api/v1/messages \
-H "Authorization: Bearer cvy_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "b71e…",
"text": "Thanks for reaching out — here is the link you asked for."
}'{
"message": {
"id": "…",
"mid": "aWdfZAG1faXRlbTo…",
"contact_id": "b71e…",
"text": "Thanks for reaching out …",
"status": "sent"
}
}{
"error": "send_not_allowed",
"message": "More than 24 hours have passed since this person's last message, so an automated reply cannot be sent.",
"reason": "outside_24h_window_and_not_human_agent",
"messaging_window": "human_agent_only"
}{
"error": "contact_not_found",
"message": "No contact matches that identifier for this account. A contact exists only after they message you first."
}- Instagram has no cold outreach. A contact can only be messaged after they message you first — otherwise you get reason: user_never_messaged_first.
- The HUMAN_AGENT tag, which extends the window to 7 days, is intentionally not available over the API. Meta permits it only for text a person actually typed, and an API call cannot attest to that. Use the Live Chat inbox for those replies.
- A 422 is a normal outcome, not a fault. Handle it rather than retrying — retrying will not change the window.
List automations
GET https://www.convoly.in/api/v1/flowsYour automations, their trigger configuration and their run statistics.
curl https://www.convoly.in/api/v1/flows \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"flows": [
{
"id": "…",
"name": "Auto-DM links from comments",
"status": "live",
"trigger": { "type": "comment", "match": "contains", "keywords": ["link"] },
"stats": { "runs": 42, "sent": 39, "clicks": 12 }
}
]
}Get usage
GET https://www.convoly.in/api/v1/usageSends in the current calendar month, broken down by outcome — including the ones the window check stopped before they cost you anything.
curl https://www.convoly.in/api/v1/usage \
-H "Authorization: Bearer cvy_live_YOUR_KEY"{
"period": "current_calendar_month",
"sent": 142,
"blocked_by_window": 9,
"blocked_opted_out": 0,
"failed": 1,
"total_attempted": 152
}