Bupple
Automate with Bupple

Automate with Bupple

Calling the API

Your first calls to the Bupple API — list your brands, search your files, run any Bupple tool price first, start a video or a design and collect it, and run an automation with your data.

The Bupple API is plain HTTPS and JSON. Every call goes to https://api.bupple.io/v1/api/… with your key in the Authorization header. The samples below are curl; any tool with an HTTP step sends the same thing. They read the key and a few ids from your shell:

export BUPPLE_API_KEY='bmcp_…'      # Account settings › Bupple API
export BRAND_ID='…'                 # from list_brands, below

1. Which brands can this key use?

Every call is for one brand, except this one.

curl -s -X POST https://api.bupple.io/v1/api/tools/list_brands \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H 'Content-Type: application/json' -d '{}'
{
  "tool": "list_brands",
  "needs_confirm": false,
  "price": null,
  "result": {
    "brands": [
      { "id": "15614c35-…", "name": "My Brand", "is_default": true, "workspace_id": "eec1f438-…", "workspace_name": "E2E Robot's Workspace" },
      { "id": "e1683780-…", "name": "Bupple", "is_default": false, "workspace_id": "eec1f438-…", "workspace_name": "E2E Robot's Workspace" }
    ]
  }
}

From now on, name the brand in the x-brand-id header (or as "brand_id" in the body). A call without one is refused with brand_required.

2. Run any tool

GET /v1/api/tools lists every tool your key may run — the same tools the Superagent and Bupple MCP use — each with its arguments as a JSON schema, paid and needs_brand.

curl -s https://api.bupple.io/v1/api/tools \
  -H "Authorization: Bearer $BUPPLE_API_KEY"

Run one with POST /v1/api/tools/<name>; the body is its arguments. Search the Media Library:

curl -s -X POST https://api.bupple.io/v1/api/tools/search_library \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H "x-brand-id: $BRAND_ID" \
  -H 'Content-Type: application/json' \
  -d '{"query":"logo"}'
{
  "tool": "search_library",
  "needs_confirm": false,
  "price": null,
  "result": {
    "total": 10,
    "files": [
      { "id": "57c81b65-…", "filename": "logo.png", "kind": "image", "status": "ready", "path": "/logo.png", "library_link": "https://app.bupple.io/storage?asset=57c81b65-…" }
    ]
  }
}

3. Paid tools say their price first

A tool that costs credits, called without "confirm": true, answers its price and spends nothing:

curl -s -X POST https://api.bupple.io/v1/api/tools/make_image \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H "x-brand-id: $BRAND_ID" \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"A flat lay of a coffee cup on a wooden desk, morning light"}'
{
  "tool": "make_image",
  "needs_confirm": true,
  "price": { "credits": 9, "direction": "at_least", "phrase": "9+ credits on Nano Banana 2.1" },
  "result": { "message": "This costs 9+ credits on Nano Banana 2.1. Nothing was spent — call again with \"confirm\": true to run it." }
}

The same call with "confirm": true in the body runs it, and the key needs Let this key spend credits. The price depends on the model and your plan, so read it from the answer rather than writing it into your workflow.

With Add files and make public links, make_share_link turns any file id into a link anyone can open — for an email, a CRM field or a LinkedIn message. It works for 30 days unless you say expires_in_days or never_expires.

curl -s -X POST https://api.bupple.io/v1/api/tools/make_share_link \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H "x-brand-id: $BRAND_ID" \
  -H 'Content-Type: application/json' \
  -d "{\"asset_id\":\"$FILE_ID\",\"expires_in_days\":14}"

The answer's result is the file with its share_link — the link to hand out — and expires_at:

{
  "tool": "make_share_link",
  "result": { "asset_id": "57c81b65-…", "filename": "logo.png", "share_link": "https://…/s/…", "expires_at": "2026-11-24T22:56:10.228Z" }
}

5. Start a video or a design, and collect it

POST /v1/api/jobs starts a video ("kind": "video") or a design ("kind": "design"). arguments are what start_video or start_design take — GET /v1/api/tools lists them; the brief is request. Without "confirm": true it answers the estimate and how it is charged, and starts nothing:

