Skip to content
Get your keyGet a key

Reference · Ads

POST/ugc-ads

Make a UGC video ad: presenters, product, voice and captions

Make one UGC ad video as the UGC Ads page makes it: the words — what happens, and what is said, in quotes — and whatever it is made from: presenters (someone from their cast, or a character they bring as pictures), the product (from GET /api/v1/products, and/or pictures of it), other pictures, a video to look like, a voice for each presenter. Only the words are needed. Every picture, video and recording goes in as a storage key or an https link to the file, brought into their Uploads first. Name what is added in the words by its tag: @Presenter1…, @Product1…, @Image1…, @Video1, @Audio1… (sounds in order). For N ads, call it N times, each with a new Idempotency-Key; takes makes several takes of one ad. A new ad starts as a fresh UGC Ads bar does: no captions and no "AI-generated" label; ask for captions (captionStyle) or the label (aiLabel) when the person wants them, and set the captions' size (captionSize) and place (captionPosition) as the Captions panel does. Video models: GET /api/v1/models (studio "ugc"). The quote gives the page’s notes — the parts a long script is made in, a line that reads like a testimonial, words that will not fit — which are said, not stops. It comes back as a job (kind "ugc") to follow with GET /api/v1/jobs/{jobId}.

Key needs
create · Make things and spend credits
Answers
A job to follow
Request
curl -X POST https://vessero.com/api/v1/ugc-ads \
  -H "Authorization: Bearer $VESSERO_API_KEY" \
  -H "Idempotency-Key: 47f8f6f5-ea00-4fb1-925f-76aac956a0ec" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "@Presenter1 holds @Product1 up to the camera in @Image1 and says: “This serum has fifteen percent vitamin C, and it is light enough to wear under make-up.”",
    "videoModel": "seedance-2.5",
    "presenters": [
      {
        "kind": "pictures",
        "pictureKeys": [
          "https://example.com/people/zola.jpg"
        ],
        "whoIsIn": {
          "kind": "no-person"
        },
        "name": "Zola"
      }
    ],
    "productId": "5e4d3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b",
    "pictureKeys": [
      "https://example.com/sets/sunny-kitchen.jpg"
    ],
    "aspect": "9:16",
    "captionStyle": "word-pop",
    "confirmCredits": 194,
    "webhookUrl": "https://example.com/hooks/vessero"
  }'
Response202 Accepted
{
  "object": "job",
  "id": "ugc.8f1c2d3e-4b5a-4789-8abc-def012345678",
  "kind": "ugc",
  "status": "working",
  "stage": "Queued",
  "files": [],
  "credits": 58,
  "url": "/api/v1/jobs/ugc.8f1c2d3e-4b5a-4789-8abc-def012345678"
}
POST/ugc-ads/quoteFree

The same body without confirmCredits. It answers the price and your balance, and runs nothing.

Header

  • Idempotency-KeystringYour id for this request: 8–64 letters, digits, - or _. A repeat within 10 minutes gets the first answer back and never runs twice. Use the same one for the quote and the run.
  • Preferstringwait=N (up to 60): hold the answer up to N seconds while the job is made, within 80 seconds for the whole call.

Body

  • promptstringrequiredThe words: what happens, and what is said in quotes (straight or curly), naming what is added by its tag, e.g. @Presenter1 holds @Product1 up to the camera in a sunny kitchen and says: “This is the only serum I reach for.”
  • videoModelstringrequiredThe model that makes the clip: an id from GET /api/v1/models (studio "ugc").
  • presenters(object · kind cast | pictures)[] · up to 4Up to 4 people in it, @Presenter1 first: {kind: "cast", castMemberId, voice?}, or {kind: "pictures", pictureKeys, whoIsIn, name?, voice?} for a character they bring.
  • voiceobject · kind own | model | library | recordingThe voice when no presenter is added: the person the model draws speaks in it. Default: the video model’s own.
  • productIdstringThe product, from GET /api/v1/products: its card brings its name, facts and picture.
  • productPictureKeysstring[] · up to 3Up to 3 pictures of the product; with a productId, more sides of it.
  • pictureKeysstring[] · up to 3Up to 3 other pictures — a place, a prop — named @Image1… in the words.
  • lookLikeobjectA video to look like (@Video1): it goes to the model as a reference.
    • keystringrequiredThe video: a storage key from POST /api/v1/files or POST /api/v1/library/use, or an https link to the file (brought into their Uploads first).
    • durationSecnumberIts length in seconds, as GET /api/v1/library (tab "uploads") or POST /api/v1/library/use gives it. Default: read from the file.
    • whoIsInobject · kind no-person | personrequiredWho is in it, as the person says: {kind: "no-person"}, or {kind: "person", name, agreed} for a real person (named, with their permission).
  • pictureModelstring | nullThe model that draws each take’s opening picture, from GET /api/v1/models (studio "ugc", pictureModels). Default: "nano-banana-2-1". null for none: the clip takes the pictures as they are.
  • aspectstringThe shape: 9:16, 4:5, 1:1, 16:9. Default 9:16.9:164:51:116:9
  • resolutionstringA size the video model lists, e.g. "1080p". Default 720p.
  • durationSecintegerA length the video model makes, in seconds. Default: fitted to the words.
  • captionStylestringThe captions, as the Captions menu offers them: none (No captions), auto (Auto), word-pop (Word Pop), impact-slam (Impact Slam), clean-subtitle (Clean Subtitle), editorial-minimal (Editorial), luxury-serif (Luxury Serif), glass-tech (Glass Tech), marker-energy (Marker Energy), retro-collage (Retro Collage). Default none (No captions).noneautoword-popimpact-slamclean-subtitleeditorial-minimalluxury-serifglass-techmarker-energyretro-collage
  • captionSizeintegerHow big the captions are, in per cent of the style's own size, as the Captions panel's Size slider sets it: S 60, M 100, L 130, XL 160, or any whole number between. Default 100.
  • captionPositionstring | numberWhere the captions sit, as the Captions panel sets it: "top" (under the AI label when it is on), "middle", "bottom" (the default, where captions always sat), or the caption block’s centre as a share of the frame’s height, 0–1, kept inside what the platform leaves clear.
  • takesintegerTakes of this one ad, 1–4, each its own video. Default 1.
  • aiLabelbooleanThe "AI-generated" label on every frame, top left. Default false: true only if the person asks for it. Without it, they say it was made with AI where they post it.
  • confirmCreditsintegerrequiredThe price you agree to, in credits: the credits its quote gave. It runs at that price, or at a lower one when that figure was quoted for this Idempotency-Key; above the price now, nothing runs (409 price_changed). Left out, nothing runs and the error carries the quote.
  • webhookUrlstring · httpsAn https address to POST the job to once it is done or has failed, signed (see Webhooks).

Answers

  • 202jobStarted: follow the job, or wait for its webhook.
  • 200jobA job that ended at once: done, or failed (see error and charged).
  • 400confirm_credits_requiredA run that spends needs confirmCredits: the quote is in details.
  • 402insufficient_creditsThe account has too few credits for this.
  • 409price_changedThe price is above the confirmCredits sent: nothing ran; the new quote is in details.
  • 422content_refusedThe content check refused it.
  • 429daily_cap_reachedThe key’s daily credit cap would be passed: see Retry-After.
Next in AdsPOST/ugc-ads/quote