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
npm install @uploadad/sdkbun works too: bun add @uploadad/sdk.
Authentication
Create a client with an API key (create one at upload.ad/dashboard/settings/api-keys):
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:
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:
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:
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
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 listCreatives and copy variants
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:
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:
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;
}
}