Envox.ai
Go to the panel

API Reference

Publish and schedule posts, create on-brand images and videos with Envox AI, read post performance and send WhatsApp templates from your own code with the Envox REST API.

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

  1. 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, "…": "…" }
      }
    }
    
  2. GET /social-accounts

    The connected accounts. Use their id as social_account_ids when posting. Only accounts with can_publish: true can be posted to; reconnect the others in the panel.

    {
      "data": [
        {
          "id": 12,
          "platform": "instagram",
          "username": "envox.ai",
          "name": "Envox",
          "status": "connected",
          "can_publish": true,
          "formats": ["image", "carousel", "video", "story"]
        }
      ]
    }
    

    platform is instagram, facebook (a page) or linkedin. formats lists what the account can take: LinkedIn takes images and carousels, not videos.

  3. POST /media

    Uploads an image or a video and returns its id for media_ids. Send either a file (multipart/form-data, field file) or a public URL (JSON, field url).

    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 with vid_. 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": []
      }
    }
    

    warnings flags 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.

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

  5. POST /posts

    Creates a post and publishes it now, schedules it, or keeps it as a draft.

    Field Type
    caption string Post text with hashtags. Required unless draft or a story. Up to 2,200 characters for Instagram.
    social_account_ids integer[] Accounts to publish to. Required unless draft.
    media_ids string[] Media from POST /media (img_…, vid_…), in slide order.
    media_urls string[] Public image or video URLs, fetched by Envox, after media_ids.
    scheduled_at string ISO 8601 time to publish at. Leave out to publish now.
    draft boolean Save without publishing.
    format string post (default) or story (one image or video, Instagram only).
    suggestion_id integer 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 pending to published or failed.

    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_… or vid_… ids from a finished generation. A post made only of AI media costs nothing more to publish.

    A scheduled_at without an offset — 2026-12-01T09:30:00 — is read in the account timezone from GET /me. Send an offset to be explicit.

  6. GET /posts

    The account's posts, newest first — including the ones made in the panel. Scheduled posts are ordered by publish time.

    Query
    status draft, scheduled, publishing, published or failed
    from, to scheduled_at window, ISO 8601
    source api, mcp or panel
    per_page 1–100, default 20
    page Page number

    The response has data, links and meta (pagination).

  7. GET /posts/{id}

    One post with its result on every account (targets).

  8. PATCH /posts/{id}

    Changes caption and/or scheduled_at of a draft or scheduled post. Only a post scheduled for later can be moved; to schedule a draft use POST /posts/{id}/publish.

  9. POST /posts/{id}/publish

    Publishes a draft now, or schedules it with scheduled_at. Also retries a failed post. social_account_ids is optional and replaces the draft's accounts.

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

  11. DELETE /posts/{id}

    Deletes a draft. Answers 204 No Content. Cancel a scheduled post first.

AI images and videos

  1. GET /brand-guides

    The brand guides of the account (usable: true when ready). When you leave brand_guide_id out, Envox uses the brand guide used last.

  2. GET /reference-image-groups

    Reference image sets (id, name, image_count) that guide the look of AI images.

  3. POST /images/generate

    Field Type
    topic string What the post is about and what the image should say. Required unless suggestion_id.
    kind string single (default) or carousel.
    count integer single: 1–4 variations.
    slide_count integer carousel: 2–10 slides, planned by Envox AI.
    aspect_ratio string 1:1 (default), 9:16 (Reels, stories, video), 4:3, 16:9.
    quality string standard (default) or high.
    language string Language of the text in the image: en, tr, de, fr, es, it, pt, nl, ru, ar.
    extra_instructions string Extra visual direction.
    brand_guide_id, reference_image_group_id integer Defaults: the ones used last.
    suggestion_id integer 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.

  4. POST /images/edit

    A changed copy of an image: image_id (img_…, generated or uploaded) and instructions such as "make the background dark blue". The original is kept.

  5. POST /videos/generate

    Turns an image into a 5–10 second motion video, published as a Reel.

    Field Type
    image_id string The image to animate (img_…); 9:16 works best.
    motion_instructions string How it should move, e.g. steam rising, slow push-in.
    style string animate (default) or text_reveal (the text animates in; premium price).
    quality string standard (default) or premium.
    duration integer 5, 6 or 10 seconds.
  6. GET /generations/{id}

    The status of a generation: queued, processing, completed, partial (some images failed) or failed. When it is done, media has 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

  1. 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_available is false and only likes and comments are returned — reconnect the account to fix it. Facebook gives likes, comments and shares.

  2. GET /social-accounts/{id}/insights

    An Instagram or Facebook account over the last days (1–30, default 30): followers, period totals (Instagram), every recent post with its numbers — including posts not made with Envox (envox_post_id marks the ones that were) — the average per post and the best_post. limit (1–50) caps how many recent posts are read.

WhatsApp

  1. GET /whatsapp/numbers

    The numbers: id (use it as phone_number_id), phone_number, ai_replies (an AI agent answers incoming messages) and token_expired.

  2. GET /whatsapp/templates

    Message templates with their Meta review status (APPROVED, PENDING, REJECTED…), text, buttons and needs — how many values a send must provide. Filters: status, phone_number_id, search. POST /whatsapp/templates/sync re-reads the statuses from Meta.

  3. 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 draft can be sent to POST /whatsapp/templates as it is (add phone_number_id).

  4. 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_id string From GET /whatsapp/numbers.
    name string Lowercase with underscores, e.g. appointment_reminder.
    category string UTILITY (about an order, booking or account) or MARKETING.
    language string en, tr, de, ar, fr, es, it, nl, ru, pt_BR…
    header string Optional text, up to 60 characters, at most one {{1}}.
    body string Up to 1,024 characters with {{1}}, {{2}}… — not at the very start or end.
    footer string Optional, up to 60 characters, no variables.
    buttons object[] { "type": "QUICK_REPLY" | "URL" | "PHONE_NUMBER", "text", "url", "phone_number" }
    examples object body: one example per body variable; header, url when used.

    Envox checks Meta's rules first and answers 422 with every problem it finds. Image headers are set up in the panel.

  5. POST /whatsapp/sends

    Sends an APPROVED template 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"] }
      ]
    }
    

    header gives the header value, button the end of a link button's URL and header_image_url the 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 send id. GET /whatsapp/sends/{id} returns the counts — accepted, sent, delivered, read, failed — and every recipient's status and error.

  6. Conversations

    Endpoint
    GET /whatsapp/conversations Conversations, newest first; status (open, closed, all), phone, limit
    GET /whatsapp/conversations/{id} One conversation with its messages (from: customer, business, human, template)
    POST /whatsapp/conversations/{id}/reply Sends text as the business; takes the conversation over from the AI agent
    POST /whatsapp/conversations/{id}/release Hands 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 pending a little longer than an image.
  • Older keys: keys created before bearer keys existed still work with the X-App-Key and X-App-Secret headers.
  • Prefer talking to an AI assistant over writing code? See MCP.

Related guides