Creative uploads
Upload an image once and reference its owner-bound file ID.
Initialize the upload
Use a live campaigns:write key. PNG, JPEG, and WebP images up to 10 MiB are accepted. The uploaded creative is public media, so upload only material the owner intends to advertise.
curl "$BASE_URL/api/v1/assets" \
-H "Authorization: Bearer $MR_API_KEY" \
-H 'Idempotency-Key: launch-image-001' \
-H 'Content-Type: application/json' \
-d '{"filename":"launch.png"}'
The response contains data.file_id, upload_url, upload_headers, max_bytes, and complete_url. The upload_url is a temporary signed destination. Treat it as a secret capability and never send it to unrelated services. Preserve the same idempotency key on uncertain initialization.
Transfer and complete
PUT the raw image bytes to the returned HTTPS upload_url, using exactly the returned upload_headers. Do not attach your MarketingRouter bearer token to this storage request. The JSON API's 16 KiB body limit does not apply to this direct upload.
Then POST /api/v1/assets/{file_id}/complete with your MarketingRouter bearer token. upload_pending means processing has not finished: retry completion with backoff. Successful completion verifies the provider file, MIME type, size, HTTPS preview URL, and workspace ownership before marking it ready.
Only a ready file can be used in a live campaign. GET /api/v1/assets requires campaigns:read and lists your files with preview_url and upload_status. There is a 100-upload workspace limit. Upload initialization retries expire after 23 hours; an expired signed URL needs a new upload.
Creative review
The owner sees the exact image, headline, primary text, destination, schedule, geography, and budget before approval. Whop and Meta still review the ad after submission. A verified upload does not certify ad-policy compliance. No AI image generation or automatic creative replacement occurs.