Skip to content

REST API v1

Sellf provides a full REST API for managing products, users, payments, refunds, coupons, webhooks, and more. Admin API endpoints are under /api/v1/.

Base URL: https://your-domain.com/api/v1

Features:

  • 60+ endpoints covering all admin operations
  • Fine-grained API keys with 13 permission scopes
  • Zero-downtime key rotation with grace period
  • Per-key rate limiting (1–1000 req/min)
  • Cursor-based pagination
  • OpenAPI 3.1 specification

Customer checkout, embedded checkout, Stripe webhook, waitlist signup, and subscription self-service routes live outside /api/v1 because they use browser sessions, public tokens, or Stripe signatures instead of API keys.


1. Create an API key in Settings → API Keys.

2. Make your first request:

Terminal window
curl https://your-domain.com/api/v1/products \
-H "Authorization: Bearer sf_live_your_key_here"

3. Response:

{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Product",
"slug": "my-product",
"price": 2900,
"currency": "USD",
"is_active": true
}
],
"pagination": {
"cursor": null,
"next_cursor": "eyJpZCI6Ii4uLiJ9",
"has_more": true,
"limit": 20
}
}

Two methods are supported:

Pass the key in the Authorization header:

Terminal window
curl https://your-domain.com/api/v1/products \
-H "Authorization: Bearer sf_live_a1b2c3d4..."

Or use the X-API-Key header:

Terminal window
curl https://your-domain.com/api/v1/products \
-H "X-API-Key: sf_live_a1b2c3d4..."

The admin panel uses HTTP-only session cookies (Supabase Auth). Session auth grants full access to all endpoints.

HTTP StatusError CodeMeaning
401UNAUTHORIZEDNo authentication provided
401INVALID_TOKENKey is invalid, expired, or revoked
403FORBIDDENKey lacks required scope
429RATE_LIMITEDToo many requests

PrefixEnvironmentExample
sf_live_Productionsf_live_a1b2c3d4e5f6... (72 chars total)
sf_test_Testingsf_test_a1b2c3d4e5f6... (72 chars total)
  • Keys are SHA-256 hashed before storage — plaintext is never saved
  • The full key is returned only once at creation time
  • Hash comparison uses timing-safe comparison to prevent timing attacks
  • The key_prefix (first 12 chars) is stored for display: sf_live_a1b2
Terminal window
curl -X POST https://your-domain.com/api/v1/api-keys \
-H "Cookie: <session>" \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline",
"scopes": ["products:read", "products:write"],
"rate_limit_per_minute": 120
}'

Response (key shown only once):

{
"data": {
"id": "...",
"name": "CI/CD Pipeline",
"key": "sf_live_a1b2c3d4e5f6...",
"key_prefix": "sf_live_a1b2",
"scopes": ["products:read", "products:write"],
"rate_limit_per_minute": 120,
"created_at": "2026-02-28T12:00:00Z"
}
}

