Skip to content

REST API Reference

Dino Discover exposes its admin and storefront surfaces through a single REST namespace: /wp-json/dino-discover/v1/. The Builder, the Coverage page, the Settings page, and the storefront quiz all talk to the plugin through this API. This page is the route catalogue.

For the architectural picture (the published-only invariant, the two-tier auth model, the optimistic-locking pattern), see Architecture.

  • Base URL: /wp-json/dino-discover/v1/.
  • Admin routes require the manage_dino_discover capability plus a valid X-WP-Nonce header.
  • Storefront routes are unauthenticated but rate-limited. After the initial POST /storefront/sessions, subsequent calls carry the X-DD-Variant-Token header.
  • Optimistic locking: every mutating admin route on a quiz carries an expected_draft_version integer; mismatch returns 409 dd_draft_version_mismatch.
  • Idempotency: mutating storefront routes (/events, /recommend, /lead) accept an idempotency key.
  • Errors use the WordPress REST error envelope (code, message, data.status).

Admin endpoints require the manage_dino_discover capability. The capability is filterable via dino_discover_capability. All requests need a valid X-WP-Nonce from wpApiSettings.nonce (or @wordpress/api-fetch’s middleware).

MethodPathPurpose
GET/quizzesList quizzes.
POST/quizzesCreate quiz.
GET/quizzes/{id}Fetch the draft tree (questions, answers, upvotes, variants).
PATCH/quizzes/{id}Update; gated by expected_draft_version.
DELETE/quizzes/{id}Soft-delete.
POST/quizzes/{id}/publishPublish a snapshot; gated by expected_draft_version.
POST/quizzes/{id}/duplicateDuplicate the quiz (draft only; doesn’t copy snapshots).
GET/quizzes/{id}/exportExport the quiz as JSON.
POST/quizzes/importImport a quiz from a JSON payload.
PUT/quizzes/{id}/answers/{answer_id}/upvotesSet the upvote mapping for an answer.
GET/quizzes/{id}/catalogueCatalogue picker payload (products available to upvote against).
GET/quizzes/{id}/share/sample-completionMost-recent completion’s anonymous ID for the Share tab “preview a recent completion” feature.
MethodPathPurpose
GET/quizzes/{id}/snapshotsList snapshots for the quiz (newest first).
PATCH/quizzes/{id}/snapshots/{sid}Rename the snapshot (update the publish note).
POST/quizzes/{id}/snapshots/{sid}/restoreRestore the snapshot back to draft.
MethodPathPurpose
POST/quizzes/{id}/variantsClone an existing variant into a new one (requires a source_variant_id).
PATCH/quizzes/{id}/variants/{vid}Update a variant.
DELETE/quizzes/{id}/variants/{vid}Delete a variant.
POST/quizzes/{id}/variants/{vid}/archiveArchive a variant (exclude from traffic).
PUT/quizzes/{id}/variant-weightsBulk-edit the traffic-weight distribution.
POST/quizzes/{id}/instances/{iid}/detachDD-11 detach a session instance from its variant.
POST/quizzes/{id}/instances/{iid}/relinkDD-11 relink.
MethodPathPurpose
GET/coverageAggregate coverage report (the scatter chart data).
GET/coverage/products/{pid}Per-product paths and score.
POST/coverage/refreshSchedule an immediate Coverage refresh.
MethodPathPurpose
GET/analytics/aggregateFunnel / topline metrics for a quiz over a date range.
GET/analytics/aggregate/variantsA/B variant comparison.
MethodPathPurpose
GET/leadsList captured leads (admin-only).
GET/leads/export.csvStream a CSV export of leads. Required query params: quiz_id, from, to.
MethodPathPurpose
GET/settingsRead settings.
PUT/settingsUpdate settings (validated against SettingsSchema).
POST/settings/regenerate-saltRotate every per-quiz experiment salt (reshuffles variant assignment for every active experiment).
GET/settings/privacy/quizzesPer-quiz retention listing.

Per-quiz configuration for the three shipped integrations.

MethodPathPurpose
GET/quizzes/{quiz_id}/integrationsList integration statuses for the quiz.
GET / PUT/quizzes/{quiz_id}/integrations/webhookWebhook config.
POST/quizzes/{quiz_id}/integrations/webhook/testTest the webhook.
GET / PUT/quizzes/{quiz_id}/integrations/klaviyoKlaviyo config.
POST/quizzes/{quiz_id}/integrations/klaviyo/testTest the Klaviyo key.
GET / PUT/quizzes/{quiz_id}/integrations/mailchimpMailchimp config.
POST/quizzes/{quiz_id}/integrations/mailchimp/testTest the Mailchimp key.
MethodPathPurpose
GET/licenceRead licence state.
PUT/licenceSave a licence key.
DELETE/licenceClear the saved key.

The licence client runs without a key during Beta — these endpoints are wired forward for the 1.0 release.

Setup checklist (SetupChecklistController)

Section titled “Setup checklist (SetupChecklistController)”
MethodPathPurpose
GET/setup-checklistDashboard checklist completion counts.

Storefront routes are unauthenticated but rate-limited. The default limit is 60 requests/minute per client IP, configurable via the dino_discover_rate_limit filter. The client IP derivation is filterable via dino_discover_client_ip for CDN passthrough.

MethodPathPurpose
GET/storefront/quizzes/{slug}/bootstrapReturn the bootstrap payload for a published quiz. Returns 404 if published_snapshot_id IS NULL.
POST/storefront/sessionsStart a new session. Returns the session ID and the X-DD-Variant-Token to use on subsequent calls.
POST/storefront/sessions/{sid}/eventsSubmit a batch of storefront events. Requires X-DD-Variant-Token. Idempotent on the event-key.
POST/storefront/sessions/{sid}/recommendCompute the recommendation set for the session. Requires X-DD-Variant-Token. Idempotent.
GET/storefront/sessions/{sid}/resultsRe-read the recommendation result. Cache-warmed by the most recent recommend call.
POST/storefront/sessions/{sid}/leadCapture a lead for the session. Requires X-DD-Variant-Token. Idempotent.
GET/storefront/quizzes/{slug}/draft-preview-bootstrapAdmin-only draft-preview endpoint. Requires the Builder-minted nonce. Single exception to the published-only invariant.

The bulk-cart endpoint (BulkCartController)

Section titled “The bulk-cart endpoint (BulkCartController)”
MethodPathPurpose
POST/storefront/cart/bulk-addAdd multiple recommended products to the WooCommerce cart in one round-trip.

AbstractController::permissions_admin() is the admin gate. It applies the dino_discover_capability filter to resolve the required capability (default manage_dino_discover), checks current_user_can(), and enforces the X-WP-Nonce header — returning a WP_Error on any failure rather than a bare boolean.

permissions_storefront() is the public gate: it runs the rate limiter (filterable via dino_discover_rate_limit) and, for routes that need session continuity, the Variant\Assignor validates the X-DD-Variant-Token header against the session record. Mismatch returns 403.

What’s documented in the design but not yet implemented

Section titled “What’s documented in the design but not yet implemented”

A few routes are catalogued in the technical design but do not exist in code as of 0.1.0. Watch the register_route() callsites before you depend on them:

  • /quizzes/{id}/lock, /quizzes/{id}/declare-winner.
  • /analytics/topline, /analytics/sankey, /analytics/export.csv.
  • /placements*, /jobs/{id}.
  • /storefront/sessions/{sid}/resume, /storefront/share/{token}, /storefront/share/{token}/event.

The shipped analytics endpoints in 0.1.0 are /analytics/aggregate and /analytics/aggregate/variants.