Official Node.js / TypeScript SDK for the Abyssale API — programmatic creative asset generation at scale.
npm install @abyssale/sdkRequires Node.js ≥ 20.
import abyssale from '@abyssale/sdk';
// List your designs
const { data, error } = await abyssale.listDesigns();
// Generate an image synchronously
const { data: banner } = await abyssale.generateImage('your-design-id', {
elements: {
title: { payload: 'Hello World' },
background: { background_color: '#FF0000' },
},
template_format_name: 'facebook-post',
});
console.log(banner?.file.cdn_url);The SDK reads configuration from environment variables — no constructor arguments needed.
| Variable | Required | Default | Description |
|---|---|---|---|
ABYSSALE_API_KEY |
✅ | — | Your Abyssale API key. The SDK throws at import time if this is not set. |
ABYSSALE_TIMEOUT_MS |
— | 30000 |
Per-request timeout in milliseconds. |
ABYSSALE_MAX_RETRIES |
— | 3 |
Maximum number of retries on 429 and 5xx errors. |
ABYSSALE_API_KEY=your-key node your-script.jsPersonalised email headers — Generate a unique image per recipient with their name, company logo, and offer. Serve it via a dynamic image URL that renders on email open with no pre-generation needed — one URL template, infinite variations.
Bulk ad creative production — Send a list of product data and generate hundreds of social media creatives (Facebook, Instagram, LinkedIn, Google Display) in every required format in a single async call. Poll for completion or supply a callback_url.
E-commerce product banners — Dynamically swap product image, price, and promotional text into a branded template for each SKU, triggered automatically when inventory or pricing changes.
Print-on-demand — Generate personalised multi-page PDFs (brochures, catalogues, certificates) with different content per page, ready for commercial printing with crop marks and color profiles.
HTML5 banner ads — Produce animated HTML5 banners for ad networks (Google Campaign Manager, Sizmek) with click-tag and backup image, directly from your design templates.
Website social cards — Generate Open Graph and Twitter Card images on demand for any page, with the page title and thumbnail baked in, triggered by a CDN edge function or serverless handler.
import abyssale from '@abyssale/sdk';
const { data, error } = await abyssale.generateImage('design-id', {
template_format_name: 'instagram-square',
elements: {
headline: { payload: 'Summer Sale — 50% Off' },
product_image: { url: 'https://cdn.example.com/product.jpg' },
cta_button: { payload: 'Shop Now', background_color: '#FF6B35' },
},
});
if (error) throw new Error(JSON.stringify(error));
console.log(data.file.cdn_url); // ready immediatelyimport abyssale from '@abyssale/sdk';
// Kick off generation across all formats at once
const { data: request, error } = await abyssale.generateMultiFormatMedia('design-id', {
elements: {
headline: { payload: 'New Product Launch' },
logo: { url: 'https://cdn.example.com/logo.png' },
},
});
if (error) throw new Error(JSON.stringify(error));
// Wait until all banners are ready — polling is handled by the SDK
const result = await abyssale.waitForGenerationRequest(request.generation_request_id);
for (const banner of result.banners) {
console.log(banner.format_name, banner.file.cdn_url);
}import abyssale from '@abyssale/sdk';
const { data } = await abyssale.createDynamicImageUrl('design-id', {
template_format_name: 'email-header',
elements: ['first_name', 'company_logo'],
});
// Embed in email — values injected at render time via query string
const imageUrl = `${data.dynamic_image_url}?first_name=Alice&company_logo=https://...`;import abyssale from '@abyssale/sdk';
const { data: request, error } = await abyssale.generateMultiPagePdf('design-id', {
pages: {
page_1: { root: { background_color: '#FFFFFF' } },
page_2: { root: { background_color: '#F5F5F5' } },
},
});
if (error) throw new Error(JSON.stringify(error));
if (!request.generation_request_id) throw new Error('No generation_request_id');
const result = await abyssale.waitForGenerationRequest(request.generation_request_id);
console.log(result.banners[0]?.file.cdn_url); // download the PDFimport abyssale from '@abyssale/sdk';
const bannerIds = ['banner-id-1', 'banner-id-2', 'banner-id-3'];
const { data } = await abyssale.exportBanners({
ids: bannerIds,
callback_url: 'https://your-server.com/webhooks/export-done',
});
console.log('Export queued:', data.export_request_id);Every method returns { data, error, response } — the SDK never throws on HTTP errors.
const { data, error } = await abyssale.generateImage(designId, { elements: {} });
if (error) {
console.error('API error:', error);
// error is typed from the OpenAPI spec
} else {
console.log(data.file.cdn_url);
}The SDK automatically retries failed requests with exponential backoff:
- Retries on
429 Too Many Requestsand5xxserver errors - Default: up to 3 retries (1 s → 2 s → 4 s delays + jitter)
- Default timeout: 30 seconds per request
Both are configurable via environment variables (ABYSSALE_TIMEOUT_MS, ABYSSALE_MAX_RETRIES).
- TypeScript-first — all types generated directly from the OpenAPI spec, full IntelliSense on every request and response field
- Zero-config singleton —
import abyssale from '@abyssale/sdk'and go; no constructor, no setup beyond one env var - Auto-retry with exponential backoff — transparent retries on transient failures (
429,5xx), configurable retry count - Never throws on HTTP errors — every method returns
{ data, error }, keeping error handling explicit and predictable - Dual ESM + CJS output — works in any Node.js project regardless of
"type"inpackage.json openapi-fetchunder the hood — ~6 KB type-safe HTTP client, no heavy runtime dependency
abyssale.listDesigns(query?) // GET /designs
abyssale.getDesign(designId) // GET /designs/{designId}
abyssale.getDesignFormat(designId, format) // GET /designs/{designId}/formats/{format}// Synchronous — returns the banner immediately
abyssale.generateImage(designId, body)
// Asynchronous — returns generation_request_id; poll or use callback_url
abyssale.generateMultiFormatMedia(designId, body)
abyssale.generateMultiPagePdf(designId, body) // printer_multipage designs only
// Polling — call getGenerationRequest once, or let the SDK loop until done
abyssale.getGenerationRequest(generationRequestId)
abyssale.waitForGenerationRequest(generationRequestId, options?)abyssale.getFile(bannerId) // GET /banners/{bannerId}abyssale.listFonts() // GET /fontsabyssale.listProjects() // GET /projects
abyssale.createProject({ name }) // POST /projectsabyssale.exportBanners({ ids, callback_url? }) // POST /async/banners/exportabyssale.createDynamicImageUrl(designId, body) // POST /designs/{designId}/dynamic-image-urlabyssale.duplicateWorkspaceTemplate(templateId, body) // POST /workspace-templates/{id}/use
abyssale.getDuplicationRequest(duplicateRequestId) // GET /design-duplication-requests/{id}
abyssale.waitForDuplicationRequest(duplicateRequestId, options?) // polls until COMPLETED or ERRORwaitForGenerationRequest and waitForDuplicationRequest handle the polling loop so you don't have to. Both use exponential backoff with jitter and accept an optional options object:
| Option | Default | Min | Description |
|---|---|---|---|
intervalMs |
3000 |
2000 |
Initial delay between polls in ms |
maxIntervalMs |
30000 |
5000 |
Maximum delay between polls in ms |
timeoutMs |
1800000 |
60000 |
Absolute timeout (30 min); throws Error("Polling timed out") if exceeded |
// Custom poll interval and timeout
const result = await abyssale.waitForGenerationRequest(id, {
intervalMs: 5_000,
maxIntervalMs: 30_000,
timeoutMs: 300_000,
});waitForDuplicationRequest resolves when status is "COMPLETED" or "ERROR" — always check result.status afterwards.
const result = await abyssale.waitForDuplicationRequest(duplicateRequestId);
if (result.status === 'ERROR') throw new Error('Duplication failed');
console.log(result.designs);All request and response types are generated from the OpenAPI spec and fully exported:
import type { Banner, Design, Font, GenerationRequestStatus, PollOptions } from '@abyssale/sdk';