API reference

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.

Base URL
https://www.convoly.in/api/v1

What 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
One key, one Instagram account. Each API key is scoped to a single connected Instagram account. To act on several accounts, create a key for each.

Authentication

Authenticate with an API key, sent in the Authorization header of every request. Create keys in Settings → API keys inside Convoly.

Authorization header
Authorization: Bearer cvy_live_YOUR_KEY

A bare Authorization: cvy_live_… without the Bearer prefix is also accepted.

Keep your key secret. It can send messages from your Instagram account. Never put it in client-side code, a mobile app or version control — call the API from your server. The key is shown once when you create it and stored only as a hash, so if you lose it, revoke it and make a new one.
Example request
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."
}
StatusErrorMeaning
400invalid_requestA required field is missing or malformed. The message says which.
401missing_api_keyNo Authorization header was sent.
401invalid_api_keyThe key is wrong, or it has been revoked.
403account_inactiveThe Instagram account behind this key is disconnected. Reconnect it in Convoly.
404contact_not_foundNo contact with that identifier belongs to this account.
422send_not_allowedInstagram's messaging window forbids this send. Check reason and messaging_window.
500internal_errorSomething went wrong on our side. Safe to retry with backoff.
GET

Get account

GET https://www.convoly.in/api/v1/account

Returns the Instagram account this API key belongs to. Useful as a health check and to confirm which account a key acts on.

Request
curl https://www.convoly.in/api/v1/account \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "account": {
    "id": "3f0c…",
    "instagram_user_id": "17841444482386124",
    "username": "languageiquanta",
    "display_name": "Language With iQuanta",
    "account_type": "BUSINESS",
    "followers_count": 222,
    "status": "active"
  }
}
GET

List contacts

GET https://www.convoly.in/api/v1/contacts

People 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.

Query parameters
ParameterTypeRequiredDescription
limitintegerNoHow many to return. Default 50, maximum 200.
Request
curl "https://www.convoly.in/api/v1/contacts?limit=2" \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "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
}
Notes
  • 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).
GET

List conversations

GET https://www.convoly.in/api/v1/conversations

Every conversation with a message count and a preview of the most recent message.

Query parameters
ParameterTypeRequiredDescription
limitintegerNoHow many to return. Default 50, maximum 200.
Request
curl https://www.convoly.in/api/v1/conversations \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "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

Get messages

GET https://www.convoly.in/api/v1/conversations/:contact_id/messages

The message history for one conversation, oldest first. Shared reels and posts arrive as attachments with an instagram.com permalink and an empty text field.

Path parameters
ParameterTypeRequiredDescription
contact_idstringYesThe contact's Convoly id.
Query parameters
ParameterTypeRequiredDescription
limitintegerNoMost recent N messages. Default 50, maximum 200.
Request
curl https://www.convoly.in/api/v1/conversations/b71e.../messages \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "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" }
  ]
}
404 Not FoundUnknown conversation
{
  "error": "conversation_not_found",
  "message": "No conversation with that contact id."
}
POST

Send a DM

POST https://www.convoly.in/api/v1/messages

Sends 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.

Body
ParameterTypeRequiredDescription
textstringYesThe message. 1–1000 characters.
contact_idstringNoThe contact's Convoly id. Provide this or instagram_user_id.
instagram_user_idstringNoThe contact's Instagram-scoped id. Provide this or contact_id.
Request
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."
  }'
Responses
201 CreatedSent
{
  "message": {
    "id": "…",
    "mid": "aWdfZAG1faXRlbTo…",
    "contact_id": "b71e…",
    "text": "Thanks for reaching out …",
    "status": "sent"
  }
}
422 UnprocessableOutside the messaging window
{
  "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"
}
404 Not FoundUnknown contact
{
  "error": "contact_not_found",
  "message": "No contact matches that identifier for this account. A contact exists only after they message you first."
}
Notes
  • 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.
GET

List automations

GET https://www.convoly.in/api/v1/flows

Your automations, their trigger configuration and their run statistics.

Request
curl https://www.convoly.in/api/v1/flows \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "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

Get usage

GET https://www.convoly.in/api/v1/usage

Sends in the current calendar month, broken down by outcome — including the ones the window check stopped before they cost you anything.

Request
curl https://www.convoly.in/api/v1/usage \
  -H "Authorization: Bearer cvy_live_YOUR_KEY"
Responses
200 OKSuccess
{
  "period": "current_calendar_month",
  "sent": 142,
  "blocked_by_window": 9,
  "blocked_opted_out": 0,
  "failed": 1,
  "total_attempted": 152
}