Skip to main content

Worked public samples

No X-API-Key required — and none accepted. Every route on this page is public by design: the API ignores the key entirely, so the samples below omit it. Signed links, tokens, or public query parameters authorize the caller where noted; do not add an API key to a browser embed.
The endpoint list below documents every public route’s parameters; this overlay walks the surfaces a signed-out visitor actually hits: callback links, the community and idea boards, shared recordings and embeds, sub-processor notices, then the survey link, the hosted consent form, and an agentic-commerce checkout. Success envelopes are { data, meta } and error envelopes { error, meta }, except where a route serves a raw protocol document or an HTML page; the four shapes together are documented in How to read a worked sample. Every response carries meta.request_id. Quote the request id when you report an out-of-window token or a misfired cancel so support can trace the request end-to-end.

1. Look up a callback token

GET /api/v1/public/callbacks/{token} returns the callback’s arrival state — ok: true with status set to pending, running, succeeded, failed, or canceled. It also reports whether a cancel and a reschedule request would still be accepted, so your confirmation page can hide an action that would 409. The route ignores X-API-Key; the sample sends nothing.
200
caller masks the calling number for screen readers and logs; the full E.164 number only resolves inside your tenant-scoped callback list.

2. Check a callback’s status

GET /api/v1/public/callbacks/{token}/status answers the same envelope without the embedded PII — use it for a barebones “still pending” check on the confirmation page before you offer the cancel button.
200

3. Cancel the callback

POST /api/v1/public/callbacks/{token}/cancel stops the remaining retry attempts and flips the callback to canceled. It works even after an attempt already ran — already_canceled: true tells you a previous cancel won, and the request is idempotent.
200

4. Reschedule the callback

POST /api/v1/public/callbacks/{token}/reschedule moves the callback to a new scheduled_for and resets the retry ladder. Rotate scheduled_for — send the new timestamp when you re-issue the token.
200

5. Errors

Errors follow the { error, meta } envelope. Two failures every token holder hits: 404 — token not found or out of window. A guessed token was never issued or the callback window already closed. Do not retry.
404
429 — token rate-limited. A public link that is hammered faster than one request per window returns a plain rate-limit so a runaway browser refresh is bounded:
429
The community board, the idea board, the published roadmap, shared recordings and dashboard embeds, and the sub-processor subscription handshake are all reach-in surfaces for a signed-out visitor, so none of them accept a tenant API key — an X-API-Key header is simply ignored here and the samples below omit it. Scope the community and idea calls with ?org=<your-org-slug>; both boards are opt-in, and an unknown slug or a disabled board collapses to the same 404 so a probe cannot tell the two apart.
Consent envelopes stay tenant-owned: a subscription records only the channel (email or webhook), the endpoint, the subscriber locale, and the double-opt-in state. Confirm and unsubscribe links are signed, single-purpose tokens that expire after 30 days, and one click from the notice email flips state — no session, no password.

6. Browse and read community questions

GET /api/v1/public/community/questions lists published questions with vote, answer, and view counts — ?sort=recent|top|unanswered, an optional q full-text filter, and limit/offset pagination.
200
GET /api/v1/public/community/questions/{id} returns the question with its published answers, and bumps the view counter — never edge-cache it. Up-vote with POST /api/v1/public/community/questions/{id}/vote?org=acme (an empty body is fine); the call is idempotent per visitor, so a repeat returns voted: false with the unchanged count:
200

7. Read the idea board and up-vote

GET /api/v1/public/ideas lists feature-request ideas with their lifecycle status (under_review, planned, in_progress, shipped, declined) — visitors can submit and vote, but only your team moves an idea onto the roadmap.
200
Up-vote with POST /api/v1/public/ideas/{id}/vote?org=acme — same idempotent-per-visitor contract as the question vote above.

8. Read the public roadmap

GET /api/v1/public/ideas/roadmap returns the three roadmap columns — planned, in_progress, shipped — each capped and ordered by votes (the shipped column reads newest-first and doubles as a “what we shipped” changelog). Pair it with the content pages under GET /api/v1/public/pages and GET /api/v1/public/pages/{slug} when you need the published copy that explains a column.
200

9. Resolve a shared recording or a dashboard embed

GET /api/v1/public/recordings/{token} resolves a signed recording share link minted from the dashboard’s share action and returns the player HTML for the recipient — never the underlying storage path. An expired or revoked link answers 404 with the same non-disclosing page. GET /api/v1/public/analytics/dashboards/embed?token=… is the white-label variant for analytics: it verifies the signed grant and returns the layout snapshot plus the minting org’s public branding theme so the embed page renders inside your iframe.
200
Both resolvers keep the recipient link private — the token is a bearer credential, the responses are no-store, and a tampered or expired grant collapses to the same 404 without distinguishing which.

10. Subscribe to sub-processor change notices

POST /api/v1/public/subprocessor-subscriptions registers an email or a webhook endpoint for advance notice before Devotel adds or replaces a sub-processor. The Devotel site signs this call server-side, so a typical integration posts through its own backend or the site form rather than from a browser. The request is idempotent per endpoint: re-subscribing the same address returns the same subscription id and re-opens the double-opt-in.
201

