# Test mode

> Test keys run the whole API with real pricing and real webhooks, never touch production, stock, couriers or invoices, and let you advance orders yourself.

Updated 2026-10-24 · HTML: https://layercrew.com/developers/test-mode · Markdown: https://layercrew.com/developers/test-mode.md · OpenAPI: https://layercrew.com/openapi.json

Test keys run the whole API against the same code and the same tables as live, in a separate environment marked `environment: test` on every object. Nothing you do with a test key reaches a printer, a courier or an invoice.

## What test keys do

- Every route, plus one of their own: `POST /v1/test/orders/{id}/advance`.
- **Real pricing.** Files are sliced and priced exactly as live; quotes and `pricing` blocks carry the numbers a live order would carry today.
- **Real validation.** The same checks and the same error codes.
- **Real events and webhooks.** The same envelope, signatures, retries and delivery log.
- Available from the moment your account owner accepts the agreements — before countersignature — so integration work starts on day one.

## What test keys never do

- Create a production order, reserve stock, book a courier or issue an invoice. `pricing.tax_treatment` is `test` and `payment` carries no instructions.
- See a live object. Ids are per environment; a live id answers `404 NOT_FOUND`.
- Share limits with live: `monthly_test_order_cap` and `max_test_items_per_order` are their own, and at most one test price job runs per partner at a time, so a live order is never queued behind a test.

## Advancing an order

Live orders move as production happens; test orders move when you say so, and each move emits the same event a live order would:

```bash
curl -X POST "https://engine.layercrew.com/v1/test/orders/7a3e9c10-2b4d-4f61-9e8a-5c6d7e8f9a0b/advance" \
  -H "Authorization: Bearer $LAYERCREW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "shipped" }'
```

_A rejection with a reason, to exercise your handling of order.rejected_

```bash
curl -X POST "https://engine.layercrew.com/v1/test/orders/7a3e9c10-2b4d-4f61-9e8a-5c6d7e8f9a0b/advance" \
  -H "Authorization: Bearer $LAYERCREW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "rejected", "reason": "design_change_needed" }'
```

| From | To |
| --- | --- |
| `pending_review` | `accepted` or `rejected` |
| `accepted` | `in_production` |
| `in_production` | `ready_to_ship` |
| `ready_to_ship` | `shipped` — a shipment with a sample carrier and tracking number is added |
| `shipped` | `delivered` |
| any state before `shipped` | `on_hold`, and from `on_hold` back to the state it had |

`received` becomes `pending_review` by itself once pricing finishes — wait for `order.priced` first. Each move answers `200` with the order and emits the event with your key as the actor; a move outside the table answers `409`. A live key on this route answers `403 TEST_ONLY`.

## Retention

Test files no order uses are deleted after your plan's `test_file_retention_days` — `purge_after` on the file says when. Test orders and their events stay, so you can replay them. Test requests sit in the same 90-day request log as live ones, marked by their key id. Your customers' addresses on test orders are redacted on the same schedule as live ones; use made-up people in test.

## From test to live

- Check `GET /v1/account`: both agreements `countersigned`, `status` `active`.
- Create a live key (the account owner does this) and register your production webhook endpoint with it — endpoints are per environment.
- Switch the key. Same routes, same bodies, same events; the only visible change is `environment: live` and a `payment` block with instructions on acceptance.
- Keep the test key: it stays the place to try a new material, a new file format or a handler change.
