Memes.ai Memes.ai API Beta v1 · 2026-08-16 Studio ↗

Betav1 endpoints are open for early integrations. Additive fields may ship before GA.

The ad-creative API for builders.

Turn a brand and an idea into finished, on-brand creative — meme ads, images, short-form video, carousels, storyboards. The same engine behind studio.memes.media, as a clean REST API. One key, one async pattern, a handful of calls to a campaign.

Studio account required. API keys are created inside an AI Studio workspace. Create a Studio account, open the Developers tab under Manage, then create a Live or Test key.

Images & memes

Brand-grounded ad images, 1–4 variants, with edits, inpaint, and reframe.

Short-form video

Text-to-video and image-to-video — animate any asset you generate.

Carousels & storyboards

Zero-credit strategy planning, then render multi-slide carousels and narrative storyboards.

Brand kits

Reusable brand profiles and URL analysis that ground every creative call.

Three ideas, and you know the whole API

One async patternEvery creative call returns a Generation you poll (or receive by webhook). You never block on a render.
One asset shapeEvery output — image, video, slide, analysis — is the same normalized Asset. Write your handling once.
One brand contextPass a brand_kit_id (or inline brand_context) to any endpoint and the output is on-brand by construction.

Quickstart

To use the API, first create or sign into an AI Studio workspace. API keys live in the Studio Developers tab.

1 · Create an account and API key

Create accountNew to Memes.ai? Create a Studio account. We'll send you into the Developers tab after signup.
Open DevelopersAlready signed in? Open Studio → Developers, or use the left sidebar: Manage → Developers.
Create keyClick Create key, give it a name like Production server or Zapier, and choose Live or Test.
Copy onceCopy the secret immediately. It starts with sk_live_ or sk_test_ and is shown only once.

2 · Generate

Every creative call is asynchronous. You get an immediate 202 with a queued job.

curl https://api.memes.media/v1/memes \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f1c9a52-0e9b-4b8d-9a1a-1f2e3d4c5b6a" \
  -d '{
    "prompt": "When the coffee finally kicks in on a Monday",
    "brand_context": { "company_name": "Dawn Roasters", "industry": "coffee" },
    "aspect_ratio": "1:1",
    "count": 2
  }'
const res = await fetch("https://api.memes.media/v1/memes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MEMES_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    prompt: "When the coffee finally kicks in on a Monday",
    brand_context: { company_name: "Dawn Roasters", industry: "coffee" },
    aspect_ratio: "1:1",
    count: 2,
  }),
});
const { generation } = await res.json();
console.log(generation.id); // 7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c
import os, uuid, requests

res = requests.post(
    "https://api.memes.media/v1/memes",
    headers={
        "Authorization": f"Bearer {os.environ['MEMES_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "prompt": "When the coffee finally kicks in on a Monday",
        "brand_context": {"company_name": "Dawn Roasters", "industry": "coffee"},
        "aspect_ratio": "1:1",
        "count": 2,
    },
)
generation = res.json()["generation"]
print(generation["id"])  # 7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c

3 · Poll for the result

Poll the unified Generations endpoint until status is terminal. In production, register a webhook instead.

curl https://api.memes.media/v1/generations/7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
{
  "generation": {
    "id": "7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c",
    "type": "meme",
    "status": "succeeded",
    "model": "forge-image",
    "completed_count": 2,
    "output": [
      { "id": "8c6a1f0e-3d42-4b79-9f15-2a7c8e0d1b3f", "type": "image", "url": "https://cdn.memes.media/a1.png", "aspect_ratio": "1:1" },
      { "id": "5d9b2e71-6a43-4c80-8f12-3e7a9b0d2c4f", "type": "image", "url": "https://cdn.memes.media/a2.png", "aspect_ratio": "1:1" }
    ],
    "completed_at": "2026-06-18T17:04:41Z"
  },
  "usage": { "credits_used": 2, "credits_remaining": 478 },
  "meta": { "request_id": "req_b2c4", "livemode": true }
}

