The Envox API brings the panel's content and messaging tools into your own code:
- Posts — publish images, carousels, Reels and stories to the accounts connected to Envox, right away or at a set time.
- Envox AI — on-brand images, carousels and short videos made from a topic.
- Ideas and results — post ideas from your best posts and your competitors, and the likes, reach and views of what you published.
- WhatsApp Business — templates (also written by AI), template messages to one or many numbers, and the inbox.
It runs the same flows as the panel, so everything shows up in Posts, the Calendar and the inbox too.
Base URL:
https://app.envox.ai/api/v1
Every request and response is JSON, except media uploads (multipart/form-data).
Before you start
- Create an API key on the API & MCP page of the panel. It starts with
envx_and is shown only once. - Send it on every request:
Authorization: Bearer envx_YOUR_API_KEY
- A key works with the permissions of the user who created it. A team member's key needs the content permissions in Roles.
- Connect the accounts you want to post to in Social Connections first.
Keep keys on your server. Never put one in a website, a mobile app or a public repository — anyone with the key can post as you.
Endpoints
GET /me
The account the key acts for, its timezone, the credit balance and the prices of publishing, AI generation and WhatsApp messages.
curl https://app.envox.ai/api/v1/me \ -H "Authorization: Bearer envx_YOUR_API_KEY"{ "data": { "user": { "id": 7, "name": "Ada", "email": "ada@example.com", "is_account_owner": true }, "account": { "id": 7, "name": "Ada", "timezone": "Europe/Istanbul" }, "credits": { "balance": 248.5, "has_active_subscription": true, "plan": "Growth", "period_ends_at": "2026-12-02T00:00:00+00:00" }, "pricing": { "publish_per_channel": 0.1, "image": 2, "carousel_slide": 2, "video": 7, "whatsapp_message": 0.05, "…": "…" } } }POST /media
Uploads an image or a video and returns its
idformedia_ids. Send either a file (multipart/form-data, fieldfile) or a public URL (JSON, fieldurl).curl -X POST https://app.envox.ai/api/v1/media \ -H "Authorization: Bearer envx_YOUR_API_KEY" \ -F "file=@summer-campaign.png"{ "data": { "id": "img_3051", "type": "image", "url": "https://app.envox.ai/storage/content-posts/uploads/7/api/9f2c….jpg", "mime": "image/jpeg", "width": 1080, "height": 1350, "warnings": [] } }- Images: JPEG, PNG or WebP, up to 8 MB. Everything is stored as JPEG.
- Videos: MP4 or MOV, up to 100 MB, 3 seconds to 15 minutes, kept as sent. 9:16 (1080×1920), H.264 video and AAC audio work everywhere.
Image ids start with
img_, video ids withvid_. A video answers with its size and length:{ "data": { "id": "vid_88", "type": "video", "url": "https://app.envox.ai/storage/content-posts/uploads/7/videos/4be1….mp4", "mime": "video/mp4", "width": 1080, "height": 1920, "duration_seconds": 14.5, "warnings": [] } }warningsflags what Instagram is likely to reject or show badly — an image outside 4:5 to 1.91:1, a video that is not 9:16, or a codec it does not take. Each media id can be used in one post.POST /media/upload-links
A one-time upload URL that needs no API key — useful when a script or an AI agent should upload a file without seeing the key. Valid for 15 minutes and one file.
{ "data": { "upload_url": "https://app.envox.ai/api/v1/media/upload-links/Xk3…", "method": "POST", "field": "file", "expires_at": "2026-11-20T09:45:00+00:00", "curl": "curl -sS -X POST -F \"file=@/path/to/file\" \"https://app.envox.ai/api/v1/media/upload-links/Xk3…\"" } }The upload answers like
POST /media.POST /posts
Creates a post and publishes it now, schedules it, or keeps it as a draft.
Field Type captionstring Post text with hashtags. Required unless draftor a story. Up to 2,200 characters for Instagram.social_account_idsinteger[] Accounts to publish to. Required unless draft.media_idsstring[] Media from POST /media(img_…,vid_…), in slide order.media_urlsstring[] Public image or video URLs, fetched by Envox, after media_ids.scheduled_atstring ISO 8601 time to publish at. Leave out to publish now. draftboolean Save without publishing. formatstring post(default) orstory(one image or video, Instagram only).suggestion_idinteger The content suggestion the post comes from (optional). A post has 1 to 10 images — more than one makes a carousel — or exactly one video. A video goes out as a Reel on Instagram and a video on Facebook pages; LinkedIn does not take videos. A story video can be at most 60 seconds.
curl -X POST https://app.envox.ai/api/v1/posts \ -H "Authorization: Bearer envx_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "caption": "New collection is live #envox", "media_urls": ["https://example.com/photo.jpg"], "social_account_ids": [12, 15], "scheduled_at": "2026-12-01T09:30:00+03:00" }'{ "data": { "id": 1842, "status": "scheduled", "format": "image", "caption": "New collection is live #envox", "scheduled_at": "2026-12-01T06:30:00+00:00", "published_at": null, "failure_reason": null, "source": "api", "media": [{ "id": "img_3052", "type": "image", "url": "https://…", "width": 1080, "height": 1080 }], "targets": [ { "id": 501, "social_account_id": 12, "platform": "instagram", "status": "pending", "external_post_id": null, "error": null, "published_at": null }, { "id": 502, "social_account_id": 15, "platform": "facebook", "status": "pending", "external_post_id": null, "error": null, "published_at": null } ], "panel_url": "https://envox.ai/customer/content-posts/1842" } }Publishing runs in the background. Read the post again to see each target move from
pendingtopublishedorfailed.A Reel from a video uploaded earlier:
{ "caption": "Behind the scenes #envox", "media_ids": ["vid_88"], "social_account_ids": [12, 15] }Media made with Envox AI works the same way: pass the
img_…orvid_…ids from a finished generation. A post made only of AI media costs nothing more to publish.A
scheduled_atwithout an offset —2026-12-01T09:30:00— is read in the account timezone fromGET /me. Send an offset to be explicit.GET /posts
The account's posts, newest first — including the ones made in the panel. Scheduled posts are ordered by publish time.
Query statusdraft,scheduled,publishing,publishedorfailedfrom,toscheduled_atwindow, ISO 8601sourceapi,mcporpanelper_page1–100, default 20 pagePage number The response has
data,linksandmeta(pagination).GET /posts/{id}
One post with its result on every account (
targets).PATCH /posts/{id}
Changes
captionand/orscheduled_atof a draft or scheduled post. Only a post scheduled for later can be moved; to schedule a draft usePOST /posts/{id}/publish.POST /posts/{id}/publish
Publishes a draft now, or schedules it with
scheduled_at. Also retries a failed post.social_account_idsis optional and replaces the draft's accounts.POST /posts/{id}/cancel
Stops a scheduled (or failed) post and turns it back into a draft. Posts already published on a network are not removed.
DELETE /posts/{id}
Deletes a draft. Answers
204 No Content. Cancel a scheduled post first.
AI images and videos
GET /brand-guides
The brand guides of the account (
usable: truewhen ready). When you leavebrand_guide_idout, Envox uses the brand guide used last.GET /reference-image-groups
Reference image sets (
id,name,image_count) that guide the look of AI images.POST /images/generate
Field Type topicstring What the post is about and what the image should say. Required unless suggestion_id.kindstring single(default) orcarousel.countinteger single: 1–4 variations.slide_countinteger carousel: 2–10 slides, planned by Envox AI.aspect_ratiostring 1:1(default),9:16(Reels, stories, video),4:3,16:9.qualitystring standard(default) orhigh.languagestring Language of the text in the image: en,tr,de,fr,es,it,pt,nl,ru,ar.extra_instructionsstring Extra visual direction. brand_guide_id,reference_image_group_idinteger Defaults: the ones used last. suggestion_idinteger Make the image for a content suggestion. curl -X POST https://app.envox.ai/api/v1/images/generate \ -H "Authorization: Bearer envx_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "topic": "Black Friday: 30% off all coffee machines", "aspect_ratio": "1:1", "language": "en" }'{ "data": { "id": "igen_412", "kind": "image", "status": "queued", "topic": "Black Friday: 30% off all coffee machines", "brand_guide_id": 3, "credits": 2, "media": [], "next_step": "Still generating (usually 20-90 seconds)…" } }The answer is
202 Accepted. Credits are charged when the generation starts and refunded for any image that is not produced.POST /images/edit
A changed copy of an image:
image_id(img_…, generated or uploaded) andinstructionssuch as "make the background dark blue". The original is kept.POST /videos/generate
Turns an image into a 5–10 second motion video, published as a Reel.
Field Type image_idstring The image to animate ( img_…); 9:16 works best.motion_instructionsstring How it should move, e.g. steam rising, slow push-in. stylestring animate(default) ortext_reveal(the text animates in; premium price).qualitystring standard(default) orpremium.durationinteger 5,6or10seconds.GET /generations/{id}
The status of a generation:
queued,processing,completed,partial(some images failed) orfailed. When it is done,mediahas the ids:{ "data": { "id": "igen_412", "kind": "image", "status": "completed", "media": [ { "id": "img_3104", "type": "image", "url": "https://…", "width": 1024, "height": 1024, "warnings": [] } ] } }Images take 20–90 seconds, videos 1–4 minutes. Poll every 10–30 seconds.
Content suggestions
Post ideas from the account's own recent Instagram and Facebook posts (what got the most likes and comments) and from tracked competitors — see Content Suggestions.
| Endpoint | |
|---|---|
GET /suggestions |
Ideas; status = pending (default), accepted, dismissed or all |
POST /suggestions/generate |
New ideas in the background: count (3–10), language, brand_guide_id, social_account_id |
GET /suggestions/batches/{id} |
Status of a run, with the new ideas once completed |
POST /suggestions/{id}/dismiss |
Marks an idea as not wanted |
GET /competitors |
Tracked competitor Instagram accounts |
POST /competitors |
Start tracking one: username (handle or profile link; Business or Creator accounts) |
DELETE /competitors/{id} |
Stop tracking one |
An idea has a topic, a rationale (why it should work) and a
suggested_format. Pass its id as suggestion_id to POST /images/generate to
make the visual; the post you then create is linked to the idea.
Insights
GET /posts/{id}/insights
Per account the post was published to:
{ "data": { "post_id": 1842, "targets": [ { "platform": "instagram", "permalink": "https://www.instagram.com/p/…", "metrics": { "likes": 60, "comments": 10, "shares": 4, "saves": 12, "reach": 900, "views": 1500, "interactions": 86, "engagement_rate": 9.56 }, "insights_available": true } ], "totals": { "likes": 67, "comments": 12, "…": "…" } } }Reach, views and saves come from Instagram insights. If the account was connected before Envox asked for that permission,
insights_availableisfalseand only likes and comments are returned — reconnect the account to fix it. Facebook gives likes, comments and shares.
GET /whatsapp/numbers
The numbers:
id(use it asphone_number_id),phone_number,ai_replies(an AI agent answers incoming messages) andtoken_expired.GET /whatsapp/templates
Message templates with their Meta review
status(APPROVED,PENDING,REJECTED…), text, buttons andneeds— how many values a send must provide. Filters:status,phone_number_id,search.POST /whatsapp/templates/syncre-reads the statuses from Meta.POST /whatsapp/templates/draft
Envox AI writes a template from a goal, following Meta's review rules, and lists any rule it still breaks. Free; nothing is sent to Meta.
{ "goal": "Remind customers of their appointment tomorrow with the time", "language": "en", "category": "UTILITY" }The answer's
draftcan be sent toPOST /whatsapp/templatesas it is (addphone_number_id).POST /whatsapp/templates
Creates a template on the number's WhatsApp Business account and submits it for Meta review (minutes to 24 hours).
Field Type phone_number_idstring From GET /whatsapp/numbers.namestring Lowercase with underscores, e.g. appointment_reminder.categorystring UTILITY(about an order, booking or account) orMARKETING.languagestring en,tr,de,ar,fr,es,it,nl,ru,pt_BR…headerstring Optional text, up to 60 characters, at most one {{1}}.bodystring Up to 1,024 characters with {{1}},{{2}}… — not at the very start or end.footerstring Optional, up to 60 characters, no variables. buttonsobject[] { "type": "QUICK_REPLY" | "URL" | "PHONE_NUMBER", "text", "url", "phone_number" }examplesobject body: one example per body variable;header,urlwhen used.Envox checks Meta's rules first and answers
422with every problem it finds. Image headers are set up in the panel.POST /whatsapp/sends
Sends an
APPROVEDtemplate to up to 1,000 numbers, each with its own values.{ "template_id": 31, "recipients": [ { "to": "+905551112233", "body": ["Ayşe", "14:30"] }, { "to": "+905554445566", "body": ["Mehmet", "16:00"] } ] }headergives the header value,buttonthe end of a link button's URL andheader_image_urlthe image of an image-header template. Each sent message costs the WhatsApp message price; sending stops if credits run out. Only send to people who agreed to receive messages from you.The answer (
202) has the sendid.GET /whatsapp/sends/{id}returns the counts —accepted,sent,delivered,read,failed— and every recipient's status and error.Conversations
Endpoint GET /whatsapp/conversationsConversations, newest first; status(open,closed,all),phone,limitGET /whatsapp/conversations/{id}One conversation with its messages(from:customer,business,human,template)POST /whatsapp/conversations/{id}/replySends textas the business; takes the conversation over from the AI agentPOST /whatsapp/conversations/{id}/releaseHands it back to the AI agent A free-form reply is only possible within 24 hours of the customer's last message (
can_reply,reply_window_expires_at); after that Meta allows only templates.
Errors
Every error has the same shape:
{
"error": {
"code": "validation_failed",
"message": "Choose at least one connected account to publish to.",
"details": { "social_account_ids": ["Choose at least one connected account to publish to."] }
}
}
| Status | code |
When |
|---|---|---|
| 401 | invalid_api_key |
Missing, wrong or revoked key |
| 402 | insufficient_credits |
Not enough credits; details has required and available |
| 403 | forbidden / account_inactive |
Missing permission, plan without publishing, or an inactive account |
| 404 | not_found |
The post, media or other item does not exist on this account |
| 409 | conflict |
Suggestions are already being generated |
| 422 | validation_failed |
A field is wrong; details lists them |
| 429 | rate_limited |
Too many requests or too many generations running; wait and retry |
| 502 / 503 | server_error |
Instagram, Facebook or the AI provider did not answer; try again later |
Good to know
- Limits: 120 requests a minute per account, of which 30 may upload media or create posts or sends and 20 may start AI generations. At most 5 generations run at the same time.
- Credits: your own uploaded media is charged the publishing price once per account it is published to. AI images, carousel slides and videos are charged when generated (failed ones are refunded) and publish at no extra cost. WhatsApp template messages are charged per sent message. Drafts, insights, template drafts and reading are free. See Credits.
- Team keys: posts, AI and insights need the content permissions; WhatsApp numbers and templates the phone number permissions; sends and the inbox the inbox permissions.
- Instagram: JPEG only (Envox converts for you), aspect ratio 4:5 to 1.91:1 for feed posts, up to 10 images, captions up to 2,200 characters.
- Videos: Reels and story videos are shown full screen at 9:16. Instagram
processes a video for up to a few minutes before it appears, so its target
stays
pendinga little longer than an image. - Older keys: keys created before bearer keys existed still work with the
X-App-KeyandX-App-Secretheaders. - Prefer talking to an AI assistant over writing code? See MCP.