REST API reference

The upload.ad REST API (v1) lets you upload creatives to your Meta and TikTok ad accounts, track upload jobs, and manage ad copy variants from any language that can make HTTPS requests.

Base URL: https://upload.ad

The reference is organized by resource:

  • Uploads: send files and track the jobs that push them to your ad platforms
  • Creatives: the files in your library
  • Copy variants: ad texts attached to each creative
  • Webhooks: signed events when an upload completes or fails

The API is also described by an OpenAPI specification.

Conventions

Authentication. Create an API key at upload.ad/dashboard/settings/api-keys and send it on every request. API access requires an active subscription: keys can only be created on a paid plan, and requests return 402 if the plan lapses.

A key is bound to the workspace that was active when it was created and acts with its creator's permissions in that workspace. Requests return 403 when the key's creator lacks the permission for an action. Workspace owners and admins can see and revoke every key bound to their workspace.

Authorization: Bearer ua_live_...

Format. Requests and responses are JSON, except POST /api/v1/uploads, which takes multipart/form-data. Timestamps are ISO 8601 strings in UTC.

Errors. Errors return a 4xx or 5xx status with a JSON body:

json
{ "message": "Description of the problem" }
StatusMeaning
400Malformed request body or parameters
401Missing or invalid API key
402An active subscription is required
404Resource not found, or not visible to your account
409The resource is not in a state that allows the operation

Account

GET/api/v1/me

Returns the authenticated account. Useful as a connectivity and key check.

cURL
curl https://upload.ad/api/v1/me \
  -H "Authorization: Bearer $UPLOADAD_API_KEY"
JavaScript
const res = await fetch('https://upload.ad/api/v1/me', {
	headers: { Authorization: `Bearer ${process.env.UPLOADAD_API_KEY}` }
});
const { account } = await res.json();
Python
import os, requests

res = requests.get(
    "https://upload.ad/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['UPLOADAD_API_KEY']}"},
)
account = res.json()["account"]
PHP
<?php
$ch = curl_init('https://upload.ad/api/v1/me');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . getenv('UPLOADAD_API_KEY')]);
$account = json_decode(curl_exec($ch), true)['account'];
curl_close($ch);
Go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, _ := http.NewRequest("GET", "https://upload.ad/api/v1/me", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("UPLOADAD_API_KEY"))
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
Ruby
require "net/http"
require "json"

uri = URI("https://upload.ad/api/v1/me")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['UPLOADAD_API_KEY']}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
account = JSON.parse(res.body)["account"]
Java
import java.net.URI;
import java.net.http.*;

public class Me {
	public static void main(String[] args) throws Exception {
		HttpRequest req = HttpRequest.newBuilder(URI.create("https://upload.ad/api/v1/me"))
			.header("Authorization", "Bearer " + System.getenv("UPLOADAD_API_KEY"))
			.build();
		HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
		System.out.println(res.body());
	}
}
C#
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization",
    $"Bearer {Environment.GetEnvironmentVariable("UPLOADAD_API_KEY")}");
var body = await client.GetStringAsync("https://upload.ad/api/v1/me");
Console.WriteLine(body);
json
{
	"account": {
		"id": "acc_123",
		"name": "Acme Inc",
		"email": "ads@acme.com",
		"plan": "growth",
		"credits": 240,
		"trialEndsAt": null
	}
}
FieldTypeDescription
idstringAccount id
namestringAccount name
emailstringAccount email
planstring or nullCurrent plan, null if not on a plan
creditsintegerRemaining credits
trialEndsAtstring or nullTrial end date, null when on a plan