That's the entire loop: submit → poll → use output[]. It's identical for images, video, carousels, and storyboards — only the request body changes.

A complete campaign

A realistic flow: save a brand once, generate variants, then resize the winner for Stories. Watch each UUID thread into the next call — a brand_kit_id grounds the generation, and an output[].id becomes the input to the reframe.

# 1 · Save the brand once — the returned id is reusable forever
curl https://api.memes.media/v1/brand-kits \
  -H "Authorization: Bearer sk_live_YOUR_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 05c2b738-8667-4ad0-aabe-a7c61fa5b5e2" \
  -d '{ "name": "Dawn Roasters", "company_name": "Dawn Roasters",
        "website_url": "https://dawnroasters.example",
        "brand_colors": ["#3B2A1A", "#E8C39E"], "tone_of_voice": "warm, witty" }'
# -> { "brand_kit": { "id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70", ... } }

# 2 · Generate four on-brand variants
curl https://api.memes.media/v1/memes \
  -H "Authorization: Bearer sk_live_YOUR_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9b1d3e52-0e9b-4b8d-9a1a-1f2e3d4c5b6a" \
  -d '{ "prompt": "POV: cold brew the night before a deadline",
        "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70", "count": 4 }'
# -> { "generation": { "id": "7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c", "status": "queued" } }

# 3 · Poll until terminal
curl https://api.memes.media/v1/generations/7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
# -> status "succeeded", output: [ { "id": "8c6a1f0e-3d42-4b79-9f15-2a7c8e0d1b3f", ... }, ... ]

# 4 · Reframe the winner for Stories — any output asset can be reused as an input
curl https://api.memes.media/v1/images/reframe \
  -H "Authorization: Bearer sk_live_YOUR_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 62be9a8d-a5bb-4e85-b020-205018b78d0f" \
  -d '{ "image_id": "8c6a1f0e-3d42-4b79-9f15-2a7c8e0d1b3f", "aspect_ratio": "9:16" }'

From here, animate the winner into video (POST /videos/animate), or fan out a carousel from the same brand kit. Every output asset is reusable as the next call's input.

Authentication

The API authenticates with secret keys sent as a bearer token. If you do not have a key yet, create a Studio account or open Studio → Developers.

curl https://api.memes.media/v1/account \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
Live keyssk_live_ + 48 lowercase hexadecimal characters — bill and affect your live workspace.
Test keyssk_test_ + 48 lowercase hexadecimal characters — use the deterministic, provider-free integration simulator.
VisibilityThe full secret is shown once at creation. We store only a one-way hash.
RotationCreate a new key, deploy it, then revoke the old one. Revocation is immediate.

Every key belongs to a workspace. The livemode boolean on every response tells you which mode a key is in.

Test keys are intercepted before every live generator and request ledger. Their one-hour state is isolated to the exact key; they never call generation or webhook-delivery providers, spend credits or quota, or read or mutate canonical workspace resources. Simulated runs return clearly marked fixture assets and meta.simulated: true. Unsupported Brand Kit mutations return 501 test_mode_not_supported and never fall through to a live handler.

Keep keys server-side. Secret keys grant full access to a workspace's generation and billing — never embed them in browser, mobile, or other client-side code. If a key leaks, revoke it immediately. A missing or invalid key returns 401 authentication_error.

Making requests

Base URL

All requests go to https://api.memes.media/v1.

Idempotency

Every POST requires a caller-generated Idempotency-Key. Generate and retain one before the first attempt. Live operations use transactional body-fingerprinted admission: same-key/same-body retries replay safely, changed-body reuse returns 409, and an in-flight request returns 409 with Retry-After.

Webhook creation is replay-safe too. A same-key/same-body retry recovers the same endpoint and signing secret; ordinary GET requests never expose that secret or provision webhook state. Test identities are deterministic from the key, operation, body, and idempotency key.

