Concept Developers

API overview: the merchant and company APIs

The platform's two public APIs: the merchant API at /api/v1 (sk_ key) and the company API at /api/company/v1 (ck_ key), who can use them, how versions work and the JSON envelope every response uses.

Last updated 22 October 2026 · Last verified 22 October 2026

Purpose#

The platform has two public REST APIs for connecting your own systems (an ERP, an app, a custom shop). Both exchange JSON, identify you with a Bearer API key and answer in the same envelope. Endpoint details are in the Merchant API reference and the Company API reference.

The two public APIs#

Merchant API Company API
Base path /api/v1 /api/company/v1
Who it is for A merchant: price, create, list, track and cancel parcels, read the statement, manage webhook endpoints A delivery company: read its merchants and couriers, list and create parcels, assign a courier, update a parcel's status
Key prefix sk_ ck_
Where you get the key Merchant panel: Integration, then Webhook and API Company panel: Integrations and API

The full address is your platform's domain plus the base path. Each of those pages has an API documentation button, and the panel shows the exact Base URL (at the bottom of the API key card for companies, in the Quick start section of the documentation page for merchants). Other endpoints under /api are not documented here: the mobile app API and store webhooks are internal, and a key-based endpoint (POST /api/parcel/create-with-security, with X-Platform) serves store and custom platforms. Use /api/v1 or /api/company/v1 for new integrations.

Who can use it#

  • Merchant API: platform merchants. A merchant who belongs to a delivery company cannot use it: the panel page shows a notice and returns to the dashboard, and the API answers 403 with api_not_allowed. A merchant who owns an internal delivery company is still a platform merchant.
  • Company API: the company admin creates the key. The company needs an active subscription and a plan that includes the API feature; platform-owned and merchant-owned companies are exempt from both.
  • Plans: when merchant plans are in use, the merchant needs an active plan with the API feature. A new merchant plan starts with the API off until the super admin turns it on; a new company plan starts with it on; an old plan with unconfigured features allows everything.

How versions work#

  • The version is part of the path. Both APIs are at v1; there is no version header and no other version.
  • The merchant in-panel documentation says new fields can be added without notice (ignore fields you do not know) and a breaking change would be a new version; the company documentation only says new fields may be added and unknown ones ignored.
  • Build your logic on the parcel stage (a simplified, fixed set of states). Use status_code and status_label for the exact status and for display, and branch on error.code rather than on error.message.

The response envelope#

Every response from these APIs uses one of two shapes.

json
{ "success": true, "data": { "id": 1 }, "meta": { "page": 1, "per_page": 20, "total": 132, "last_page": 7 } }
json
{ "success": false, "error": { "code": "validation_failed", "message": "...", "fields": { "customer_phone": ["..."] } } }
  • meta appears only on paginated lists (page, per_page, total, last_page): merchant GET /parcels and GET /statement, company GET /merchants and GET /parcels. Other lists are plain arrays in data. No links.
  • error.code is a short snake_case code: program against it, not against error.message. The message is Arabic by default and English with Accept-Language: en.
  • fields appears on most validation errors (a few company API ones carry only message), retry_after on rate_limited, reference on server errors.
  • Timestamps on parcels, events, statement lines and webhook endpoints are ISO 8601 with a UTC offset. The plan expiry in GET /me is a plain string: YYYY-MM-DD for merchants and YYYY-MM-DD HH:MM:SS for companies. Money amounts inside parcel objects are in US dollars.
  • Always send Accept: application/json. Errors raised before the API code runs (unknown path, wrong HTTP method, the general and route request limits) use a different format, {"message": "..."}, or an HTML page without the header.

Quick start#

  1. Confirm that your plan includes the API

    Merchants: the "Plan and subscription" page lists each plan's features, including the API entry and its limits. Companies: the "Company plan" card on the "Integrations and API" page lists your plan's features.

  2. Generate an API key

    Follow Authentication and API keys.

  3. Call the account endpoint

    GET /me returns your account details and proves that the key works. For the company API use /api/company/v1/me.

    bash
    curl https://YOUR_DOMAIN/api/v1/me \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Accept: application/json"
    
  4. Create and follow parcels

    See the two API references.

  1. Your current API keys (shown masked)
  2. The name of the platform or system you connect
  3. Generate a new key
  4. Open the API documentation
API keys and connecting your system (demo data)

Common mistakes#

  • Wrong key type. A ck_ key on /api/v1, or a sk_ key created for a store platform, gives 401 and invalid_key.
  • Key outside the header. A key in the query string or body is ignored: 401 and unauthenticated.
  • Planning around 120 or 300 requests per minute. The general 60 per minute per IP address applies too.
  • Putting the key in a mobile app or browser code. Keep it on your server.

Limits and permissions#

  • Rate limits. Three layers apply: a general limit of 60 requests per minute per IP address on every /api request; route limits (merchant 120 per minute, 60 for POST /parcels, 30 for GET /statement; company 300 per minute, 120 for POST /parcels), counted per IP address on one shared counter, so a POST /parcels request counts against both its group limit and its own and these are not separate quotas (because each one is counted twice, one IP address can in practice create only about 30 parcels per minute with the merchant API and about 60 with the company API, and fewer if it also makes other calls in the same minute); and plan limits per account (per minute and per day). Plan limits return 429 with rate_limited, retry_after in seconds and a Retry-After header; the general and route limits return 429 with {"message": "Too Many Attempts."}. Plan for at most 60 requests per minute per IP address.
  • Webhooks. Notifications to your system are configured separately, with the merchant API's /webhooks endpoints or in the panel; the company API has no webhook endpoints (use the panel).

API

  • GET /api/v1/me
  • GET /api/company/v1/me