The canonical, always-current source is docs/rest-api.md in the plugin’s repository. Namespace: approvaltrail/v1. 11 routes total, and (this is asserted by a test in the plugin’s own suite) no route is registered with permission_callback => __return_true. Every route checks something.
Staff routes
Require the edit_shop_orders capability unless noted otherwise.
| Method | Route |
|---|---|
| GET, POST | /proofs |
| GET, DELETE | /proofs/{uuid} |
| POST | /proofs/{uuid}/versions |
| POST | /proofs/{uuid}/link |
| GET | /proofs/{uuid}/events |
| POST | /proofs/{uuid}/lock-override (requires manage_woocommerce) |
| POST | /uploads |
| POST | /uploads/{upload_id}/chunk |
| POST | /uploads/{upload_id}/commit |
Public, token-authorized routes
These are the routes the customer’s browser calls when they open their approval link — no WordPress authentication involved, only the link’s own token.
| Method | Route |
|---|---|
| POST | /public/proofs/{uuid}/decision |
| GET | /public/proofs/{uuid}/file/{version} |
Every failure on these two routes returns a byte-identical 404 — whether the token is wrong, expired, revoked, belongs to a different proof, or the proof doesn’t exist at all. This is deliberate: a distinguishable error response would let someone probe for valid proof IDs. Two rate-limit buckets apply (one per IP, one per token), and a request must pass both.
/file/{version} accepts a rendition parameter of preview or master, defaulting to preview; see Files, previews and retention for why the preview is the default.
Worked examples
Create a proof from your own workflow
curl -X POST https://yourshop.example/wp-json/approvaltrail/v1/proofs \
-u "user:application_password" \
-H "Content-Type: application/json" \
-d '{"order_id": 1234, "title": "Front logo placement"}'
Then attach the first version:
curl -X POST https://yourshop.example/wp-json/approvaltrail/v1/proofs/{uuid}/versions \
-u "user:application_password" \
-F "file=@/path/to/proof.pdf"
This is the route to use if your production system (an order-management tool, a custom intake form) generates proofs outside the WooCommerce order screen itself.
Upload a 150 MB file without hitting a timeout
Use the three /uploads routes together: POST /uploads to start an upload session, repeated POST /uploads/{upload_id}/chunk calls to send pieces, then POST /uploads/{upload_id}/commit once all chunks have arrived. This is exactly what the admin UI does automatically above the ~20 MB threshold — see Files, previews and retention.
Pull the decision trail into a report
curl https://yourshop.example/wp-json/approvaltrail/v1/proofs/{uuid}/events \
-u "user:application_password"
Returns the full ordered list of events for a proof: useful for building your own dashboard or exporting decisions into an external reporting tool.
See also
- Hooks: for reacting to events inside PHP rather than polling the API.
- The approval record: what the decision data actually means.