Carvr Public API Reference (Beta)

Bearer-token HTTP API reference for the Carvr public API — authentication, endpoints, and code examples for automating Figma-to-Klaviyo template creation.

Beta. This API is available today for anyone with a Carvr account, but endpoints and response shapes may still change before a stable release is announced.

What This API Does

The Carvr public API lets you drive the same Figma-to-Klaviyo pipeline the web app and Figma plugin use, from your own code or automation — connect brands, analyze an email design image, get slice positions back, and push the finished sections to Klaviyo as a template. Call it from any HTTP client.

Getting an API Token

  1. Go to your Profile and find API Tokens for AI Tools.
  2. Give it a name and, optionally, scope it to one or more brands.
  3. Copy the token immediately — it's shown once and can't be retrieved again.

Only account owners and admins can create or revoke tokens. Anyone on the account can see that tokens exist, but not their raw values.

Authentication

Send the token as a bearer token on every request:

Authorization: Bearer carvr_live_...

Requests without a valid token return 401. A request for a brand the token isn't scoped to returns 403. These are real HTTP status codes — unlike the rest of the Carvr backend (which always returns 200 with a success flag in the body), this API follows normal REST conventions since it's meant for external tools.

Endpoints

GET /api-list-brands

Lists the brands your token can access.

curl "https://nvowpqdlcusmkbyrtyhr.supabase.co/functions/v1/api-list-brands" \
  -H "Authorization: Bearer carvr_live_..."

POST /api-create-brand

Creates a brand from a Klaviyo private API key (pk_...) — the API-only alternative to the interactive OAuth connect flow, for systems that already store their clients' Klaviyo keys and add brands programmatically. The key is validated against Klaviyo before anything is created (it needs the accounts:read scope, which full-access keys have), and the brand is named and URL'd from the Klaviyo account automatically — pass name / websiteUrl only to override that.

curl -X POST "https://nvowpqdlcusmkbyrtyhr.supabase.co/functions/v1/api-create-brand" \
  -H "Authorization: Bearer carvr_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "apiKey": "pk_..." }'

Returns 201 with the new brand (use its id as brandId in create-template calls). Safe to retry: POSTing a key that's already on one of your account's brands returns that existing brand with 200 and created: false instead of a duplicate. An invalid or rejected key is 400. Brand-scoped tokens can't call this endpoint (403) — creating brands takes an unscoped token, since it grows the very brand list a scoped token is limited to.

GET /api-get-account-status

Returns your plan tier and remaining upload credits for the current billing period.

curl "https://nvowpqdlcusmkbyrtyhr.supabase.co/functions/v1/api-get-account-status" \
  -H "Authorization: Bearer carvr_live_..."

POST /api-analyze-email-design

Upload a raw image (send it as the request body, with a Content-Type: image/* header — not multipart form data). Returns suggested slice positions using the same AI-guided algorithm as the Figma plugin, with an automatic fallback to a simpler pixel-based algorithm if the AI pass is unavailable.

curl -X POST "https://nvowpqdlcusmkbyrtyhr.supabase.co/functions/v1/api-analyze-email-design" \
  -H "Authorization: Bearer carvr_live_..." \
  -H "Content-Type: image/png" \
  --data-binary "@design.png"

The response includes storagePath, width/height, and positionspercentages from 0–100 down the image's height, not pixel Y-coordinates (e.g. 33.3 means one-third of the way down). Crop the image into positions.length + 1 sections yourself before calling create-template below. Pass the same storagePath through to create-template so this upload has a real reference for your account's upload history.

It also includes previewUrl — the same image with the computed slice lines drawn on it and numbered, so a human can approve the cuts (e.g. inside a PM tool, before an automation proceeds to create-template and spends a credit) without needing to render anything themselves. previewUrl is null if the preview couldn't be generated or saved — that's non-fatal and never fails the request; check for a warning field when it happens.

POST /api-create-klaviyo-template

Uploads your already-cropped sections to Klaviyo and creates a template. This is the step that actually bills a credit and requires the brand to have a connected Klaviyo API key.

curl -X POST "https://nvowpqdlcusmkbyrtyhr.supabase.co/functions/v1/api-create-klaviyo-template" \
  -H "Authorization: Bearer carvr_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "brandId": "your-brand-id",
    "templateName": "My template",
    "width": 600,
    "height": 1200,
    "positions": [33.3],
    "storagePath": "api/.../....png",
    "sections": [
      { "imageBase64": "...", "contentType": "image/png", "altText": "Hero" },
      { "imageBase64": "...", "contentType": "image/png", "altText": "Footer" }
    ]
  }'

sections.length must equal positions.length + 1. On success you get back a templateId you can open directly in Klaviyo. Pass the storagePath from a prior analyze call if you have one (optional) — it's used as the reference image for this upload in your history. If you sliced with your own logic and never called analyze, omit it; the first section is used as a stand-in instead.

Each section's altText is optional — leave it out (or send an empty string) and Carvr generates it for you with the same AI-vision pipeline the Figma plugin uses, in parallel with that section's upload so it costs no extra time. Supply your own if you want exact control instead.

Error Responses

Every error follows the same shape:

{ "success": false, "error": { "type": "validation_error", "message": "..." } }
  • 401 auth_error — missing, invalid, or revoked token.
  • 403 auth_error — token isn't scoped to the requested brand.
  • 400 validation_error — missing/malformed fields.
  • 402 — plan's upload credits are exhausted.
  • 429 — rate limit exceeded for this token.

Rate Limits

Tokens are rate-limited per account to keep the API stable for everyone. If you hit the limit you'll get a 429 — back off and retry after a short delay.

Try It

Frequently Asked Questions

Does calling the API use my normal upload credits?

Yes. An API-created template counts the same as a plugin or web app upload against your plan's monthly credit allowance — there is no separate quota.

Can one token access every brand on my account?

By default, yes — a token created with no brands selected can act on any brand your account owns. You can scope a token to specific brands when you create it in Profile → API Tokens, which is recommended for tokens handed to a third-party tool.

What happens if I lose my token?

Tokens are shown once, at creation, and are stored hashed — Carvr cannot show it to you again. Revoke the lost token from Profile → API Tokens and create a new one.

Is this API stable enough to build on?

It is early — endpoints, response shapes, and rate limits may still change before a stable v1 is announced. Treat it as a preview: useful for internal automations and experimentation today, not yet guaranteed to be backward compatible.