curl -s -X POST https://api.bupple.io/v1/api/jobs \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H "x-brand-id: $BRAND_ID" \
  -H 'Content-Type: application/json' \
  -d '{"kind":"video","arguments":{"request":"A 20-second vertical video for Dana Lee, Head of Growth at Acme, inviting her to a 15-minute demo. Use her name and company.","aspect":"9:16","duration_sec":20}}'
{
  "tool": "start_video",
  "needs_confirm": false,
  "result": {
    "started": false,
    "how_it_is_charged": "…",
    "min_credits_to_start": 500,
    "credits_available": 5402,
    "enough_credits_to_start": true,
    "next": "Nothing was started. …"
  }
}

Send the same body with "confirm": true beside kind to start it; the answer carries the job's job_id. Then:

# Where it is
curl -s https://api.bupple.io/v1/api/jobs/$JOB_ID \
  -H "Authorization: Bearer $BUPPLE_API_KEY" -H "x-brand-id: $BRAND_ID"

# Its files, once it is finished — each with a library link
curl -s https://api.bupple.io/v1/api/jobs/$JOB_ID/result \
  -H "Authorization: Bearer $BUPPLE_API_KEY" -H "x-brand-id: $BRAND_ID"
{
  "tool": "collect_job",
  "result": {
    "job_id": "vsj_50bf88f8868b4abab34c1a0d",
    "kind": "video",
    "ready": true,
    "files": [
      { "asset_id": "00c8d18b-…", "kind": "video", "duration_sec": 15, "download_url": "https://…", "library_link": "https://app.bupple.io/storage?asset=00c8d18b-…" }
    ],
    "credits_charged": 352
  }
}

library_link is the file's page in Bupple, for your team. download_url is the file itself and works for a short while — to hand the video to somebody outside, make a public link from its asset_id.

A video takes minutes, not seconds: ask where it is every minute or two, or let a webhook on A video or design is finished tell your tool.

6. Run an automation with your data

List the brand's automations — each with its id, status and what starts it:

curl -s https://api.bupple.io/v1/api/automations \
  -H "Authorization: Bearer $BUPPLE_API_KEY" -H "x-brand-id: $BRAND_ID"
{
  "automations": [
    { "id": "wf_9600e55c87dc4e3890ff", "name": "CRM Lead Welcome Note", "brand_id": "e1683780-…", "status": "active", "trigger": "start_link" }
  ]
}

Start one run now. input is any JSON object — a lead, a row, a form — up to 16,000 characters; every step gets it as data. Send an Idempotency-Key (a lead's id, a row's id) and a retry of the same call answers the same run instead of starting a second:

curl -s -X POST https://api.bupple.io/v1/api/automations/$AUTOMATION_ID/runs \
  -H "Authorization: Bearer $BUPPLE_API_KEY" \
  -H "x-brand-id: $BRAND_ID" \
  -H 'Idempotency-Key: lead-2001' \
  -H 'Content-Type: application/json' \
  -d '{"input":{"first_name":"Priya","company":"Globex","asked_about":"video for product launches"}}'

The answer is 201 with the run, or 200 with the same run when that Idempotency-Key already started it. Read the run until finished is true:

curl -s https://api.bupple.io/v1/api/runs/$RUN_ID \
  -H "Authorization: Bearer $BUPPLE_API_KEY" -H "x-brand-id: $BRAND_ID"
{
  "run": {
    "id": "wfr_0b854f8dfc3f4d6da65b",
    "automation_name": "CRM Lead Welcome Note",
    "status": "succeeded",
    "finished": true,
    "credits_used": 8,
    "drafts": ["Hi Priya, thanks for reaching out from Globex! We'd love to share how you can easily create high-impact video for product launches to make your upcoming releases a huge success."],
    "results": [{ "kind": "draft", "words": "CRM welcome note for Priya at Globex" }],
    "input": { "first_name": "Priya", "company": "Globex", "asked_about": "video for product launches" }
  }
}

drafts are the finished drafts in full; results are what it made — files, posts and links, each with its kind and, for a file, its id and link.

Limits

Each key, and each address calling the API, may make a limited number of calls a minute. Over it, the answer is 429 with a Retry-After header — wait that many seconds. A tool's own step for retrying on 429 is the right fix.

  • API reference — every route, its parameters and its answers.
  • Start links — the same automation run, from a tool that cannot hold a key.