Credits, entitlements & rate limits

Billable generation endpoints return 429 quota_exceeded when the workspace lacks credits. Live provider-backed operations, including zero-credit planning, prompt enhancement, and URL analysis, require an eligible paid workspace and return 403 plan_feature_unavailable otherwise.

Every request consumes weighted points in fixed windows across API-key, workspace, and client-IP buckets; expensive operations also hold weighted concurrency leases. Responses include RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. Rejections include Retry-After; back off with jitter for 429 rate_limited, authentication_rate_limited, concurrency_limited, and test_mode_capacity_limited.

Pagination

List endpoints are cursor-paginated and consistent everywhere.

curl "https://api.memes.media/v1/memes?limit=40&starting_after=5d9b2e71-6a43-4c80-8f12-3e7a9b0d2c4f" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
{ "data": [ /* ... */ ], "has_more": true, "next_cursor": "6e0c3f82-7b54-4d91-9a23-4f8b0c1d3e5a" }
ParamTypeDescription
limitintegerPage size, 1–100. Default 40.
starting_afterstringObject id to start after (from next_cursor).
qstringFree-text search, ≤200 chars, where supported.
orderenumnewest (default) or oldest.

The cursor is always the id of the last object in the page you received — pass it as starting_after for the next page, and stop when has_more is false.

Generations

A Generation is the single resource behind every long-running operation. Whether you render one image or a ten-slide carousel, you get a Generation and read results from it.

Lifecycle

POST /v1/<resource>          ->  202  { generation: { status: "queued" } }
GET  /v1/generations/{id}    ->  200  { generation: { status, output } }
webhook generation.completed ->  push (optional)

Status values

StatusMeaning
queuedAccepted and credits reserved; not started yet.
processingActively rendering.
succeededAll requested outputs produced.
partialSome of N outputs succeeded; unfilled credits are refunded.
failedTerminal failure; reserved credits are refunded.
canceledCanceled before completion.

succeeded, partial, failed, and canceled are terminal — stop polling once you reach one.

Credits

Credits are reserved when a job is queued and settle when it completes — you're charged only for delivered outputs, and reserved credits are refunded on failed, canceled, or the unfilled part of a partial. That's why a job reads credits_used: 0 at submit and the final figure once terminal. Every response carries a usage block: { credits_used, credits_remaining, interval, reset_at }.

Paid API plans

Your API key inherits the paid plan on the Studio workspace that created it. The standard ad-generation bucket is reported as images by GET /account/usage; video has its own monthly bucket.

PlanAd generations / rolling 30 daysVideo generations / rolling 30 days
Starter1005
Pro25015
Business50030
Elite1,00060

Need a higher monthly allowance, custom throughput, or a managed plan? Email members@memes.com.

The Generation object

{
  "id": "7b58d92a-2c3e-4f81-9a67-1d0e2f3a4b5c",
  "object": "generation",
  "type": "meme",
  "status": "succeeded",
  "model": "forge-image",
  "requested_count": 4,
  "completed_count": 4,
  "failed_count": 0,
  "output": [ /* Asset objects */ ],
  "error": null,
  "created_at": "2026-06-18T17:04:22Z",
  "completed_at": "2026-06-18T17:04:53Z"
}

type is one of meme, image, edit, reframe, video, carousel, storyboard, or remix.

The Asset object

Every output, for every endpoint, has the same shape:

{
  "id": "8c6a1f0e-3d42-4b79-9f15-2a7c8e0d1b3f",
  "type": "image",
  "url": "https://cdn.memes.media/a1.png",
  "aspect_ratio": "1:1",
  "slide_index": null,
  "parent_id": null,
  "model": "forge-image",
  "created_at": "2026-06-18T17:04:41Z"
}

type is image, video, carousel_slide, or analysis. slide_index is set for carousel slides; parent_id links edits and reframes to their source.

