REST API: developer reference

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.

Something here wrong or missing? Tell us and we will fix it.