Wrap a creative
Turn a creative's URL into a Vojo Passport you can schedule.
You need the wrappers:write scope and a screen. If you're not sure what a Passport does, read Passport and wrapping.
Send the creative's URL
curl -X POST https://api.vojo-media.com/v1/wrappers \
-H "Authorization: Bearer $VOJO_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"content_source": "https://cdn.your-cms.example/creatives/77.mp4",
"content_type": "video",
"screen_id": "'"$SCREEN_ID"'",
"external_id": "creative-77",
"source": "YOUR_CMS",
"duration": 15,
"fingerprint": true,
"delivery_mode": "archive",
"metadata": { "line_item": "LI-2291" }
}'const { data: wrapper, error } = await api.POST("/v1/wrappers", {
params: { header: { "Idempotency-Key": crypto.randomUUID() } },
body: {
content_source: "https://cdn.your-cms.example/creatives/77.mp4",
content_type: "video",
screen_id: screenId,
external_id: "creative-77",
source: "YOUR_CMS",
duration: 15,
fingerprint: true,
delivery_mode: "archive",
metadata: { line_item: "LI-2291" },
square_ratio: 0.03, // The default. The client's types currently require it.
},
});
if (error) throw new VojoApiError(error);| Field | What to send |
|---|---|
content_source |
A public http(s) URL to the creative. Vojo downloads it, so you don't upload the file first. |
content_type |
video, image or html. |
screen_id |
The screen this wrapper will play on. Send it every time. |
external_id, source |
Your own creative id, and your namespace for it. You can filter plays by them later. |
fingerprint |
true to fingerprint the creative. This needs external_id, or advertisement_id if you're wrapping an existing advertisement. Send duration too, unless the advertisement already has a length. |
delivery_mode |
How you want the Passport back. See below. |
metadata |
Anything you want back later. Vojo returns it unchanged and never scores it. |
Without
screen_id, the wrapper's plays have no screen, so a Harvester can never corroborate them. The response then carriesmeta.warnings[0].code = "screen_id_missing". Make one wrapper per creative per screen.
Choose a delivery mode
inlineis the default, and returns the Passport HTML indata.html. You get it only in this response:GET /v1/wrappers/{wrapper_id}returnshtmlasnull, and so does an idempotent replay.archivestores a zip and returnsdata.url. Choose this if you might need the file again.
Handle both outcomes
Today a wrap always completes within the request and returns 201 with status: "ready". The contract also allows 202 with status: "processing", so build for it now. When you get 202, poll GET /v1/wrappers/{wrapper_id}, honouring Retry-After, until the status is ready or failed.
If Vojo can't fetch the creative, the response is 422 with errors[0].code set to creative_fetch_failed or creative_not_found, and the pointer /content_source.
Wrapping is limited to 30 requests a minute per key.
Play it unmodified
Schedule the Passport (the inline HTML, or the archive's index.html) in place of the raw creative, for the creative's full slot. Don't edit, re-encode, crop or overlay it.
Next: receive webhooks as your plays come in.