Endpoints

GET/generationsList jobs; filter by type and status
GET/generations/{id}Poll any job; normalized output
POST/generations/{id}/cancelCancel a queued or processing job

Poll every 2–3s and stop at the first terminal status. Images and memes typically finish in 10–30s, video in 1–4 minutes. In production, prefer a webhook.

Models

Set model to pick a model, or omit it for the smart default per endpoint. Models belong to the Forge family — each named by capability, with a faster -fast variant where one is offered.

ModelBest for
forge-imagePrimary text-to-image ad creative; reference, product, and logo conditioning. default for Images & Memes
forge-image-fastFaster, cheaper image generation — quick variants and iteration.
forge-editInstruction edits, mask inpainting, and aspect-ratio reframing.
forge-videoText-to-video and multi-reference (2–4 image) video.
forge-motionImage-to-video — animate a single existing asset.
forge-promptPrompt enhancement — rough idea to production-ready brief.
forge-planCarousel strategy planning.
forge-copy-fastFast brand/creative analysis (e.g. URL analysis).

Most endpoints pick the right model for you — you only set model to choose between forge-image and forge-image-fast. A Forge id routes to the best available engine and fails over automatically; your code references only the stable id, and we improve what's behind it without changing the contract.

Errors

The API uses conventional HTTP status codes and returns a single error envelope.

{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_request",
    "message": "Either prompt, brand_context, or reference_images is required.",
    "param": "prompt",
    "request_id": "req_8f2a1c"
  },
  "meta": { "request_id": "req_8f2a1c", "livemode": true }
}
HTTPTypeCommon codesWhen
400invalid_request_errorinvalid_request, idempotency_key_invalid, idempotency_key_requiredMalformed or missing input/retry key.
401authentication_errorinvalid_api_keyMissing, invalid, expired, or revoked key.
403permission_errorinsufficient_scope, plan_feature_unavailableKey scope or live-workspace entitlement is insufficient.
404not_found_errorresource_not_found, test_resource_not_foundUnknown live id or simulator fixture.
409conflict_erroridempotency_conflict, idempotency_key_conflict, idempotency_in_progress, brand_kit_limit_reached, webhook_endpoint_limit_reachedRetry-key conflict/in-flight state, a resource cap, or a rejected cancellation.
429quota_error / rate_limit_errorquota_exceeded, rate_limited, authentication_rate_limited, concurrency_limited, test_mode_capacity_limitedCredit quota, fixed-window points, concurrency, or simulator capacity exhausted.
500api_errorinternal_error, test_mode_internal_errorUnexpected error on our side.
501test_mode_errortest_mode_not_supportedNo isolated simulator representation.
502generation_error / api_errorgeneration_failed, webhook_provider_errorA synchronous dependency request failed.
503service/admission errortemporarily_unavailable, webhook_provider_unavailable, idempotency_outcome_unknown, video_admission_unavailable, queue_fullAdmission, persistence, configuration, or capacity unavailable.

Async rendering failures appear on the generation resource as generation_failed, not as a 422 create response. Honor Retry-After for idempotency_in_progress; retry transient 503 responses with the same key and exponential backoff. Other 400409 responses require a change, and 429 quota_exceeded requires credits or a quota reset.

Webhooks

Skip polling: register an HTTPS endpoint and we'll POST a signed event when a job reaches a terminal state.

EventFires when
generation.completedA job succeeded.
generation.partialA job finished with some outputs.
generation.failedA job failed or timed out.
generation.canceledA job was canceled.

Payload

{
  "id": "evt_2x9k",
  "type": "generation.completed",
  "created_at": "2026-06-18T17:04:53Z",
  "livemode": true,
  "data": { "generation": { /* full Generation object */ } }
}

Verifying signatures

Every delivery is signed with your endpoint's secret (whsec_…, shown once) and carries svix-id, svix-timestamp, and svix-signature headers. The simplest way to verify is the official libraries — JS/TS, Python, Go, Rust, Ruby, PHP, Java, C#, and more:

