Miniwall Docs
Reference

Public API

The read-only HTTP endpoints the Web SDK uses to load published screens and send events, with response shapes.

The Web SDK talks to these endpoints for you. You only need this page to debug, to self-check an integration, or to build your own client. The base URL is the API address, followed by /v1. All SDK endpoints are under /v1/sdk.

Authentication

Every /v1/sdk request carries your project's public key in the query string: ?key=pk_.... A missing, wrong or revoked key answers 401 with code invalid_key.

If the project has allowed websites, a request whose Origin header is not on the list answers 403 with code origin_not_allowed. Any origin may call these endpoints otherwise (CORS is open for GET and POST).

Errors have this shape:

{ "error": { "code": "invalid_key", "message": "Missing or invalid public key" } }

Caching

Delivery responses carry an ETag and Cache-Control: public, max-age=0, s-maxage=30, stale-while-revalidate=30. Send If-None-Match to get 304. A new publish reaches sites within about a minute.

GET /v1/sdk/placements/:key

The screen for a placement. Add v=2 if your client can draw toast, side drawer and launcher formats; without it, placements with those formats return display: null.

{
  "placement": "upgrade_button",
  "paywallId": "uuid",
  "version": 4,
  "paywall": { "default_locale": "en_US", "components_config": { "base": {} }, "components_localizations": {} },
  "packages": ["monthly", "annual"],
  "experiment": { "id": "uuid", "shareB": 50, "b": { "paywallId": "uuid", "version": 2, "paywall": {}, "packages": [] } },
  "rules": [{ "id": "rule1", "conditions": [{ "field": "user.plan", "op": "eq", "value": "free" }], "paywall": null }],
  "frequency": { "max": 3, "per": "day" },
  "holdout": { "id": "placementId:timestamp", "share": 10 },
  "display": { "format": "modal", "size": "medium" },
  "trigger": { "type": "delay", "seconds": 10, "pages": [], "priority": 0 }
}
FieldMeaning
paywallThe published screen JSON. A schedule in force replaces it.
packagesPackage IDs your site must pass prices for
experimentA running A/B test with side B, or null. Always null while a schedule is in force or when the plan lacks A/B tests.
rulesAudiences in order. paywall: null means show nothing. Audiences whose screen is unpublished are left out.
frequency, holdoutCap and holdout, or null
display, triggerHow and when it shows, or null

Errors: 404 not_found when the key matches no placement, or the placement has no published screen.

GET /v1/sdk/paywalls/:paywallId

One published screen by ID. The response has placement: null, paywallId, version, paywall and packages. Used for Go to screen and for paywallId sources. 404 if it is unknown or not published.

GET /v1/sdk/auto

The placements that show themselves, highest trigger priority first. Only placements with a trigger other than manual, a format this client can draw, and a published screen are listed.

{ "placements": [{ "placement": "exit_offer", "display": { "format": "modal" }, "trigger": { "type": "exit_intent", "pages": ["/pricing"], "priority": 10 } }] }

The SDK then loads each screen through the placement endpoint when its trigger fires.

POST /v1/sdk/events

Sends a batch of events. The body is JSON, and text/plain is accepted too so sendBeacon works. It answers 204 with no body.

{ "events": [{ "type": "view", "paywallId": "uuid", "version": 4, "placement": "upgrade_button", "visitorId": "random-id-8-to-64-chars", "occurredAt": "2026-10-06T10:00:00Z" }] }
FieldNotes
typeview, close, purchase_click, purchase, purchase_cancel, purchase_error, restore, action, holdout, holdout_purchase, answer
visitorIdRequired, 8 to 64 characters
paywallId, version, placementWhich screen. placement up to 64 characters.
packageIdUp to 64 characters
actionIdFor action; must match the action ID pattern, else the event is dropped
fieldId, optionIdFor answer; must match the answer ID pattern, else dropped
experimentId, variantvariant is a or b
occurredAtOptional; ignored if more than a day from now

A batch holds 1 to 50 events. More than 1,200 events a minute for one key answers 429 rate_limited. A screen ID that does not belong to the project is stored without a screen.

GET /v1/preview/:token

Public. The latest saved draft behind a preview link: name, savedAt, paywall, packages. Never cached. 404 if the link is off.

On this page