The API connects Marketplace with your accounting system: export products, update prices and stock, fetch orders. It is available to verified sellers with an active shop.
All requests are POST to a single address:
https://YOUR-PROJECT-REF.supabase.co/functions/v1/secure-action
The token is passed in a header, the method — in the action field of the body:
Authorization: Bearer sg_live_your_token
Content-Type: application/json
{ "action": "api_products_list", "payload": { "limit": 50 } }
| Rule | Value |
|---|---|
| Request rate | 60 per minute per token |
| Exceeded | HTTP 429, error: "rate_limited" |
| Products per request | up to 200 |
| Items per update | up to 200 |
| Active tokens | up to 5 |
A token gets only the permissions you selected. A script that syncs stock should not be able to change prices.
| Permission | Grants |
|---|---|
listings:read | Read products and stock |
listings:write | Change the price |
stock:write | Change the stock |
orders:read | Read orders |
The seller's products with current stock. Requires listings:read.
{
"action": "api_products_list",
"payload": { "limit": 100, "offset": 0 }
}
Response:
{
"success": true,
"products": [
{
"id": "8f3c…",
"title": "Sneakers",
"price": 49,
"currency": "USD",
"status": "active",
"product_type": "physical",
"city": "Dubai",
"created_at": "2026-08-01T10:00:00Z",
"stock": { "quantity": 12, "reserved": 2 }
}
]
}
stock is null if stock is not tracked for the product.
reserved — how many units are held by active orders.
Bulk update of prices and stock. Requires stock:write
or listings:write.
{
"action": "api_products_update",
"payload": {
"items": [
{ "id": "8f3c…", "quantity": 10 },
{ "id": "9a21…", "quantity": 0, "price": 54 }
]
}
}
The response comes for each item separately — one error doesn't cancel the others:
{
"success": true,
"results": [
{ "id": "8f3c…", "ok": true },
{ "id": "9a21…", "ok": false, "error": "below_reserved", "reserved": 3 }
]
}
below_reserved with the number. Otherwise buyers would be left
with confirmed orders and no goods.
The seller's orders. Requires orders:read.
{
"action": "api_orders_list",
"payload": { "limit": 50, "status": "pending" }
}
Order statuses:
| Status | Meaning |
|---|---|
pending | Waiting for the seller's response |
confirmed | Confirmed |
paid | Paid |
shipped | Shipped or handed over |
completed | Received, closed |
returned | Not picked up, returned |
declined | Declined by the seller |
expired | The seller didn't respond in time |
cancelled | Cancelled by the buyer |
To avoid polling orders in a loop, set the address for notifications in the
“Integrations” section. https only; internal addresses are not accepted.
Each event arrives as a separate POST:
POST https://your-endpoint/webhook
X-Webhook-Event: order.created
X-Webhook-Delivery: 4b7e…
X-Webhook-Signature: 9c1f…
{
"event": "order.created",
"delivery_id": "4b7e…",
"created_at": "2026-08-21T09:12:00Z",
"data": {
"order_id": "…",
"public_no": "SG-2608-41207",
"kind": "physical",
"status": "pending",
"city": "Dubai",
"items_total": 49,
"currency": "USD",
"expires_at": "2026-08-22T09:12:00Z"
}
}
X-Webhook-Signature is an HMAC-SHA256 of the request body,
signed with the secret from the “Integrations” section. Verifying it is
mandatory: without it anyone could call your endpoint.
// Node.js
const crypto = require('crypto');
function verify(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody) // the raw body, not JSON.parse
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signature)
);
}
Respond with a 2xx code. If there is no response or an error comes back, the delivery is retried after 1, 5 and then every 25 minutes, up to six times in total. After twenty failures in a row the endpoint is disabled automatically.
A retry has the same delivery_id — use it so as not to
process one event twice.
| Event | When |
|---|---|
order.created | A buyer placed an order |
order.updated | The order status changed: confirmed, declined, paid, shipped, completed or cancelled |
chat.message | A new chat message (off by default) |
order.updated carries status, and also
tracking_number and carrier once the shipment
has been created. The order is identified by order_id.
| Code | error | Reason |
|---|---|---|
| 401 | no_token | No Authorization header |
| 401 | bad_token | The token is invalid or revoked |
| 403 | scope_required | The token lacks the required permission |
| 429 | rate_limited | More than 60 requests per minute |
| 400 | no_items | Empty list in an update |
| 400 | too_many | More than 200 items |
Integration questions — support@example.com. If a token has leaked, revoke it in the dashboard and issue a new one: the old one stops working immediately.