import { Webhook } from "svix"; // npm install svix

const wh = new Webhook(process.env.MEMES_WEBHOOK_SECRET); // whsec_…
// Pass the RAW request body + the svix-* headers.
const event = wh.verify(rawBody, {
  "svix-id": req.headers["svix-id"],
  "svix-timestamp": req.headers["svix-timestamp"],
  "svix-signature": req.headers["svix-signature"],
}); // throws on bad signature or stale timestamp
from svix.webhooks import Webhook  # pip install svix

wh = Webhook(os.environ["MEMES_WEBHOOK_SECRET"])  # whsec_…
event = wh.verify(raw_body, {
    "svix-id": headers["svix-id"],
    "svix-timestamp": headers["svix-timestamp"],
    "svix-signature": headers["svix-signature"],
})  # raises on bad signature or stale timestamp

To verify manually: svix-signature is a space-separated list of v1,<base64> signatures, each HMAC-SHA256(secret, "{svix-id}.{svix-timestamp}.{raw_body}") over the base64 bytes after the whsec_ prefix; reject if |now − svix-timestamp| > 5 minutes. Deliveries are at-least-once — dedupe on svix-id. Failed deliveries retry with backoff for ~24h and are replayable from your webhook portal.

Managing endpoints

GET/webhooksList endpoints
POST/webhooksRegister; returns the signing secret on its idempotent creation lineage
GET/webhooks/{id}Fetch without exposing a secret or provisioning state
PATCH/webhooks/{id}Update url, events, enabled
DEL/webhooks/{id}Remove an endpoint
POST/webhooks/{id}/testSend a test event
curl https://api.memes.media/v1/webhooks \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: webhook-primary-v1" \
  -d '{
    "url": "https://example.com/hooks/memes",
    "events": ["generation.completed", "generation.failed"]
  }'

Webhook destinations must be public HTTPS. Each workspace may register at most 25 endpoints, including disabled endpoints. Creation retries with the same key and body recover the endpoint and secret; ordinary reads are side-effect free.

Images

Generate and edit ad images from a prompt, a brand context, and up to four reference images.

POST/imagesText-to-image / reference-conditioned (1–4)
POST/images/editsInstruction edit / mask inpaint
POST/images/reframeOutpaint to a new aspect ratio
GET/imagesList generated images
GET/images/{id}Fetch one image asset

Create an image

POST /images

ParamTypeDescription
promptstringone of*Creative direction, max 4,000 characters.
business_namestringoptionalBrand/business name, max 200 characters.
brand_kit_idstringone of*A saved brand kit to ground the image.
brand_contextobjectone of*Inline brand profile if you have no kit.
template_promptstringoptionalFormat/template directive, max 4,000 characters.
reference_imagesarrayoptionalUp to 4 { type, source }; type is ref/template/logo, source is an https URL or asset id.
aspect_ratioenumoptionalauto, 1:1 (default), 4:5, 3:4, 16:9, 9:16, 2:3, 3:2, 21:9, …
countintegeroptionalVariants, 1–4. Default 1.
qualityenumoptionalfast, standard (default), premium.
modelenumoptionalforge-image (default) or forge-image-fast.

* At least one of prompt, brand_kit_id/brand_context, or reference_images.

Reuse outputs as inputs. Any live UUID in output[].id (or a test asset_test_… id) can be passed as a reference, edit/reframe source, or animation source.

curl https://api.memes.media/v1/images \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: b2693cf4-1383-4dc9-8b96-8bf2ddd58ea8" \
  -d '{
    "prompt": "Minimalist product hero on a sunlit kitchen counter",
    "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70",
    "reference_images": [{ "type": "logo", "source": "https://yourcdn.example/logo.png" }],
    "aspect_ratio": "4:5",
    "count": 3
  }'

