Jobs
List jobs, newest first
GET /v1/jobs
Scope: jobs:read
Filter metadata with metadata.<key>=<value> query parameters.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
cursor | query | string | ||
limit | query | string | 1–100, default 25 | |
to | query | string | Created before (ISO 8601) | |
from | query | string | Created at or after (ISO 8601) | |
printerId | query | string | ||
deviceId | query | string | ||
state | query | "queued" | "sending" | "printed" | "failed" | "cancelled" |
Responses
| Status | Description |
|---|---|
200 | A page of jobs. |
Fields of the 200 response:
| Field | Type | Required | Description |
|---|---|---|---|
data | object[] | yes | |
data[].id | string | yes | |
data[].idempotencyKey | string | null | yes | |
data[].deviceId | string | null | yes | |
data[].printerId | string | null | yes | |
data[].source | "local" | "cloud" | yes | |
data[].mode | "live" | "test" | yes | test: created with a jp_test_ key |
data[].type | string | yes | |
data[].templateId | string | null | yes | The template the job was printed from, if any |
data[].state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
data[].attempt | integer | yes | |
data[].errorCode | string | null | yes | |
data[].errorMessage | string | null | yes | |
data[].metadata | object | yes | |
data[].contentRetained | boolean | yes | Whether the content is still stored (needed to reprint) |
data[].hasPreview | boolean | yes | Sandbox jobs (jp_test_ keys): GET /v1/jobs/{id}/preview returns the printed receipt as PNG |
data[].createdAt | string | yes | ISO 8601 date-time |
data[].updatedAt | string | yes | ISO 8601 date-time |
data[].dispatchedAt | string | null | yes | |
data[].printedAt | string | null | yes | |
data[].expiresAt | string | null | yes | |
data[].events | object[] | ||
nextCursor | string | null | yes | Pass as ?cursor= for the next page |
curl "https://api.jodaprint.dev/v1/jobs" \
-H "Authorization: Bearer $JODAPRINT_API_KEY"
Create a print job
POST /v1/jobs
Scope: jobs:write
Dispatched at once when the device is online, otherwise queued until it reconnects or the job expires.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | Same key within 24 hours returns the first job and prints nothing. |
Request body
A job-request (protocol/schemas/job-request.json) plus the target: printerId, or deviceId with an optional alias. The Idempotency-Key header overrides idempotencyKey in the body. To print a template, send templateId and its variables in data instead of type, encoding and content; the cloud renders it (GET /v1/templates lists them).
| Field | Type | Required | Description |
|---|---|---|---|
idempotencyKey | string | Same key within 24 h returns the first job and prints nothing. | |
printer | printer-ref | Selects a printer by id, alias or name (A7). Omit the whole reference to use the default printer. | |
templateId | string | Print a stored template (ZPL, EPL or receipt) filled with data. The job then has no type or encoding. | |
type | "receipt" | "escpos" | "raw" | "zpl" | "epl" | "pdf" | "image" | "text" | "html" | ||
encoding | "json" | "base64" | "utf8" | "url" | ||
data | string | receipt-document | object | yes | Job content, or template variables with templateId. |
options | job-options | Print options (A7). Printers ignore options they do not support. | |
metadata | object | Free key/value pairs stored with the job and searchable. | |
printerId | string | Example: "prn_01J8Z2ABCDEF" | |
deviceId | string | Example: "dev_01J8Z2ABCDEF" | |
alias | string | Example: "receipt" |
{
"printerId": "prn_01J8Z2ABCDEF",
"type": "receipt",
"encoding": "json",
"data": {
"width": "80mm",
"blocks": [
{
"type": "text",
"value": "Hello"
},
{
"type": "cut",
"mode": "partial"
}
]
},
"options": {
"copies": 1
},
"metadata": {
"orderId": "10492"
}
}
Responses
| Status | Description |
|---|---|
200 | A job with this idempotency key already exists; it is returned unchanged. |
201 | The job was created. |
400 | INVALID_JOB |
402 | LICENSE_LIMIT: monthly jobs of the plan used up |
Fields of the 200 response:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
idempotencyKey | string | null | yes | |
deviceId | string | null | yes | |
printerId | string | null | yes | |
source | "local" | "cloud" | yes | |
mode | "live" | "test" | yes | test: created with a jp_test_ key |
type | string | yes | |
templateId | string | null | yes | The template the job was printed from, if any |
state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
attempt | integer | yes | |
errorCode | string | null | yes | |
errorMessage | string | null | yes | |
metadata | object | yes | |
contentRetained | boolean | yes | Whether the content is still stored (needed to reprint) |
hasPreview | boolean | yes | Sandbox jobs (jp_test_ keys): GET /v1/jobs/{id}/preview returns the printed receipt as PNG |
createdAt | string | yes | ISO 8601 date-time |
updatedAt | string | yes | ISO 8601 date-time |
dispatchedAt | string | null | yes | |
printedAt | string | null | yes | |
expiresAt | string | null | yes | |
events | object[] | ||
events[].state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
events[].errorCode | string | null | yes | |
events[].at | string | yes | ISO 8601 date-time |
curl -X POST "https://api.jodaprint.dev/v1/jobs" \
-H "Authorization: Bearer $JODAPRINT_API_KEY" \
-H "Idempotency-Key: order-10492-receipt" \
-H "Content-Type: application/json" \
-d '{"printerId":"prn_01J8Z2ABCDEF","type":"receipt","encoding":"json","data":{"width":"80mm","blocks":[{"type":"text","value":"Hello"},{"type":"cut","mode":"partial"}]},"options":{"copies":1},"metadata":{"orderId":"10492"}}'
Get a job with its state history
GET /v1/jobs/{id}
Scope: jobs:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description |
|---|---|
200 | The job, with events. |
404 | JOB_NOT_FOUND |
Fields of the 200 response:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
idempotencyKey | string | null | yes | |
deviceId | string | null | yes | |
printerId | string | null | yes | |
source | "local" | "cloud" | yes | |
mode | "live" | "test" | yes | test: created with a jp_test_ key |
type | string | yes | |
templateId | string | null | yes | The template the job was printed from, if any |
state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
attempt | integer | yes | |
errorCode | string | null | yes | |
errorMessage | string | null | yes | |
metadata | object | yes | |
contentRetained | boolean | yes | Whether the content is still stored (needed to reprint) |
hasPreview | boolean | yes | Sandbox jobs (jp_test_ keys): GET /v1/jobs/{id}/preview returns the printed receipt as PNG |
createdAt | string | yes | ISO 8601 date-time |
updatedAt | string | yes | ISO 8601 date-time |
dispatchedAt | string | null | yes | |
printedAt | string | null | yes | |
expiresAt | string | null | yes | |
events | object[] | ||
events[].state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
events[].errorCode | string | null | yes | |
events[].at | string | yes | ISO 8601 date-time |
curl "https://api.jodaprint.dev/v1/jobs/<id>" \
-H "Authorization: Bearer $JODAPRINT_API_KEY"
Preview of a sandbox job
GET /v1/jobs/{id}/preview
Scope: jobs:read
The receipt a sandbox job (jp_test_ key) printed on the cloud's virtual printer, as PNG. Only receipt, escpos, raw and text jobs have one; it is deleted with the job content.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description |
|---|---|
404 | JOB_NOT_FOUND or NOT_FOUND (no preview) |
curl "https://api.jodaprint.dev/v1/jobs/<id>/preview" \
-H "Authorization: Bearer $JODAPRINT_API_KEY"
Cancel a queued cloud job
POST /v1/jobs/{id}/cancel
Scope: jobs:write
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description |
|---|---|
200 | The job, now cancelled. |
409 | JOB_ALREADY_FINISHED |
Fields of the 200 response:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
idempotencyKey | string | null | yes | |
deviceId | string | null | yes | |
printerId | string | null | yes | |
source | "local" | "cloud" | yes | |
mode | "live" | "test" | yes | test: created with a jp_test_ key |
type | string | yes | |
templateId | string | null | yes | The template the job was printed from, if any |
state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
attempt | integer | yes | |
errorCode | string | null | yes | |
errorMessage | string | null | yes | |
metadata | object | yes | |
contentRetained | boolean | yes | Whether the content is still stored (needed to reprint) |
hasPreview | boolean | yes | Sandbox jobs (jp_test_ keys): GET /v1/jobs/{id}/preview returns the printed receipt as PNG |
createdAt | string | yes | ISO 8601 date-time |
updatedAt | string | yes | ISO 8601 date-time |
dispatchedAt | string | null | yes | |
printedAt | string | null | yes | |
expiresAt | string | null | yes | |
events | object[] | ||
events[].state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
events[].errorCode | string | null | yes | |
events[].at | string | yes | ISO 8601 date-time |
curl -X POST "https://api.jodaprint.dev/v1/jobs/<id>/cancel" \
-H "Authorization: Bearer $JODAPRINT_API_KEY"
Print a job again
POST /v1/jobs/{id}/reprint
Scope: jobs:write
Only while its content is retained. The new job has metadata.reprintOf.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Responses
| Status | Description |
|---|---|
201 | The new job. |
409 | CONFLICT: content no longer retained |
Fields of the 201 response:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
idempotencyKey | string | null | yes | |
deviceId | string | null | yes | |
printerId | string | null | yes | |
source | "local" | "cloud" | yes | |
mode | "live" | "test" | yes | test: created with a jp_test_ key |
type | string | yes | |
templateId | string | null | yes | The template the job was printed from, if any |
state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
attempt | integer | yes | |
errorCode | string | null | yes | |
errorMessage | string | null | yes | |
metadata | object | yes | |
contentRetained | boolean | yes | Whether the content is still stored (needed to reprint) |
hasPreview | boolean | yes | Sandbox jobs (jp_test_ keys): GET /v1/jobs/{id}/preview returns the printed receipt as PNG |
createdAt | string | yes | ISO 8601 date-time |
updatedAt | string | yes | ISO 8601 date-time |
dispatchedAt | string | null | yes | |
printedAt | string | null | yes | |
expiresAt | string | null | yes | |
events | object[] | ||
events[].state | "queued" | "sending" | "printed" | "failed" | "cancelled" | yes | |
events[].errorCode | string | null | yes | |
events[].at | string | yes | ISO 8601 date-time |
curl -X POST "https://api.jodaprint.dev/v1/jobs/<id>/reprint" \
-H "Authorization: Bearer $JODAPRINT_API_KEY"