REST API · Creatives
Create uploads
Signed upload URLs for files on the caller's machine (PUT each file, then POST /uploads/confirm)
POSThttps://api.apogee.ad/api/v1/uploads
What it does
For a Meta, TikTok or Snapchat launch: ad_account_id is the account the files are for (GET /ad-accounts?platform=…). Up to 50 files per call, 500 MB per file; the URLs are valid 1 hour and never stored (an Idempotency-Key is accepted, nothing is replayed). Each file's size is required: an Apogee account may ask for 2000 files and 100 GB a day through the API and the MCP (429 rate_limited past it).
Request
POST /uploads on https://api.apogee.ad/api/v1.
Headers
-
Authorizationstring header requiredBearer apk_…: an API key with the scope of this route. -
Idempotency-Keystring header optionalAccepted and checked, never replayed (signed URLs are not stored).
-
Content-Typestring header requiredapplication/json
Body
-
ad_account_idstring requiredAd account id: Meta act_…, a TikTok advertiser id or a Snapchat ad account id (GET /ad-accounts?platform=…)
-
filesarray of objects requiredFields of each item (3)
-
namestring requiredFile name with its extension
-
sizeinteger requiredBytes (the daily upload budget counts them)
-
mime_typestring optional
-
Response
201.
-
filesarray of objectsFields of each item (8)
-
namestring -
upload_urlstring (uri) -
methodstring -
headersmap -
pathstring -
refstring -
expires_atstring (date-time) -
errorstring
-
Every answer carries X-Request-Id (give it to support), Apogee-Version: 2026-10-06, and the RateLimit and RateLimit-Policy headers; a replayed answer also carries Idempotent-Replayed: true.
Errors
Errors are application/problem+json with a stable code to switch on (all the codes).
| Status | Possible codes |
|---|---|
| 400 Bad request | idempotency_key_required, not_supported, request_refused, validation_failed |
| 401 Unauthorized | invalid_api_key |
| 403 Forbidden | account_not_connected, forbidden, insufficient_scope, meta_permission_denied, platform_permission_denied, upgrade_required |
| 404 Not found | not_found |
| 409 Conflict | action_already_ran, idempotency_in_progress, plan_already_launched |
| 422 Unprocessable content | budget_above_cap, idempotency_key_reused, launch_refused, missing_answers |
| 429 Too many requests | daily_read_cap, meta_rate_limited, platform_rate_limited, quota_exceeded, rate_limited |
| 500 Internal server error | internal_error |
Example
With your key in APOGEE_API_KEY (create one):
curl -X POST 'https://api.apogee.ad/api/v1/uploads' \
-H "Authorization: Bearer $APOGEE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ad_account_id": "act_1234567890",
"files": [
{
"name": "NORDLICHT_RAIN_HOOK1_9x16.mp4",
"size": 48213112,
"mime_type": "video/mp4"
}
]
}' {
"files": [
{
"name": "Nordlicht | Spring launch",
"upload_url": "https://www.example.com/products/nordlicht-jacket",
"method": "PUT",
"headers": {
"key": "120200000000000001"
},
"path": "120200000000000001",
"ref": "120200000000000001",
"expires_at": "2026-10-23T09:00:00.000Z",
"error": "120200000000000001"
}
]
} Access and cost
| Plans | Pro and Scale. |
|---|---|
| Scope | launch (scopes). |
| Credits | Free up to the daily free reads (5,000 a day on Pro, 10,000 on Scale), then 1 credit per read. A request that fails costs nothing, a replayed one neither (credits). |
| Rate limit | Write: 120 per 15 minutes on Pro, 240 on Scale (rate limits). |
| Daily cap | Counts 2 units toward the 2,000 units one API key can use in 24 hours. |
In the MCP
An AI assistant does the same with this tool of the MCP server:
get_upload_urls: For files on your computer: one signed upload URL per file (50 per call, 500 MB per file, valid 1 hour). The assistant uploads each file with an HTTPPUT.
Related operations
- Create import:
POST /imports - Get import:
GET /imports/{id} - List drive folder:
GET /drive-folders - Confirm uploads:
POST /uploads/confirm - List TikTok posts:
GET /ad-accounts/{acc}/tiktok-posts - List TikTok music:
GET /ad-accounts/{acc}/tiktok-music - List platform templates:
GET /ad-accounts/{acc}/platform-templates