Returns 202 with a Generation (type: "image"). Credits: 1 per delivered image.

Edit & reframe

POST /images/edits returns 202. Live POST /images/reframe returns a completed generation with 200; the test simulator returns 202. Both preserve lineage through parent_id. Credits: 1 each for live work.

Memes

Memes are the flagship branded-ad format: a brand-grounded image with full edit/reframe lineage. Functionally they're Images with meme defaults plus lineage fields.

POST/memesGenerate 1–4 brand-grounded meme ads
GET/memesList memes
GET/memes/{id}Fetch one meme
GET/memes/{id}/lineageFull edit/reframe family tree
DEL/memes/{id}Soft-delete a meme

Create memes

ParamTypeDescription
promptstringone of*The joke, angle, or message, max 4,000 characters.
business_namestringoptionalBrand/business name, max 200 characters.
brand_kit_id / brand_contextstring / objectone of*Brand grounding.
template_promptstringoptionalA meme-template directive, max 4,000 characters.
reference_imagesarrayoptionalUp to 4 typed references.
aspect_ratioenumoptionalDefault 1:1.
countintegeroptional1–4. Default 1.
enhancebooleanoptionalRun prompt enhancement first.

* At least one of prompt, brand_kit_id/brand_context, template_prompt, or reference_images.

curl https://api.memes.media/v1/memes \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5884509e-3312-4547-a89c-b2773d20da3e" \
  -d '{
    "prompt": "POV: you discover cold brew the night before a deadline",
    "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70",
    "count": 4,
    "enhance": true
  }'

Returns 202 (type: "meme"). Credits: 1 per delivered variant. GET /memes/{id}/lineage returns the root plus every edit and reframe in chronological order.

Videos

Generate short-form video from text, references, or an existing image.

POST/videosText-to-video or reference-to-video
POST/videos/animateImage-to-video from an existing asset
GET/videosList video jobs
GET/videos/{id}Fetch one video
DEL/videos/{id}Delete a video (refunds credits)

Create a video

ParamTypeDescription
promptstringone of*What the video shows, max 4,000 characters.
business_namestringoptionalBrand/business name, max 200 characters.
business_urlstringone of*A website to ground the concept, max 2,048 characters.
brand_kit_id / brand_contextstring / objectone of*Brand grounding.
reference_imagesarrayoptionalUp to 4 ref/logo items; public HTTPS or owned asset id only. No data URIs or templates.
aspect_ratioenumoptional16:9 (default), 9:16, 1:1, 4:3, 3:4, …
durationintegeroptionalSeconds, 1–15. Default 5.
resolutionenumoptional480p or 720p (default).

The model (forge-video or forge-motion) is selected automatically from your inputs.

curl https://api.memes.media/v1/videos \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: c733a729-4050-4b3b-97d4-431056e865ab" \
  -d '{
    "prompt": "A latte poured in slow motion, steam rising, warm morning light",
    "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70",
    "aspect_ratio": "9:16",
    "duration": 6
  }'

Returns 202 (type: "video"). Credits: 10 per completed video. Video takes 1–4 minutes — use a webhook. POST /videos/animate takes an image_id and runs at 5s / 720p with forge-motion.

Carousels

Two steps by design: a zero-credit strategy plan, then a billable render that fans out one image per slide. Both live calls require paid API entitlement.

POST/carousels/planSlide strategy (no images, zero credits)
POST/carouselsRender: fan out N slide jobs
GET/carouselsList carousel sets
GET/carousels/{id}Set + per-slide status and URLs
DEL/carousels/{id}Soft-delete a set

Plan a carousel

