POST /v1/public/pages/{slug}/unlock
Verifies the password for a gated page and returns a short-lived content token. The token is passed to the content-origin Worker (artifactausercontent.com/c/{slug}?token=...) to fetch the gated bytes.
This endpoint is unauthenticated and is called by the Artifacta viewer after the visitor submits the password prompt.
The token expires in 5 minutes (expires_in: 300). After expiry the viewer must call this endpoint again.
Authentication
None. This is a public endpoint.Path parameters
| Parameter | Type | Description |
|---|---|---|
slug | string | Page slug (pg_...) from the public URL. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
password | string | Yes | The passcode set when the page was published. |
Response
| Field | Type | Description |
|---|---|---|
content_token | string | Signed JWT (HS256). Carries slug, purpose: "page_content", and exp. Pass this as a query parameter to the content-origin Worker. |
expires_in | integer | Token lifetime in seconds. Always 300. |
Error codes
| Code | Status | When |
|---|---|---|
artifact_not_found | 404 | Page is missing, unpublished, expired, or access is not "password". No oracle. |
unauthorized | 401 | Password is incorrect. Same error code regardless of whether the slug exists (no oracle). |
rate_limited | 429 | Too many unlock attempts for this slug. Try again after the Retry-After header value. |
invalid_request | 400 | Missing or empty password field, or malformed JSON body. |
Notes
- Single failure mode: An incorrect password returns
unauthorized, notartifact_not_found. However, a missing or unpublished slug also returns a non-200 status code — callers cannot distinguish wrong-password from missing-slug. This is intentional. - Brute-force protection: Attempts are rate-limited per slug plus a separate per-IP edge rule. The per-slug cap is the primary control.
- Token scope: The token is single-purpose (
purpose: "page_content") and accepted only by the content-origin Worker. It cannot be used to call any API endpoint.