Skip to Content

Contents

A Content is one submission: a set of assets plus your intent. Most applications should use inklet.push.*, which drives this resource for you. Reach for it directly when you need to control the individual calls.

retrieve()

const content = await inklet.contents.retrieve("content_123");

The main use is polling after a push.

list()

const page = await inklet.contents.list({ mode: "manual", state: "ready" });
list(options?: ListContentsOptions): Promise<ContentPage> interface ListContentsOptions { state?: "pending" | "processing" | "ready" | "failed"; mode?: "auto" | "manual" | "hardcode"; cursor?: string; limit?: number; // 1–50 }

An out-of-range value for state or mode throws ConfigurationError locally.

create()

create(input: CreateContentRequest, idempotencyKey: string): Promise<CreateContentResponse>
interface CreateContentRequest { mode: "auto" | "manual" | "hardcode"; displayId?: string | null; intent?: string | null; title?: string | null; assets: readonly CreateContentAssetInput[]; }

Note the asset shape here differs from inklet.assets.*. Binary assets are declared by metadata onlyfilename, contentType, sizeBytes — because the bytes go to a presigned URL afterwards, not in this request body.

type CreateContentAssetInput = | { type: "text"; text: string } | { type: "link"; url: string } | { type: "image"; filename: string; contentType: AllowedImageContentType; sizeBytes: number } | { type: "file"; filename: string; contentType: AllowedFileContentType; sizeBytes: number };

Returns the Content plus one upload ticket per binary asset:

interface CreateContentResponse { content: Content; uploadTickets: readonly UploadTicket[]; } interface UploadTicket { assetIndex: number; url: string; fields: Readonly<Record<string, string>>; expiresAt: string; }

idempotencyKey is required here — 8–128 printable ASCII characters, no spaces. It is sent as the idempotency-key header.

Validation

Enforced locally, before the request:

FieldRule
modeMust be one of the three modes
displayIdRequired for manual/hardcode; must be omitted for auto
assets1–50 entries
Hardcode assetsExactly one asset, and it must be a PNG or JPEG image
sizeBytesInteger, 1 to 10 MiB
Link URLsAbsolute HTTP(S), no embedded credentials
TextAt least one non-whitespace character

confirm()

Closes uploads and starts processing:

const content = await inklet.contents.confirm(content.id);

Check content.upload.status afterwards:

StatusMeaning
awaiting_uploadNothing uploaded yet
partialSome assets missing — upload.failedAssetIndexes lists them
completeAll assets present

refreshUploadTickets()

New presigned URLs for assets that failed to upload:

const refreshed = await inklet.contents.refreshUploadTickets(content.id, [0, 2]);

assetIndexes must be one or more unique non-negative integers; anything else throws ConfigurationError. Returns the same shape as create().

The Content type

interface Content { id: string; mode: "auto" | "manual" | "hardcode"; requestedDisplayId: string | null; intent: string | null; title: string | null; state: "pending" | "processing" | "ready" | "failed"; assets: readonly ContentAsset[]; upload: ContentUpload; processing: ContentProcessing; presentationIds: readonly string[]; createdAt: string; updatedAt: string; }
interface ContentAsset { assetIndex: number; type: "text" | "link" | "image" | "file"; text: string | null; url: string | null; filename: string | null; contentType: string | null; sizeBytes: number | null; uploadState: "pending" | "uploaded" | "failed"; } interface ContentUpload { status: "awaiting_upload" | "partial" | "complete"; failedAssetIndexes: readonly number[]; } interface ContentProcessing { stage: | "awaiting_upload" | "fetching_links" | "summarizing" | "routing" | "creating_presentations" | "complete" | "failed" | null; warnings: readonly PresentationProblem[]; error: PresentationProblem | null; }

warnings is worth logging even on success — it is where Inklet reports things like a link it could not fetch, or a display it skipped.

Doing it by hand

The full sequence push.* performs, if you need to own each step:

const created = await inklet.contents.create( { mode: "manual", displayId: "display_123", title: "Menu", assets: [ { type: "text", text: "Tonight" }, { type: "file", filename: "menu.pdf", contentType: "application/pdf", sizeBytes: bytes.byteLength, }, ], }, "menu-2026-08-15", ); for (const ticket of created.uploadTickets) { const form = new FormData(); for (const [key, value] of Object.entries(ticket.fields)) { form.append(key, value); } form.append("file", new Blob([bytes], { type: "application/pdf" }), "menu.pdf"); await fetch(ticket.url, { method: "POST", body: form }); } const content = await inklet.contents.confirm(created.content.id);

Note the upload fetch above carries no Inklet credentials — that is deliberate, and push.* does the same. Never attach your PAT to a storage URL.

Last updated on