Skip to content

Platform paths

A site reaches the rest of its workspace through paths under /_platform/. Its Worker calls them with plain fetch, on its own hostname or on https://digize.com, and Digize’s Outbound Worker answers them from the App Worker. The site never holds a key: Outbound knows which workspace and site is calling from Dispatch, and nothing the site sends can change that.

PathTakesAnswers
GET /_platform/contextNothingThe site's identity: workspaceId, siteId and hostname
POST /_platform/formsA form: JSON, urlencoded or multipart, up to 256 KB{ submissionId }, or a 303 for a plain HTML form
POST /_platform/store/page-dataA page data query: home, product, collection or searchThe store and that page's products, from the catalog
POST /_platform/store/checkoutA cart and where to send the customer afterwards{ checkoutId, url }: Stripe Checkout's page
POST /_platform/store/checkout-status{ checkoutId }Whether it's open, completed or expired, and the order number
POST /_platform/store/reviews{ productSlug?, limit?, cursor? }The reviews widget's reviews, a page at a time
POST /_platform/store/submit-reviewA visitor's review, with a Turnstile token{ reviewId }; the review waits for the team

From a Worker, fetch the path on the request’s own origin:

src/index.ts
export default {
async fetch(request: Request): Promise<Response> {
const site = await fetch(new URL("/_platform/context", request.url));
const { workspaceId, siteId, hostname } = (await site.json()) as {
workspaceId: string;
siteId: string;
hostname: string;
};
return Response.json({ workspaceId, siteId, hostname });
},
};

A browser can’t call them: a visitor’s request for /_platform/forms on the site’s hostname goes to the site’s Worker like any other path, and the Worker passes it on (as the quickstart does). The script Digize deploys with static sites does that for every platform path.

Every call is JSON in and JSON out, except a form, which can also be urlencoded or multipart. Each answer has cache-control: no-store.

A call that works answers 200 with its value as the whole body, such as { "submissionId": "fs_01JF…" }. One that doesn’t answers with the error’s status and:

{
"error": {
"code": "invalid",
"message": "Enter an email address or a phone number.",
"details": { "fields": { "email": "Enter an email address." } }
}
}
code Status
invalid 400 What was sent isn’t valid. details.fields, when it’s there, names the fields. 405 for the wrong method, 415 for a form in another format.
unauthorized 401 Only from https://digize.com/api/store/…, for a request without the site context.
forbidden 403 Turnstile didn’t pass, or the site isn’t the workspace’s any more.
not_found 404 No such product, collection or checkout, or no such path.
conflict 409 The same checkout is still starting.
too_large 413 The body is over the path’s limit.
rate_limited 429 Over the path’s rate.
unavailable 503 Digize couldn’t take the call just now; try again.

message is written for people and may change; branch on code.

GET /_platform/context answers who Outbound says is calling: workspaceId, siteId, and the hostname the visitor’s request came to. Under a route, that’s the routed Worker’s id on the other Worker’s hostname.

Any other request a site makes to https://digize.com carries the site’s identity, signed by Outbound for 60 seconds, in x-digize-site-context, without the visitor’s cookies or authorization header. The App Worker answers the storefront’s calls there too, at POST https://digize.com/api/store/<call>, where <call> is page-data, checkout, checkout-status, reviews or submit-review. They take the same bodies as the paths under /_platform/store/.