Integration Guide
This guide covers the public API for integrating external systems with Vectis OMS.
Support: support@stoalogistics.com
Terms of Service: stoalogistics.com/terms
Authentication
All API requests require a Bearer token in the Authorization header.
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": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Making Requests
curl https://acme.vectisoms.app/api/orders \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Generate client credentials from Settings → API Access in your Vectis dashboard.
Ecommerce Integration
Push orders from your ecommerce platform to Vectis for fulfillment.
Check Inventory Before Selling
GET /api/inventory?sku=WIDGET-001
Authorization: Bearer YOUR_ACCESS_TOKEN
Response:
{
"items": [{
"id": "inv_123",
"sku": "WIDGET-001",
"quantityAvailable": 150,
"quantityReserved": 10,
"warehouseId": "wh_456"
}]
}
Create an Order
POST /api/orders
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"externalId": "SHOPIFY-12345",
"customerId": "cust_jane123",
"customerEmail": "jane@example.com",
"items": [
{ "sku": "WIDGET-001", "quantity": 2, "unitPrice": 29.99 }
],
"shippingAddresses": [{
"name": "Jane Smith",
"line1": "123 Main St",
"city": "Austin",
"region": "TX",
"postalCode": "78701",
"country": "US"
}],
"billingAddress": {
"name": "Jane Smith",
"line1": "123 Main St",
"city": "Austin",
"region": "TX",
"postalCode": "78701",
"country": "US"
}
}
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"total": 59.98,
"itemCount": 2,
"createdAt": "2026-01-26T12:00:00Z"
}
Get Order Status
GET /api/orders/{orderId}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "shipped",
"total": 59.98,
"itemCount": 2,
"items": [...],
"createdAt": "2026-01-26T12:00:00Z"
}
Cancel an Order
Cancel an order before it ships:
POST /api/orders/{orderId}/cancel
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"reason": "Customer requested cancellation"
}
Product Catalog Sync
Keep your product catalog in sync with Vectis.
Create a Product
POST /api/products
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"sku": "WIDGET-001",
"name": "Premium Widget",
"weight": { "value": 1.5, "unit": "lb" },
"dimensions": {
"length": 10, "width": 8, "height": 4, "unit": "in"
}
}
Get Product by SKU
GET /api/products/sku/WIDGET-001
Authorization: Bearer YOUR_ACCESS_TOKEN
Update a Product
PATCH /api/products/{productId}
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"name": "Premium Widget v2",
"weight": { "value": 1.2, "unit": "lb" }
}
Inventory Adjustments
Adjust inventory levels when stock changes outside of Vectis.
PATCH /api/inventory/{id}/adjust
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"adjustment": -5,
"reason": "Damaged goods removed"
}
Webhook Subscriptions
Subscribe to real-time events for order and inventory changes.
Create a Webhook Subscription
POST /api/webhooks
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
{
"url": "https://your-system.com/webhooks/vectis",
"events": ["order.shipped", "order.delivered", "inventory.low_stock"],
"secret": "your-webhook-secret"
}
Available Events
| Event | Description |
|---|---|
order.created | New order received |
order.confirmed | Order confirmed for fulfillment |
order.shipped | Order has shipped (includes tracking) |
order.delivered | Order delivered to customer |
order.cancelled | Order was cancelled |
inventory.adjusted | Inventory level changed |
inventory.low_stock | Stock below reorder threshold |
Webhook Payload Example
{
"event": "order.shipped",
"timestamp": "2026-01-27T14:30:00Z",
"data": {
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS"
}
}
Verify webhooks using HMAC-SHA256 signature in the X-Webhook-Signature header.
Carrier Tracking Webhooks
Vectis receives tracking updates from carriers via webhook endpoints.
Supported carriers: fedex, ups, usps, dhl, ontrac, lasership, amazon
POST /api/webhooks/carriers/{carrier}/tracking
Content-Type: application/json
Payload format varies by carrier. Vectis normalizes all events internally.
Pagination
List endpoints return paginated results:
GET /api/orders?limit=50&offset=100
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 20 | 100 | Items per page |
offset | integer | 0 | - | Items to skip |
Response includes pagination metadata:
{
"orders": [...],
"pagination": {
"limit": 50,
"offset": 100,
"total": 523
}
}
Idempotency
Order creation is idempotent based on externalId. If you submit an order with an externalId that already exists, the existing order is returned instead of creating a duplicate.
This allows safe retries on network failures:
# First request (creates order)
POST /api/orders
{ "externalId": "SHOP-12345", ... }
# Response: 201 Created
# Retry (returns existing order)
POST /api/orders
{ "externalId": "SHOP-12345", ... }
# Response: 200 OK (same order returned)
Webhook Signature Verification
Outbound webhooks include an HMAC-SHA256 signature for verification.
Headers:
X-Webhook-Signature: HMAC signature (hex)X-Webhook-Timestamp: Unix timestamp (seconds)
Verification (Node.js):
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, timestamp, secret) {
// Reject old timestamps (replay protection)
const age = Date.now() / 1000 - parseInt(timestamp);
if (age > 300) return false; // 5 minute window
// Compute expected signature
const signedPayload = `${timestamp}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Rate Limits
- 1000 requests per minute per access token
Response headers:
X-RateLimit-Limit: Max requests per windowX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Window reset (Unix timestamp)
When rate limited (HTTP 429), check the Retry-After header for seconds to wait.
Error Handling
All errors return a consistent format:
{
"error": "ValidationError",
"message": "SKU is required",
"details": { "field": "sku" }
}
| Status Code | Meaning |
|---|---|
| 400 | Bad request / validation error |
| 401 | Invalid or missing access token |
| 404 | Resource not found |
| 409 | Conflict (e.g., order already cancelled) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
API Reference
Full OpenAPI specification available at the API Reference page.
Need Help?
- Technical support: support@stoalogistics.com