SeloraXDEVELOPERS

API Overview

API Overview — v1

Interactive API Explorer: Test the Apps API, Public API, and Webhooks live at api.selorax.io/api/docs. Download the OpenAPI spec (JSON) or YAML to import into Postman via File > Import, or use it to generate client SDKs.

API Version

You are reading the documentation for API v1 — the current and only supported version. All endpoints live under the /api/apps/v1/ namespace. See the Changelog for recent changes and the Migration Guide for versioning policy.

The SeloraX Platform API gives apps programmatic access to store data -- orders, products, customers, inventory, billing, and more. All endpoints live under the /api/apps/v1/ namespace and require app authentication.

Base URLs

EnvironmentBase URL
Productionhttps://api.selorax.io
Developmenthttps://api-dev.selorax.io

All paths in this reference are relative to the base URL. For example, GET /api/apps/v1/orders in production resolves to:

https://api.selorax.io/api/apps/v1/orders

Authentication

Every API request must include authentication credentials. The platform supports two methods:

Bearer Token

Pass a session token obtained via the OAuth flow in the Authorization header:

Authorization: Bearer <token>

Client Credentials (Server-to-Server)

For background/server-side requests, pass your app's credentials directly:

X-Client-Id: sx_app_...
X-Client-Secret: sx_secret_...
X-Store-Id: 22

Both methods resolve to the same auth context. See the Authentication guide for details on obtaining credentials.

Scopes

Each endpoint requires a specific OAuth scope. If your app does not have the required scope, the API returns a 403 insufficient_scope error. Common scopes include:

ScopeRead AccessWrite Access
read:orders / write:ordersList, get ordersCreate, update orders, change status
read:products / write:productsList, get productsCreate, update, delete products
read:customers / write:customersList, get customersUpdate customer info
read:inventory / write:inventoryRead stock levelsAdjust stock
read:discounts / write:discountsList, get discountsCreate, update, delete discounts
read:storeRead store information
read:analytics / write:analyticsRead analytics data
read:metafields / write:metafieldsRead custom fieldsCreate, update, delete metafields
billingCreate charges, manage subscriptions, wallet

Response Format

All responses return JSON with a consistent envelope.

Success

{
  "data": { ... },
  "status": 200
}

List endpoints also include a pagination object. Some endpoints include a message field.

Error

{
  "message": "Invalid client credentials",
  "code": "invalid_client",
  "status": 401
}

The HTTP status code on the response always matches the status field in the body.

Rate Limits

ScopeLimit
Global (all /api/ routes)1,000 requests / minute
Custom app credential endpoints10 requests / 15 minutes
/oauth/token10 requests / minute
/session/verify300 requests / minute

Rate Limit Headers

Every response includes standard rate limit headers:

HeaderDescription
RateLimit-LimitMaximum requests allowed in the current window
RateLimit-RemainingRequests remaining in the current window
RateLimit-ResetSeconds until the rate limit window resets

When you exceed a rate limit the API returns HTTP 429 Too Many Requests. Use the RateLimit-Reset header to determine when to retry:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    if (response.status !== 429) return response;
 
    const resetAfter = response.headers.get("RateLimit-Reset") || 60;
    console.log(`Rate limited. Retrying in ${resetAfter}s...`);
    await new Promise((r) => setTimeout(r, resetAfter * 1000));
  }
  throw new Error("Rate limit exceeded after retries");
}

Pagination

List endpoints support offset-based pagination via query parameters:

ParameterTypeDefaultDescription
pageinteger1Page number (1-indexed)
limitinteger50Items per page (max varies by endpoint)

Example:

GET /api/apps/v1/orders?page=2&limit=50

Paginated responses include a pagination object alongside the data array:

{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 50,
    "total": 120
  },
  "status": 200
}

Use the total field to calculate the number of available pages.

Store Scoping

All requests are automatically scoped to the store_id derived from the authentication context. You cannot access data belonging to other stores. There is no need to pass store_id as a query parameter on data-read endpoints -- it is inferred from your credentials.

Error Codes

The following error codes may appear in the code field of error responses. For a full reference with resolution steps, see the Error Codes page.

CodeHTTP StatusMeaning
missing_token401No Authorization header or client credentials provided
invalid_token401Token is expired, malformed, or revoked
invalid_client401Invalid client_id or client_secret
missing_auth401App authentication required (scope middleware)
missing_store_id400X-Store-Id header required when using client credentials
not_installed401App is not installed for the specified store
store_inactive403Store is suspended or frozen
insufficient_scope403Your app lacks the required scope for this endpoint
invalid_amount400Charge amount is outside the allowed min/max range
invalid_installation400App installation is inactive or not found
charge_not_found404The specified charge does not exist
insufficient_balance400Store wallet balance is too low for the requested debit
duplicate_name409Custom app with this name already exists for the same creator
auth_error500Internal error during authentication

Example Error Response

curl -X GET https://api.selorax.io/api/apps/v1/orders \
  -H "Authorization: Bearer expired_token_here"
{
  "message": "Token is expired or invalid",
  "code": "invalid_token",
  "status": 401
}

Content Type

All request bodies must be sent as application/json. All responses are returned as application/json.

curl -X POST https://api.selorax.io/api/apps/v1/billing/charges \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{ "name": "Pro Plan", "amount": 500.00 }'