API & webhooks v1
Automate your store: manage products and stock, read orders, issue refunds and receive signed event notifications.
Authentication
Create a key in Dashboard → API keys. Send it as a Bearer token. Each key only ever sees its own shop. Limit: 120 requests/minute per key (HTTP 429 beyond). Money is always an integer in minor units (cents) plus a currency code.
curl https://mail.sellpass.net/api/v1/ping \ -H "Authorization: Bearer sk_live_…" \ -H "Accept: application/json"
Errors use standard HTTP codes with {"message": "…", "errors": {…}}. Lists return {"data": [...], "meta": {current_page, last_page, per_page, total}}.
Shop
| GET | /ping | Verify your key; returns the shop slug and currency. |
Products
| GET | /products | List products. Filters: type, group_id, q, per_page (≤100). |
| POST | /products | Create. Body: title, type (serials|file|service|dynamic|subscription), price (minor units), currency, description, visibility, group_id… |
| GET | /products/{id} | Product detail incl. variants, custom fields, images. |
| PUT | /products/{id} | Update any field from create (except type). |
| DELETE | /products/{id} | Delete (soft — order history is kept). |
| GET | /products/{id}/stock | Serial counts: available / reserved / delivered. |
| POST | /products/{id}/stock | Add serials. Body: {"items": ["KEY-1", "KEY-2"], "variant_id": null}. Duplicates skipped. |
| DELETE | /products/{id}/stock | Remove unsold serials (all, or {"items": [...]}). |
Categories
| GET | /groups | List categories. |
| POST | /groups | Create: name, visibility, sort. |
| PUT | /groups/{id} | Update. |
| DELETE | /groups/{id} | Delete (products are kept, uncategorised). |
Coupons
| GET | /coupons | List coupons. |
| POST | /coupons | Create: code, type (percent|fixed), value (percent in basis points: 1000 = 10%; fixed in minor units), scope, targets[], min_order, max_uses, per_customer_uses, starts_at, expires_at. |
| PUT | /coupons/{id} | Update is_active, value, max_uses, expires_at. |
| DELETE | /coupons/{id} | Delete. |
Orders
| GET | /orders | List. Filters: status, email, gateway, from, to. |
| GET | /orders/{uuid} | Order with items and delivered content. |
| POST | /orders/{uuid}/complete | Mark paid (unpaid orders), release (held orders) or fulfilled (service orders). |
| POST | /orders/{uuid}/void | Void an unpaid order and release its stock. |
| POST | /orders/{uuid}/replace | Deliver a replacement serial. Body: item_id (optional). |
| POST | /orders/{uuid}/refund | Refund through the gateway. Body: amount (minor units, default full). |
| POST | /payments | Create an order and get a pay URL: product_id, quantity, email, gateway, variant_id, coupon_code, custom_fields{}. |
Customers & blacklist
| GET | /customers | Buyers aggregated by email: orders, total_spent, first/last seen. |
| GET | /blacklist | Your Fraud Shield rules. |
| POST | /blacklist | Add: type (email|email_domain|ip|cidr|country|custom), value, note. |
| DELETE | /blacklist/{id} | Remove a rule. |
Feedback & tickets
| GET | /feedback | Reviews (filter: rating). |
| POST | /feedback/{id}/reply | Public seller reply. |
| GET | /tickets | Support tickets (filter: status). |
| GET | /tickets/{id} | Ticket with messages. |
| POST | /tickets/{id}/reply | Reply (emails the buyer). Body: body, close. |
Webhooks
Add endpoints in Dashboard → Webhooks. We POST JSON and retry failed deliveries (non-2xx or timeout after 10 s) up to 5 times: after 1 min, 5 min, 30 min, 2 h and 6 h. Every attempt is logged with the response so you can debug and resend.
order:createdorder:paidorder:partialorder:completedorder:cancelledorder:refundedorder:disputedorder:on_holdproduct:stock_lowquery:createdquery:repliedfeedback:receivedsubscription:createdsubscription:renewedsubscription:cancelled POST https://your-server/hook
X-Signature: 3f1c… (hex HMAC-SHA512 of the raw body, keyed with your webhook secret)
X-Event: order:paid
X-Delivery-Id: evt_…
{"id":"evt_…","event":"order:paid","created_at":"2026-01-01T12:00:00+00:00",
"data":{"uuid":"…","status":"completed","customer_email":"buyer@example.com","total":1299,"currency":"USD","items":[…]}}
Verify the signature (PHP)
$raw = file_get_contents('php://input');
$expected = hash_hmac('sha512', $raw, getenv('WEBHOOK_SECRET'));
if (! hash_equals($expected, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}
$event = json_decode($raw, true); // dedupe on $event['id']
Node.js
const crypto = require('crypto');
const expected = crypto.createHmac('sha512', process.env.WEBHOOK_SECRET).update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.get('X-Signature') || ''));
Dynamic products
For products generated on demand (license servers, account creation). After payment we POST the order to your URL; the response body (≤64 KB, within 10 s) is delivered to the buyer. The request is signed exactly like webhooks with the product's signing secret. Only public addresses are allowed; redirects are not followed. If your server fails, the order stays "paid · to fulfil" and you can deliver manually.
{"event":"order:paid","invoice":"…","product_id":12,"variant_id":null,"quantity":1,
"customer_email":"buyer@example.com","custom_fields":{"Username":"neo"},"total":999,"currency":"USD"}
Embed a Buy button
<script src="https://mail.sellpass.net/embed.js" async></script> <button data-sellpass-shop="your-shop" data-sellpass-product="product-slug">Buy now</button>