Repository navigation
API Reference
interface ClientOptions {
apiKey: string; // required — '2dai_sk_…'
baseUrl?: string; // default 'https://dapp.2dai.io:444'
fetch?: typeof fetch;
timeoutMs?: number; // default 60000
maxRetries?: number; // default 2
integration?: 'sdk' | 'mcp'; // default 'sdk'
integrationVersion?: string; // semver, e.g. '1.4.0'
}integration is a closed set, not a free-form User-Agent: the server derives
each creation's source from the client token, and source is what puts a row
in the dashboard's SDK / MCP collections and picks its origin pill. Only the
official 2DAI MCP server sends 'mcp' — your own app, a script or a backend job
leaves this alone and lands as sdk. integrationVersion rides along for
diagnostics and must look like 1.2.3 (a prerelease or build suffix is fine);
a malformed value is replaced by 0.0.0 rather than omitted — the token has to
match name/x.y.z for the server to recognise the integration at all, so an
honest placeholder beats losing the attribution.
client.baseUrl: stringclient.me(signal?): Promise<Account>-
client.download(ref, opts?: DownloadOptions)— shortcut forclient.cdn.download
generate.image(params: ImageParams, opts?: SubmitOptions): Promise<GenerationResult> // { wait:true } default
generate.image(params: ImageParams, opts: { wait:false } & SubmitOptions): Promise<QueueTicket>
generate.imageWithRefs(params: RefParams, opts?): Promise<GenerationResult | QueueTicket>
generate.video(params: VideoParams, opts?): Promise<GenerationResult | QueueTicket>SubmitOptions: { wait? (default true), intervalMs? (default 2000), timeoutMs? (default 300000), signal? } — same defaults for WaitOptions.
interface RefParams {
tool: 'face-ref' | 'character-ref' | 'style-transfer';
refCreationIds: string[]; // ≤6 identity refs (face/character) · ≤3 style sources
prompt?; quality?; aspectRatio?; width?; height?; allowNSFW?;
extractionDirective?; // style-transfer only, default 'style'
clientToken?;
}
interface VideoParams {
prompt: string; inputCreationId: string;
duration?; // seconds, tier-gated
quality?; style?; frameInterpolation?; allowNSFW?; clientToken?;
}queue.get(queueId: string, signal?): Promise<QueueState>
queue.waitFor(queueId: string, opts?: WaitOptions): Promise<QueueState> // resolves on any terminal statuscreations.list(opts?: ListOptions): Promise<CreationPage>
creations.get(ref: CreationRef, signal?): Promise<Creation>
creations.move(ref, target: string | null, signal?): Promise<{ creationId, folderId }> // 'root'|null = detach
creations.trash(ref, signal?): Promise<{ creationId, trashed }>
creations.restore(ref, signal?): Promise<{ creationId, trashed }>
creations.delete(ref, signal?): Promise<{ creationId, deleted }> // must be trashed first
creations.publish(ref, signal?): Promise<{ creationId, isPublicShared }>
creations.unpublish(ref, signal?): Promise<{ creationId, isPublicShared }>ListOptions: { limit?, beforeDate?, folderId?, trashed?, signal? }
(folderId: 'root' = ungrouped root).
folders.list(arg?: AbortSignal | FolderListOptions): Promise<FolderPage>
folders.create(input: { title, description? }, signal?): Promise<Folder>
folders.update(folderId, patch: { title?, description? }, signal?): Promise<Folder>
folders.delete(folderId, opts?: { trashContents?, signal? }): Promise<{ folderId, deleted }>
interface FolderListOptions { limit?; beforeDate?; sort?: FolderSort; signal? }
type FolderSort = 'index' | 'date-desc' | 'date-asc' | 'name-asc' | 'name-desc' | 'update-desc'list returns a page (newest first by default, limit 1..100 default 20) —
paginate with nextBeforeDate. The cursor is only emitted for the default and
date-desc orderings: beforeDate filters on the creation date, so any other
sort is honoured but comes back without nextBeforeDate — raise limit
instead. The bare-AbortSignal call form (folders.list(signal)) still works.
uploads.image(input: UploadInput): Promise<Creation>
// UploadInput: { path? } | { data: Uint8Array|ArrayBuffer|Blob } | { base64 }, + filename?, contentType?, signal?cdn.url(ref: CdnRef, transform?: CdnTransform): string
cdn.fetch(ref: CdnRef, arg?: CdnFetchArg): Promise<CdnAsset> // { bytes, contentType, ext }
cdn.download(ref, opts?: DownloadOptions): Promise<string | CdnAsset>
cdn.toBlob(ref, arg?: CdnFetchArg): Promise<Blob>
cdn.toDataUrl(ref, arg?: CdnFetchArg): Promise<string>
interface CdnTransform {
width?: number; // → ?w — target width in px
height?: number; // → ?h — target height in px
maxSide?: number; // → ?s — longest edge in px, aspect ratio preserved
}
interface CdnFetchOptions extends CdnTransform { signal?: AbortSignal }
interface DownloadOptions extends CdnTransform { savePath?: string; signal?: AbortSignal }
type CdnFetchArg = AbortSignal | CdnFetchOptionsThe resize happens on the CDN, before the bytes are sent — nothing is decoded
client-side, so a preview costs a fraction of the transfer. maxSide on its own
scales the longest edge and keeps the aspect ratio; width / height target
those axes specifically and may crop. Non-finite or non-positive values throw
ApiError('INVALID_TRANSFORM') locally, before any request goes out; valid ones
are rounded to whole pixels. fetch / toBlob / toDataUrl still accept a bare
AbortSignal as their second argument, so pre-transform code keeps working; pass
{ …transform, signal } to combine the two. download composes the same way —
savePath plus a transform writes a resized file.
interface Account { userId; username?; creditUsd; tier; key: KeyContext }
interface KeyContext { keyId; label; scopes: Scope[]; spendLimitUsd: number|null; spentUsd }
type Scope = 'read' | 'generate' | 'manage' | 'publish'
interface QueueTicket { queueId; status: QueueStatus; costUsd? } // costUsd present when a charge applied
interface ApiErrorBody { error?; message?; [key: string]: unknown } // raw parsed error payload (err.details)
interface GenerationResult extends Creation { queueId; costUsd? }
interface Creation {
creationId; prompt?; toolKind?; style?; quality?; aiModel?;
cdnId?; downloadUrl?; width?; height?; isUploaded?; source?; nsfwRate?; creationDate?; raw?
// source: 'web' | 'sdk' | 'mcp' | 'api' — creation origin (SDK ≥ 2.0.1)
}
interface QueueState { queueId; status; costUsd?; creationId?; cdnId?; downloadUrl?; error?; createdAt?; completedAt? }
type QueueStatus = 'pending'|'pendingCharge'|'processing'|'inProgress'|'completed'|'failed'|'cancelled'|'dismissed'|'timeout'|'expired'
interface Folder { folderId; title?; description?; icon?; kind?; isPublicShared?; isShared?; posterCreationId?; createdAt?; updatedAt?; raw? }
interface CreationPage { creations: Creation[]; nextBeforeDate? }
interface FolderPage { folders: Folder[]; nextBeforeDate? }
type CdnRef = string | { cdnId?; outputCdnId?; downloadUrl? }
type CreationRef = string | { creationId? }
type AspectRatio = '1:1'|'16:9'|'9:16'|'4:3'|'3:4'|'3:2'|'2:3'See Error Handling for the full error class table. For the underlying HTTP endpoints (any language), see REST API.