Note: API key management endpoints (/api/v1/api-keys/*) require session auth — you cannot create keys using another key.


Each API key has a scopes array that controls what it can access.

ScopeDescription
products:readView products
products:writeCreate, update, delete products
users:readView users and access records
users:writeManage user access (grant, revoke, extend)
coupons:readView coupons
coupons:writeCreate, update, delete coupons
analytics:readView analytics, reports, and payment data
webhooks:readView webhook configurations
webhooks:writeManage webhooks (create, update, delete, test)
integrations:writeManage tracking and consent integrations
refund-requests:readView refund requests
refund-requests:writeProcess refund requests
system:readView system status and update info
*Full access to all resources

A key with products:write automatically has products:read permission. You don’t need to include both.

Common scope combinations for quick setup:

PresetScopesUse case
Full Access*Admin integrations, MCP server
Read OnlyAll :read scopesDashboards, BI tools, reporting
Analyticsanalytics:readRevenue dashboards
Supportproducts:read, users:read, coupons:readCustomer support team

Rotate keys with zero downtime using a grace period:

Terminal window
curl -X POST https://your-domain.com/api/v1/api-keys/{id}/rotate \
-H "Cookie: <session>" \
-H "Content-Type: application/json" \
-d '{ "grace_period_hours": 24 }'

During the grace period (0–168 hours, default 24):

  • The new key is active immediately
  • The old key continues to work until the grace period expires
  • The new key inherits all scopes from the old key

This allows you to update your integration without any downtime.


Each API key has a configurable rate limit (default: 60 requests/minute, range: 1–1000).

When exceeded, the API returns:

{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Maximum 60 requests per minute."
}
}

HTTP status: 429 Too Many Requests


{
"data": { ... }
}
{
"data": [ ... ],
"pagination": {
"cursor": "eyJpZCI6Ii4uLiJ9",
"next_cursor": "eyJpZCI6Ii4uLiJ9",
"has_more": true,
"limit": 20
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input",
"details": {
"name": ["Name is required"],
"price": ["Price must be positive"]
}
}
}
CodeHTTP StatusDescription
UNAUTHORIZED401No authentication provided
INVALID_TOKEN401Invalid, expired, or revoked key
FORBIDDEN403Missing required scope
VALIDATION_ERROR400Input validation failed
INVALID_INPUT400Malformed request body
NOT_FOUND404Resource not found
CONFLICT409Resource conflict
ALREADY_EXISTS409Duplicate resource
RATE_LIMITED429Rate limit exceeded
INTERNAL_ERROR500Server error
SERVICE_UNAVAILABLE503Service temporarily unavailable

All list endpoints use cursor-based pagination.

ParameterDefaultDescription
limit20Items per page (max 100)
cursorCursor from next_cursor of previous response
searchSearch query (where supported)
sort_byvariesSort field
sort_orderdescasc or desc

Example:

Terminal window
# First page
curl ".../api/v1/products?limit=10"
# Next page (use next_cursor from previous response)
curl ".../api/v1/products?limit=10&cursor=eyJpZCI6Ii4uLiJ9"

All endpoints are prefixed with /api/v1. Every endpoint also supports OPTIONS for CORS preflight.

MethodPathScopeDescription
GET/productsproducts:readList products
POST/productsproducts:writeCreate product
GET/products/{id}products:readGet product
PATCH/products/{id}products:writeUpdate product
DELETE/products/{id}products:writeDelete product
GET/products/{id}/otoproducts:readGet one-time offer config
PUT/products/{id}/otoproducts:writeSet one-time offer
DELETE/products/{id}/otoproducts:writeRemove one-time offer
MethodPathScopeDescription
GET/usersusers:readList users
GET/users/{id}users:readGet user
GET/users/{id}/accessusers:readList user’s product access
POST/users/{id}/accessusers:writeGrant product access
GET/users/{id}/access/{accessId}users:readGet access record
PATCH/users/{id}/access/{accessId}users:writeExtend/modify access
DELETE/users/{id}/access/{accessId}users:writeRevoke access
MethodPathScopeDescription
GET/couponscoupons:readList coupons
POST/couponscoupons:writeCreate coupon
GET/coupons/{id}coupons:readGet coupon
PATCH/coupons/{id}coupons:writeUpdate coupon
DELETE/coupons/{id}coupons:writeDelete coupon
GET/coupons/{id}/statscoupons:readGet usage statistics
MethodPathScopeDescription
GET/paymentsanalytics:readList payments
GET/payments/{id}analytics:readGet payment details
PATCH/payments/{id}analytics:readUpdate payment metadata
GET/payments/statsanalytics:readPayment statistics
POST/payments/exportanalytics:readExport payments (CSV)
POST/payments/{id}/refundrefund-requests:writeRefund a payment, including partial refunds
MethodPathScopeDescription
GET/order-bumpsproducts:readList order bumps
POST/order-bumpsproducts:writeCreate order bump
GET/order-bumps/{id}products:readGet order bump
PATCH/order-bumps/{id}products:writeUpdate order bump
DELETE/order-bumps/{id}products:writeDelete order bump
MethodPathScopeDescription
GET/webhookswebhooks:readList webhooks
POST/webhookswebhooks:writeCreate webhook
GET/webhooks/{id}webhooks:readGet webhook
PATCH/webhooks/{id}webhooks:writeUpdate webhook
DELETE/webhooks/{id}webhooks:writeDelete webhook
POST/webhooks/{id}/testwebhooks:writeSend test event
GET/webhooks/logswebhooks:readList delivery logs
POST/webhooks/logs/{logId}/retrywebhooks:writeRetry failed delivery
POST/webhooks/logs/{logId}/archivewebhooks:writeArchive log entry
MethodPathScopeDescription
PATCH/integrationsintegrations:writeUpdate tracking and consent integrations

Supported fields: gtm_container_id, gtm_server_container_url, gtm_ss_enabled, google_ads_conversion_id, google_ads_conversion_label, facebook_pixel_id, facebook_capi_token, facebook_test_event_code, fb_capi_enabled, send_conversions_without_consent, umami_website_id, umami_script_url, cookie_consent_enabled, consent_logging_enabled.

Supported outgoing event types include purchases, leads, waitlist signups, refund issued events, subscription lifecycle events, and invoice payment events.

MethodPathScopeDescription
GET/analytics/dashboardanalytics:readDashboard overview
GET/analytics/revenueanalytics:readRevenue breakdown
GET/analytics/top-productsanalytics:readTop performing products
MethodPathScopeDescription
GET/refund-requestsrefund-requests:readList refund requests
GET/refund-requests/{id}refund-requests:readGet request details
PATCH/refund-requests/{id}refund-requests:writeProcess (approve/deny)
MethodPathScopeDescription
GET/variant-groupsproducts:readList variant groups
POST/variant-groupsproducts:writeCreate variant group
GET/variant-groups/{id}products:readGet variant group
PATCH/variant-groups/{id}products:writeUpdate variant group
DELETE/variant-groups/{id}products:writeDelete variant group
MethodPathScopeDescription
GET/system/statussystem:readSystem status and version
GET/system/update-checksystem:readCheck for updates
POST/system/upgradesystem:readTrigger self-upgrade
GET/system/upgrade-statussystem:readPoll upgrade progress

These endpoints require admin session authentication — API keys cannot manage other keys.

MethodPathDescription
GET/api-keysList your API keys
POST/api-keysCreate new key (returns secret once)
GET/api-keys/{id}Get key details
PATCH/api-keys/{id}Update key (name, scopes, rate limit)
DELETE/api-keys/{id}Revoke key
POST/api-keys/{id}/rotateRotate with grace period

These routes are intentionally not part of API-key authenticated /api/v1.

MethodPathAuthDescription
POST/api/embed/checkout-sessionPublic origin validationCreate an embedded checkout session for an allowed origin
POST/api/embed/free-accessPublic origin validationGrant access for free embedded products
GET/embed/v1/checkout.jsPublic scriptSelf-hosted checkout embed script for external pages
MethodPathAuthDescription
GET/api/subscriptionsSessionList the current customer’s subscriptions
POST/api/subscriptions/{id}/cancelSessionCancel at period end
POST/api/subscriptions/{id}/resumeSessionResume before the current period ends
MethodPathAuthDescription
POST/api/webhooks/stripeStripe signatureProcess checkout, refund, dispute, subscription, upcoming renewal, and invoice events

Subscribe the Stripe endpoint to the events listed by STRIPE_WEBHOOK_EVENTS in admin-panel/src/lib/constants.ts.

MethodPathAuthDescription
POST/api/waitlist/signupPublic or sessionCapture waitlist signups and dispatch waitlist.signup outgoing webhooks

The OpenAPI 3.1 registry and generator live in admin-panel/src/lib/api/schemas/openapi.ts. Use it as the source for generated API docs or Bruno/Postman imports when exposing a spec endpoint in your deployment.