API Reference

Vectis provides a REST API for orders, products, inventory, and webhooks, documented in OpenAPI 3.1, with HMAC-signed webhooks.

Base URL

API requests use your tenant subdomain:

https://{tenant}.vectisoms.app

Where {tenant} is your organization’s subdomain (e.g., acme.vectisoms.app). Endpoint paths below already include the /api prefix (except /health), so a full URL looks like https://acme.vectisoms.app/api/orders.

Authentication

All API requests require a Bearer token in the Authorization header, obtained via OAuth 2.0 client credentials flow.

Obtaining a Token

Request an access token from the OAuth endpoint:

curl -X POST https://api.vectisoms.app/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"

Response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "orders:read orders:write inventory:read inventory:write products:read products:write"
}

Making Requests

Include the token in the Authorization header:

curl https://acme.vectisoms.app/api/orders \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Organization owners create API Clients in the Vectis account portal (the Control Plane link in the app sidebar), under Organization Settings → Developer → API Clients. (The same tab also lists API Keys; for the Vectis API, use an API Client.) The secret is shown once. Contact support@stoalogistics.com if you need assistance.

API client tokens currently have read access to orders, products, and inventory, and can manage webhook subscriptions. To create or change orders, products, or inventory through the API, contact support@stoalogistics.com.

Common Endpoints

Orders

MethodEndpointDescription
GET/api/ordersList orders with filtering and pagination
POST/api/ordersCreate a new order
POST/api/orders/bulk-importBulk import up to 500 orders (JSON body with format and data: an array of orders or CSV text)
GET/api/orders/{id}Get order details
PATCH/api/orders/{id}Confirm an order or mark it delivered (status: confirmed or delivered)
POST/api/orders/{id}/cancelCancel an order

Products

MethodEndpointDescription
GET/api/productsList products
POST/api/productsCreate a product
GET/api/products/{id}Get product details
GET/api/products/sku/{sku}Get product by SKU
PATCH/api/products/{id}Update product
DELETE/api/products/{id}Delete a discontinued product (soft delete)

Inventory

MethodEndpointDescription
GET/api/inventoryList inventory levels
POST/api/inventoryCreate inventory record
GET/api/inventory/{id}Get inventory item
PATCH/api/inventory/{id}/adjustAdjust inventory quantity

Webhooks

MethodEndpointDescription
GET/api/webhooksList webhook subscriptions
POST/api/webhooksCreate webhook subscription
DELETE/api/webhooks/{id}Delete webhook subscription

System

MethodEndpointDescription
GET/healthSystem health check

Request Format

Most requests use JSON. Bulk order import takes a JSON body {"format": "json", "data": [orders]} or {"format": "csv", "data": "<csv text>"} (one order per row); see POST /api/orders/bulk-import.

Order creation request body:

POST /api/orders
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "externalId": "SHOP-12345",
  "customerId": "cust_john123",
  "customerEmail": "john@example.com",
  "items": [
    { "sku": "WIDGET-BLU", "quantity": 2 },
    { "sku": "GADGET-RED", "quantity": 1 }
  ],
  "shippingAddresses": [{
    "name": "John Doe",
    "line1": "123 Main St",
    "city": "Phoenix",
    "region": "AZ",
    "postalCode": "85001",
    "country": "US"
  }],
  "billingAddress": {
    "name": "John Doe",
    "line1": "123 Main St",
    "city": "Phoenix",
    "region": "AZ",
    "postalCode": "85001",
    "country": "US"
  }
}

Line prices come from your product catalog.

Addresses

Shipping and billing address objects accept line1 as today, and also street1 as an alias for the same field. Use whichever your upstream system already emits.

Order line items in responses

When present on an order, line items may include cost fields for operations and integrations: unitCost, costCurrency, and lineCost. Treat them as optional; availability can depend on your catalog and tenant configuration.

Response Format

Successful responses return JSON with the resource:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "total": 109.97,
  "itemCount": 3,
  "createdAt": "2026-01-15T10:30:00Z"
}

Errors return a non-2xx status and a JSON body with an error field. Depending on the endpoint, error is a message string, an object with code and message, or, for request validation failures (HTTP 400), an object with an issues list. Branch on the HTTP status code.

Pagination

The order and product lists support pagination (limit default 20, max 100; offset default 0):

GET /api/orders?limit=50&offset=0

Paginated list responses include limit, offset, and total inside the pagination object so you know how many records match the query, not just the current page.

Response includes pagination metadata:

{
  "orders": [...],
  "pagination": {
    "limit": 50,
    "offset": 0,
    "total": 1234
  }
}

Filtering

Filter by query parameters:

GET /api/orders?status=pending&q=SHOP-12345&fromDate=2026-01-01

Webhooks

Create webhooks through the API (the dashboard form doesn’t send the required signing secret yet), then manage, test, and view deliveries in Settings → Webhooks. All webhooks are signed with HMAC-SHA256.

Verifying Signatures

Each delivery includes X-Vectis-Signature: t=<timestamp>,v1=<signature>. Compute HMAC-SHA256 of <timestamp>.<raw request body> with your webhook secret, compare the hex digest with v1 in constant time, and reject timestamps older than five minutes. Deliveries also carry X-Vectis-Event and X-Vectis-Delivery-Id. See the Webhooks Guide for code.

Event Types

Subscribe with the event names below, or * for all events. Each delivery names its event in the event field and the X-Vectis-Event header: OrderCreated, OrderConfirmed, OrderCancelled, OrderShipped, OrderDelivered, PackageCreated, PackageShipped, PackageDelivered, InventoryAdjusted.

Rate Limits

Rate limits are not published for the tenant API. Some features, such as AI demand forecasting, have their own limits. A 429 whose body has "error": "LIMIT_EXCEEDED" means a plan limit (for example warehouses, carrier accounts or sales channels); retrying won’t clear it. Any other 429 is temporary: wait and retry with backoff.

Idempotency

To retry POST /api/orders safely, send an Idempotency-Key header. A repeat request with the same key within 24 hours returns the original order instead of creating a new one. externalId is not checked for duplicates. No other endpoint on this page supports idempotency keys.

OpenAPI Specification

The public OpenAPI 3.1 spec is at https://stoalogistics.com/openapi.json. Browse it interactively in the API Reference.

SDKs

There are no official SDKs. Use any HTTP client with the REST API.

Support