ParamTypeDescription
briefstringrequiredWhat the carousel should accomplish, ≤4000 chars.
goalenumoptionalawareness, leads (default), sales, followers, engagement.
platformenumoptionalig-portrait (default), ig-square, linkedin, tiktok.
slide_countintegeroptional3–10. Default 5.
brand_kit_id / brand_contextstring / objectoptionalBrand grounding.
curl https://api.memes.media/v1/carousels/plan \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4859f5ac-04fe-4790-8437-cce026a4bff8" \
  -d '{
    "brief": "5 myths about cold brew, debunked, for first-time buyers",
    "goal": "leads",
    "platform": "ig-portrait",
    "slide_count": 5,
    "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70"
  }'
{
  "plan_id": "9e2b7c41-5d8a-4f30-b6c9-1a7e3d5f8b20",
  "plan": {
    "id": "9e2b7c41-5d8a-4f30-b6c9-1a7e3d5f8b20",
    "concept_title": "Cold Brew Myths, Busted",
    "viral_mechanic": "myth/fact reveal",
    "cta": "Try the starter kit",
    "slides": [
      { "slide_index": 0, "role": "hook", "on_image_text": "5 cold brew myths" }
    ]
  },
  "model": "forge-plan",
  "meta": { "request_id": "req_b2c4f9", "livemode": true }
}

Planning returns 200 synchronously and uses zero credits. Render with the returned plan_id or a bounded inline plan (3–10 slides, at most 128 KiB); POST /carousels returns a 202 carousel envelope. Credits: 1 × slide_count.

Storyboards

A storyboard is a single composite 3–4 panel narrative ad image (not a fan-out).

POST/storyboardsGenerate one multi-panel storyboard
ParamTypeDescription
goalstringone of*What the story should land, max 4,000 characters.
business_namestringoptionalBrand/business name, max 200 characters.
brand_kit_id / brand_contextstring / objectone of*Brand grounding.
presetenumoptionalauto, problem-solution, before-after, how-it-works, customer-journey, testimonial-sequence, founder-story.
panel_countintegeroptional3 or 4. Default 3.
aspect_ratioenumoptional16:9, 9:16, 1:1.
visual_styleenumoptionalcomic-strip or clean-storyboard.
toneenumoptionalNarrative tone, e.g. playful, bold, warm, professional.
text_densityenumoptionalminimal, balanced, rich.
product_roleenumoptionalHow prominently the product features.
reference_imagesarrayoptionalUp to 4 typed references.

* At least one of goal or brand_kit_id / brand_context.

curl https://api.memes.media/v1/storyboards \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8b4e6d20-9c31-47fa-a2d5-1e7f3b8c6a40" \
  -d '{
    "goal": "Show how cold brew goes from beans to glass in 3 steps",
    "brand_kit_id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70",
    "preset": "how-it-works",
    "panel_count": 3
  }'

Returns 202 (type: "storyboard"). Credits: 4.

Brand Kits

Reusable brand profiles that ground generation. Persistence uses zero credits; public API creation is rejected once a workspace has 50 total Brand Kits.

GET/brand-kitsList kits
POST/brand-kitsCreate a kit
GET/brand-kits/{id}Fetch a kit
PATCH/brand-kits/{id}Partial update
DEL/brand-kits/{id}Delete a kit
POST/brand-kits/{id}/logoUpload or replace the logo
DEL/brand-kits/{id}/logoRemove the logo
POST/brand-kits/{id}/product-referencesAdd a product reference (max 5)
DEL/brand-kits/{id}/product-references/{ref_id}Remove a product reference
POST/brand-kits/{id}/set-defaultMark the default kit
POST/brand-kits/analyze-urlExtract a profile from a URL (no save)

No public brand-audit endpoint in v1. analyze-url only extracts brand-kit profile fields; it does not create or publish brand audit reports.

Create a brand kit

