SDK

@uploadad/sdk is a typed TypeScript client for the upload.ad REST API. It has zero runtime dependencies and works anywhere fetch is available: Node 18+, Bun, Deno, Cloudflare Workers, and other edge runtimes.

Install

bash
npm install @uploadad/sdk

bun works too: bun add @uploadad/sdk.

Authentication

Create a client with an API key (create one at upload.ad/dashboard/settings/api-keys):

ts
import { UploadAd } from '@uploadad/sdk';

const client = new UploadAd({ apiKey: 'ua_live_...' });

If you omit apiKey, the client reads the UPLOADAD_API_KEY environment variable. Check who you are authenticated as:

ts
const account = await client.me();
console.log(account.email, account.credits);

Uploading creatives

uploads.create accepts one or more files as a Blob, ArrayBuffer, or Uint8Array:

ts
import { readFile } from 'node:fs/promises';

const data = await readFile('banner.png');
const [job] = await client.uploads.create([{ name: 'banner.png', data, type: 'image/png' }]);

Uploads process in the background. Use waitFor to poll until a job reaches a terminal state:

ts
const upload = await client.uploads.waitFor(job.id);
if (upload.status === 'completed') {
	console.log(upload.facebook.imageHash);
}

waitFor polls every 3 seconds by default; pass { intervalMs, timeoutMs } to tune it. The same limits apply as in the API: up to 25 files per call, images up to 30 MB, videos up to 200 MB.

Managing upload jobs

ts
const uploads = await client.uploads.list({ limit: 20 });
const upload = await client.uploads.get('up_...');
await client.uploads.retry('up_...'); // retry a failed upload
await client.uploads.dismiss('up_...'); // remove it from the list

Creatives and copy variants

ts
const creatives = await client.creatives.list();
await client.creatives.delete(['cr_a', 'cr_b']);

const copies = await client.copy.list('cr_a');
const copyId = await client.copy.save('cr_a', {
	headline: 'Summer sale',
	primaryText: 'Up to 40% off this week only.'
});
await client.copy.save('cr_a', { id: copyId, label: 'variant-b' }); // update
await client.copy.delete('cr_a', copyId);

Verifying webhooks

Use verifyWebhookSignature to authenticate webhook deliveries. Pass the raw request body exactly as received, the uploadad-signature header, and your signing secret:

ts
import { verifyWebhookSignature } from '@uploadad/sdk';

const rawBody = await request.text();
const ok = await verifyWebhookSignature(
	rawBody,
	request.headers.get('uploadad-signature') ?? '',
	process.env.UPLOADAD_WEBHOOK_SECRET
);
if (!ok) return new Response('invalid signature', { status: 401 });

Signatures older than 5 minutes are rejected by default; pass a fourth argument to change the tolerance in seconds. See Webhooks for event payloads.

Error handling

Every non-2xx response throws an UploadAdError with the HTTP status and the API's error message:

ts
import { UploadAdError } from '@uploadad/sdk';

try {
	await client.uploads.get('up_missing');
} catch (err) {
	if (err instanceof UploadAdError && err.status === 404) {
		console.log('not found');
	} else {
		throw err;
	}
}