Contents
The Content resource — the lower-level lifecycle behind inklet.push, including create, confirm, and upload ticket refresh.
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>Prop
Type
An out-of-range value for state or mode throws ConfigurationError
locally.
create()
create(input: CreateContentRequest, idempotencyKey: string): Promise<CreateContentResponse>Prop
Type
Note the asset shape here differs from inklet.assets.*.
Binary assets are declared by metadata only — filename, 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:
Prop
Type
Prop
Type
idempotencyKey is required here — 8–128 printable ASCII characters, no
spaces. It is sent as the idempotency-key header.
The service applies the same plan authorization at this lower level: auto
and manual require Pro, while hardcode is available on Free. Direct use of
contents.create() cannot bypass the AI feature gate.
Validation
Enforced locally, before the request:
| Field | Rule |
|---|---|
mode | Must be one of the three modes |
displayId | Required for manual/hardcode; must be omitted for auto |
assets | 1–50 entries |
| Hardcode assets | Exactly one asset, and it must be a PNG or JPEG image |
sizeBytes | Integer, 1 to 10 MiB |
| Link URLs | Absolute HTTP(S), no embedded credentials |
| Text | At least one non-whitespace character |
confirm()
Closes uploads and starts processing:
const content = await inklet.contents.confirm(content.id);Check content.upload.status afterwards:
| Status | Meaning |
|---|---|
awaiting_upload | Nothing uploaded yet |
partial | Some assets missing — upload.failedAssetIndexes lists them |
complete | All 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
Prop
Type
Prop
Type
Prop
Type
Prop
Type
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.