The error shape
Errors return a JSON body with an error string describing what went wrong. Handle on the HTTP status; log the message.
{
"error": "contentType must be one of raw_base64, pdf_base64, text"
}HTTP statuses
| Status | What it means | What to do |
|---|---|---|
400 | Validation failed — a missing field, an unknown content type, or a URI type that is disabled. | Fix the request. This will not succeed on retry. |
401 | Missing, malformed, or revoked API key. | Check the X-API-Key header. Revoked keys fail permanently — issue a new one. |
404 | No such resource, or it belongs to another organization. | Confirm the ID and that the key belongs to the same organization. |
409 | Conflict — an idempotency key reused with different input, or a cancel on an already-dispatched job. | For idempotency, use a new key for genuinely new content. For cancel, the job is already on its way. |
413 | The request body exceeds 14 MiB, or content exceeds 10 MiB. | Send smaller content. Labels are kilobytes; if you are near the limit, something is wrong upstream. |
429 | Rate limited — more than 300 requests per minute on this key. | Back off for the number of seconds in the Retry-After header, then retry. |
5xx | Something failed on our side. | Retry with the same Idempotency-Key. That is exactly what it is for. |
Job failures are not HTTP errors
A job that is accepted and later fails to print returns 201 at creation. The failure appears on the job itself: status becomes failed and the error field carries the reason the print system gave.
- The print queue rejected the job or is paused.
- The printer was unreachable from the station.
- The format is not supported on that device — for example raw content on Windows.
- The station lost its connection mid-print and reported the outcome on reconnect.
Alert on failed jobs by source. That is the signal that a bench has a real problem, and it is much earlier than a customer telling you.
Limits
| Limit | Value | Behavior at the edge |
|---|---|---|
Requests | 300 per minute per API key, burst 30 | 429 with Retry-After |
Content size | 10 MiB | 413 |
Request body | 14 MiB | 413 |
Idempotency key | 200 characters | 400 |
List page size | 50 default, 200 maximum | Clamped to the maximum |
How to retry safely
Send an Idempotency-Key on every job creation, derived from your own identifier. Then retry freely on 429 and 5xx — a duplicate request returns the original job rather than printing a second label.
async function printWithRetry(body, idempotencyKey, attempts = 4) {
for (let attempt = 1; attempt <= attempts; attempt++) {
const res = await fetch("https://rocketprint.io/api/v1/print-jobs", {
method: "POST",
headers: {
"X-API-Key": process.env.ROCKETPRINT_KEY,
"Idempotency-Key": idempotencyKey, // same key on every attempt
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (res.ok) return res.json(); // 200 replay or 201 created
if (res.status === 429) {
await sleep(Number(res.headers.get("retry-after") ?? 1) * 1000);
continue;
}
if (res.status >= 500) { await sleep(2 ** attempt * 250); continue; }
throw new Error(`print failed: ${res.status} ${await res.text()}`);
}
throw new Error("print failed after retries");
}Do not retry 400, 401, 404, or 409 — they will not succeed without a change.
The full failure model
Offline queueing, ordering, and the failures we cannot detect at all.
Read the reliability page