11. Confirm and unsubscribe from the notice email

Every notice email carries both links. The token template is v1.<payload>.<signature> — a signed, single-purpose credential bound to one subscription, valid 30 days. GET /api/v1/public/subprocessor-subscriptions/confirm?token=… completes the double opt-in and flips the subscription to confirmed:
GET /api/v1/public/subprocessor-subscriptions/unsubscribe?token=… is the one-click footer link — it flips any state to unsubscribed and is safe to re-hit. Both endpoints answer an HTML page for the human who clicked; a missing, malformed, or expired token renders “link not valid” with a prompt to subscribe again, and re-subscribing from the sub-processor page mints a fresh pair of tokens on the same subscription id. Survey invitation links, hosted consent landing pages, and the agentic-commerce (ACP) checkout are the three public surfaces your recipients and shopping agents drive straight from a browser or an agent runtime. Like the boards above, all three ignore X-API-Key; the token or the storefront id in the path is the credential.
GET /api/v1/public/surveys/{token}
The survey link you send is this route with the signed invitation token in the path. It always answers HTML (text/html), not JSON: a self-contained page with a 0-10 score row and an optional comment box, or a thank-you page when the recipient already answered. The JSON block on the generated entry above is a schema placeholder; browsers and iframe embeds render the page below.
200
An expired or invalid token renders a non-disclosing 404 HTML page — This feedback link has expired or is invalid. — identical for tokens that never existed, so a probe cannot enumerate survey ids. See How to read a worked sample for the error envelope used by the JSON surfaces below.
404

13. Submit a survey response (HTML vs JSON)

POST /api/v1/public/surveys/{token}/submit
The submit route accepts a JSON body or an HTML form post, keyed off the signed token in the URL, and is idempotent per link — a repeat submission never double-counts. The response format follows the caller’s Accept header: JSON clients get the { data, meta } envelope, form posts get a thank-you page.
200
Drop the Accept header (or send Accept: text/html) from a form post and the same call answers the thank-you page a human sees after clicking submit:
200
An invalid or expired token answers 403 on submit (the JSON surface names it; the HTML page route above uses the non-disclosing 404):
403
GET /api/v1/public/consent/{tenantId}/config
A hosted consent landing page renders from this route: it returns the public, safe-subset config a form needs — enabled flag, branding, copy, and the channels the tenant accepts. No secrets, no tenant enumeration: an unknown or disabled tenant answers enabled: false with empty branding and copy.
200
For a tenant whose form is switched off, the same call answers the non-disclosing variant — render nothing interactive when enabled is false:
200

15. Capture an opt-in or opt-out

POST /api/v1/public/consent
The form posts here. An opt-out is one-click and never gated; an opt-in requires the signed proof-of-ownership token that Orbit delivered to the recipient’s own address, so nobody can subscribe a third party. On success the route returns the ids of the consent records it wrote, one per channel.
200
A malformed payload (missing channel, bad identifier) answers 422 with the offending fields listed in details.issues:
422
An opt-in without a valid proof token answers 403 CONSENT_PROOF_REQUIRED; opt-out ("optIn": false) never does.

16. Discover an agentic-commerce storefront

GET /api/v1/public/commerce/acp/{storefrontId}/.well-known/agentic-commerce
A shopping agent starts here. The route serves the ACP discovery manifest RAW — not the { data, meta } envelope — so a generic ACP client parses the protocol document directly. Unknown or unpublished storefronts 404.
200

17. Browse the hosted product feed

GET /api/v1/public/commerce/acp/{storefrontId}/feed
The feed is also served RAW, straight from the merchant’s stored catalog. Prices are in MAJOR currency units; the agent browses this to build a cart and never supplies a price of its own.
200

18. Open an ACP checkout session

POST /api/v1/public/commerce/acp/{storefrontId}/checkout
The agent posts the product ids and quantities it wants. The storefront prices every line SERVER-SIDE against the stored catalog — a forged price can never enter the cart — and returns the raw session snapshot. messages lists per-item problems (unknown product, out of stock); a blocking error keeps the session not_ready_for_payment.
200
POST /api/v1/public/commerce/acp/{storefrontId}/checkout/update re-prices the same session for a replacement item set — send the current session plus the new items and read the re-derived totals the same way.

19. Complete the checkout under an agent mandate

POST /api/v1/public/commerce/acp/{storefrontId}/checkout/complete
Completing a session requires a verified AP2 payment mandate: the route checks the agent’s signature before any charge, re-prices the cart against the stored catalog, and re-verifies the mandate’s scope and spend caps. An anonymous caller 401s; an unverifiable signature 403s. The response is RAW — the completed session plus the mandate and authorization it ran under (shown here with the fields the route logs):
200
No money moves on Devotel’s side — the authorization belongs to the mandate’s payment instrument, and the order record is what your storefront reconciles against.