upload.ad documentation
upload.ad is the workspace between finished creative and a live ad on Meta (Facebook/Instagram) and TikTok. It holds your creative library, the review and approval workflow around it, ad copy variants, the campaigns and ads you launch from those creatives, comment moderation, performance reporting, and the automations that act on all of it. Everything below is available through the same programmatic surface as the app.
There are several ways to integrate. They all use the same API keys and expose the same data:
- REST API: a plain HTTPS API for scripts and backend services. Full endpoint reference with curl and JavaScript examples.
- CLI: the
uploadadcommand for terminals and CI pipelines. - SDK:
@uploadad/sdk, a typed TypeScript client for Node, Bun, Deno, and edge runtimes. - MCP server: lets AI agents such as Claude Code, Claude Desktop, and Cursor manage creatives and copy on your behalf.
Three more docs cover features you can drive from any of the above:
- Automations: trigger, condition, and action flows that run in the background, including loops, waits, retries, and the inbound webhook trigger.
- Notifications: in-app and channel alerts your integrations and automations can send.
- Shopify: connect a store so your ads report profit instead of platform-estimated revenue.
- Zapier, Make, and n8n: wiring upload.ad events and actions into outside automation platforms.
Paid plans only. The REST API, CLI, SDK, and MCP server are part of every paid plan; the free trial covers the app itself. You can subscribe at any time, including during the trial. A workspace without a plan is refused with 402 subscription_required (-32002 over MCP), and an agent that signs in without one is turned away at the authorization screen.
Quickstart
This walkthrough uploads a creative with curl and polls it to completion. It takes about two minutes.
1. Create an API key
Create a key at upload.ad/dashboard/settings/api-keys. The key is shown once at creation, so store it securely. Then export it in your shell:
export UPLOADAD_API_KEY="ua_live_..."2. Upload a creative
Send one or more files as multipart/form-data:
curl -X POST https://upload.ad/api/v1/uploads \
-H "Authorization: Bearer $UPLOADAD_API_KEY" \
-F "files=@banner.png"The response returns immediately with an upload id. Processing happens in the background:
{ "uploads": [{ "id": "up_1", "status": "processing" }] }3. Poll until it finishes
Fetch the upload until its status is completed or failed:
curl https://upload.ad/api/v1/uploads/up_1 \
-H "Authorization: Bearer $UPLOADAD_API_KEY"{
"upload": {
"id": "up_1",
"fileName": "banner.png",
"kind": "image",
"status": "completed",
"facebook": { "imageHash": "a1b2c3...", "videoId": null },
"createdAt": "2026-07-09T10:15:00.000Z"
}
}A completed image upload carries the Graph API imageHash, and a completed video upload carries the videoId. Both are ready to reference when you create ads through the Graph API.
4. Attach ad copy
Once processing completes, the file appears in your creative library. List creatives to find its id, then save a copy variant:
curl -X POST https://upload.ad/api/v1/creatives/cr_1/copy \
-H "Authorization: Bearer $UPLOADAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "headline": "Summer sale", "primaryText": "Save 20% this week only.", "label": "variant-a" }'From here, the REST API reference covers every endpoint, or you can do the same from the terminal with the CLI.
Authentication
Every request is authenticated with an API key sent as a Bearer token:
Authorization: Bearer ua_live_...Keys are created and revoked at upload.ad/dashboard/settings/api-keys. Requests with a missing or invalid key return 401 with a JSON error body. Treat keys like passwords: keep them out of source control and pass them through environment variables or a secret manager.
The free trial covers the app only. Programmatic access (API keys, CLI, MCP, and the SDK) requires a paid plan: keys can only be created on a paid plan, and requests return 402 with the code subscription_required if the plan lapses.
Base URL and format
The base URL for all endpoints is https://upload.ad. Requests and responses are JSON, except file uploads, which use multipart/form-data. Errors return a 4xx or 5xx status with a body of the form:
{ "error": { "code": "not_found", "message": "Description of the problem" } }The REST API reference lists every error code.