Developers
Building an app
An app is your own server. Describe it in a manifest, install it with OAuth, and answer the signed events Sellstamp sends. Nothing you write runs on Sellstamp.
The manifest
One JSON document describes the app: its name, the scopes it asks for, its redirect URIs, the address of its dashboard page, the events it wants and where lifecycle and compliance events go. Unknown fields are rejected, and every URL must be https, on your own server, and not a private address. Lint it before you submit; every error names the field.
sellstamp app validate manifest.json # or, with no login at all: curl -X POST https://api.sellstamp.com/api/v1/app-manifest/validate \ -H 'content-type: application/json' --data @manifest.json
The JSON Schema is served at /api/v1/app-manifest/schema. The dashboard form and the manifest are the same record: an app registered by form has an implicit manifest.
Versions and review
- Every submission is a new, immutable version. Nothing is edited in place.
- A version that only narrows (fewer scopes, fewer redirect URIs, a copy change) goes live at once.
- A version that adds anything (a scope, a redirect URI, a new origin, an extension, a webhook topic, a new name) waits for review as a diff. The live version keeps serving, and installs already made are untouched.
- Staff can roll an app back to an earlier approved version. Existing installs are narrowed to that version's scopes, never widened.
Lifecycle events
Sellstamp POSTs signed JSON to your lifecycle.url:
- app.installed
- A store installed the app.
- app.uninstalled
- The store removed it. Tokens are already dead. Delete what you keep about the store by purge_after (30 days).
- app.scopes_updated
- The install's scopes changed (re-authorization or a rollback).
- app.suspended / app.resumed
- Sellstamp suspended the app, or lifted it.
Each install has its own secret, read from GET /api/v1/public/app with the install's token. The x-sellstamp-signature header is the hex HMAC-SHA256 of the raw body. Delivery is at least once: deduplicate on event_id. Failures are retried with backoff.
Compliance events
An app that asks for customers.read or any orders.* scope must declare lifecycle.compliance_url and answer customer.data_request, customer.redact and shop.redact. Before it can be approved, Sellstamp sends a signed probe, which must get a 2xx, and a forged one, which must not. Run the check from Apps → Build apps after installing the app on your own store.
Rolling secrets without downtime
- Install secret:
POST /api/v1/public/app/rotate-secretwith the install token. Events carryv1=<new>,v1=<old>for 24 hours. - Client secret: the old one keeps authenticating the token endpoint for 24 hours.
- Page (embed) secret: the new one is shown now, and Sellstamp keeps signing with the old one until the new one activates (a day, or when you press it). Verify with both until then.
Settings
Declare a settings schema in the manifest (text, number, true/false, a choice, or a secret) and Sellstamp renders the form on your app’s page in the dashboard, so most apps need no frame at all. Saves are validated on Sellstamp’s side. You are told with app.settings_updated, which carries only a version: read the values at GET /api/v1/public/app/settings. A secret field is write-only for the merchant and is readable only by your app.
App data
Ask for app_data.read and/or app_data.write and store typed values on a store, a product, an order or a customer:
PUT /api/v1/public/app-data/product/<product id>/size-guide
{ "type": "json", "value": { "rows": [{ "size": "M", "cm": 50 }] } }- The namespace is yours: you can never see or write another app's data, or another store's.
- Values are strings, numbers, booleans or plain JSON, with hard limits (16 KB a value, 6 levels, 100 keys per resource), and each refusal names its limit.
- The merchant can see everything you store, it is in their data export, and it is deleted with the customer it describes and after an uninstall.
Blocks, actions and the App Bridge
Declare extensions in the manifest: a block is a card on an order, product or customer page, and an action is a button that opens a modal (with bulk, also on the order and product lists). Nothing is injected: each one is a sandboxed frame of yours. Inside it, @sellstamp/app-bridge asks the dashboard for things; the dashboard renders anything visible (a confirmation, a resource picker, the save bar, a modal) and you receive only the answer. See the protocol spec in the repository, docs/APP_BRIDGE_PROTOCOL.md.
To act on what the viewer is looking at, exchange the session token for an online token: its scopes are your install’s intersected with what that viewer may do, so a viewer’s frame can never cause a write.
Automations: actions, triggers and delivery guarantees
Declare automation.actions and automation.triggers in the manifest. A merchant can wire a rule to call one of your actions (a signed POST to a path on your own origin, with only the inputs you declared) or start a rule from a trigger you raise with POST /api/v1/public/app/triggers. Only an action you mark idempotent is retried, and every call carries a stable idempotency_key: deduplicate on it.
Deliveries (lifecycle, compliance, webhooks) are at least once with a stable event_id, no ordering guarantee, and a published backoff. Merchants and you each get a delivery log with replay, and you can send yourself a test event. The details are in docs/PUBLIC_API.md.
Showing your data on a storefront
You cannot put code or markup on a storefront. Store a value with PUT /api/v1/public/app-data/shop/{shopId}/{key}; the merchant adds an App content section, binds it to that key and chooses how it is shown (text, badge, list, button, stars, formatted text, an image from their own library, or search data). If the value does not fit the shape they chose, nothing is shown. The shapes are in docs/PUBLIC_API.md.
Trust: proving your domains, and being paused
To be approved, prove you control every host your manifest names: publish a DNS TXT record at _sellstamp-app.<host> or a file at /.well-known/sellstamp-app-verification.txt (the value is on your app’s page), then press Verify. It is re-checked daily; three failures suspend the app. Apps that read customer data or change a store also need a confirmed contact address. A merchant can pause your app at any time (its token returns 401 and nothing is sent until they resume), and a new version that asks for more scopes waits for each merchant to agree. Details in docs/PUBLIC_API.md.
Versions, the CLI and conformance
The API is versioned by date: send Sellstamp-Version: 2026-10-01 (or pin api_version in your manifest). With no header you stay on the baseline until a sunset date we announce at least twelve months ahead. Edit a product safely by sending the ETag you read as If-Match; cut a list with ?fields=; write up to 50 values at once with POST /public/app-data/bulk.
The sellstamp CLI has app init (a server that verifies signatures and handles repeats), app dev (a local verifier), app webhooks test, app deploy, app logs, app test-store and app conformance; the last four use a key with the apps.develop scope. Conformance checks that you verify signatures, refuse forgeries, handle a repeated event id and ignore events you do not know; a reviewer sees the result. See docs/API_CHANGELOG.md.
Storefront widgets
Declare storefront_widgets (a path on your origin, a fixed height, and one sentence saying what it receives). A merchant places the widget on a page; the visitor sees that sentence and your origin first, and your page loads only after they press the button, in a sandboxed frame with no cookies or storage, never on checkout, payment, order or account pages. Merchants can switch it off at any time. See docs/PUBLIC_API.md.
The reference app
examples/reference-app in the repository is a one-file, dependency-free app that does all of the above. It is the template to copy, and the fixture Sellstamp's own tests run end to end.
Sellstamp