ParamTypeDescription
namestringrequiredA label for the kit.
company_namestringoptionalBrand name.
website_urlstringoptionalBrand site.
brand_colorsstring[]optionalHex colors.
tone_of_voicestringoptionalVoice description.
target_audiencestringoptionalAudience description.
website_contextstringoptionalPositioning notes.
industrystringoptionalIndustry.
auto_attach_product_referencesbooleanoptionalAuto-pull product images from the site. Default true.
curl https://api.memes.media/v1/brand-kits \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 652c1f3c-4ee0-47dc-971e-858615a4be4f" \
  -d '{
    "name": "Dawn Roasters",
    "company_name": "Dawn Roasters",
    "website_url": "https://dawnroasters.example",
    "brand_colors": ["#3B2A1A", "#E8C39E"],
    "tone_of_voice": "warm, witty, unpretentious"
  }'
{
  "brand_kit": {
    "id": "3a9f6d20-4c7b-4e18-9d52-6f1a8b3c5e70",
    "object": "brand_kit",
    "name": "Dawn Roasters",
    "is_default": false,
    "created_at": "2026-06-18T17:00:00Z"
  }
}

The returned id is what you pass as brand_kit_id everywhere else. POST /brand-kits/analyze-url with { "url": "https://…" } returns an extracted profile without saving it — great for pre-filling a kit, not for running a public audit. Synchronous 200.

Prompt Enhancement

Turn a rough idea into a polished, production-ready creative prompt.

POST/prompts/enhanceRough idea → polished image prompt
curl https://api.memes.media/v1/prompts/enhance \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 30b652c3-4af8-445f-8266-e24d07f392e9" \
  -d '{ "prompt": "funny ad about mondays and coffee", "website_url": "https://dawnroasters.example" }'
{
  "enhanced_prompt": "A weary office worker slumped at a desk Monday morning, transformed mid-sip...",
  "original_prompt": "funny ad about mondays and coffee",
  "model": "forge-prompt"
}

Synchronous 200. Pass has_logo, has_reference_image, and aspect_ratio to tailor the result to your intended render.

Images as inputs

Pass an https URL, data URI, or workspace asset id as a reference or edit source; the API validates and normalizes it server-side. Edit masks also accept a data URI.

https URLYour own hosted asset URL, or any public image URL.
workspace asset idAny live UUID from a previous generation's output[], or a test asset_test_… id.
"reference_images": [
  { "type": "logo", "source": "https://yourcdn.example/logo.png" },
  { "type": "ref",  "source": "5a7e2d91-8b44-4f30-a6c2-1d9e7b3f5a80" }
]

Video inputs are stricter: use a public HTTPS URL or owned workspace asset id with ref or logo; data URIs and templates are rejected.

Account & Usage

Read your workspace's plan and current consumption.

GET/accountWorkspace, plan, key prefix, livemode
GET/account/usageCredit consumption + quota by interval
curl https://api.memes.media/v1/account/usage \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
{
  "plan": "pro",
  "credits_remaining": 480,
  "intervals": {
    "images": { "limit": 1000, "used": 520, "remaining": 480, "interval": "rolling_30_days", "reset_at": "2026-07-01T00:00:00Z" },
    "video":  { "limit": 50,   "used": 4,   "remaining": 46,  "interval": "rolling_30_days", "reset_at": "2026-07-01T00:00:00Z" }
  }
}

SDKs & MCP

TypeScript & Python SDKs soon

Typed clients with automatic retries, idempotency, and a webhook-signature helper.

MCP server soon

Every operation as a Model Context Protocol tool — generate_meme, generate_video, plan_carousel, get_generation — so agents can build campaigns directly.

Until the SDKs ship, the API is plain REST — any HTTP client works. Want early access to a key, an SDK, or the MCP server? Email members@memes.com.

Cookbook

Real things you can build with the API — point your Shopify, Google Sheet, or Notion catalog at it, spin up Meta creative tests, animate Reels. Pick a card for the exact setup. These are starting points for inspiration, not a limit — building something or have a wild integration in mind? We'd love to help or just hear about it: members@memes.com. Also as plain Markdown.

© 2026 Memes.ai · Built on studio.memes.media Back to top ↑
Copied