Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tybritelabs.com/llms.txt

Use this file to discover all available pages before exploring further.

The OrdersService class (accessed via client.orders) manages the entire commerce lifecycle. All order write operations require mandatory HMAC Security to ensure complete data integrity.

πŸ” Security & Signing (HMAC)

To prevent tampering, replay attacks, and duplicate processing of updates, createOrder and updateOrder require both an HMAC-SHA256 signature and a mandatory Idempotency Key.

Signing Process

  1. Generate Timestamp: Get the current Unix timestamp in seconds.
  2. Prepare Payload: Concatenate the timestamp and the JSON request body with a dot: timestamp + "." + JSON_body.
  3. Generate Signature: Compute an HMAC-SHA256 signature of the payload using your HMAC Secret (found in Settings β†’ Integration Settings).
  4. Base64 Encode: The resulting signature must be Base64 encoded.

Code Implementation (TypeScript/Node.js)

import crypto from 'crypto';

// 1. Define Signing Helper
function generateHmacSignature(payload: string, secret: string): string {
  return crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('base64');
}

// 2. Prepare Data & Sign
const timestamp = Math.floor(Date.now() / 1000);
const body = JSON.stringify(orderData);
const payload = `${timestamp}.${body}`;
const signature = generateHmacSignature(payload, hmacSecret);

// 3. Execute request with headers
const order = await client.orders.createOrder({
  idempotencyKey: `order-${timestamp}`,
  xTimestamp: timestamp,
  xSignature: signature,
  requestBody: orderData
});
NEVER expose your HMAC Secret client-side. Signing should always occur on a secure backend server. Requests with missing or invalid signatures will return 401 Unauthorized.

Core Operations

createOrder

Place a new order. Returns 201 Created (semantic create) with the new order resource. Requires verified signatures and idempotency protection.
  • Required body fields: total_amount, payment_method, and a non-empty items array. Each item requires product_id.
  • Optional: customer_id (guest checkout is supported), billing_address, shipping_address (both nullable), variant_id per item (defaults to the product’s primary variant), and gift_card_redemption.
  • Replay Protection: The X-Timestamp must be within 5 minutes of the server time.
  • Post-processing: When payment_status: "paid" is set, the worker runs gift card redemption, stock reduction, and customer metrics updates. See Post-Processing Warnings below β€” the response may include a post_processing_warnings array that clients must check.
const order = await client.orders.createOrder({
  idempotencyKey: `order-${Date.now()}-abc123`,
  xTimestamp: Math.floor(Date.now() / 1000),
  xSignature: hmacSignature, // base64 HMAC-SHA256 of `${timestamp}.${body}`
  requestBody: {
    total_amount: 5000,
    payment_method: 'card',
    customer_id: 'optional-customer-uuid',
    items: [
      { product_id: 'product-uuid', quantity: 2, unit_price: 2500 }
    ],
    payment_status: 'paid' // triggers inventory + accounting + metrics
  }
});
// order.id is the new order UUID
// order.post_processing_warnings is undefined OR present with details

Post-Processing Warnings

When an order is created with payment_status: "paid", the worker runs post-processing in this order:
  1. Gift card redemption (if gift_card_redemption provided)
  2. Stock reduction per item via atomic RPC
  3. Customer metrics update via atomic RPC (no lost-update races)
If any step fails, the order is still recorded β€” but the response includes a post_processing_warnings array AND the order’s notes field is stamped with a tag ([GIFT_CARD_REDEMPTION_FAILED] or [STOCK_REDUCTION_PARTIAL]). Clients MUST check this array and route failures to a support or retry flow.

Response shape

{
  id: 'order-uuid',
  // ... full order fields
  post_processing_warnings: [
    {
      stage: 'gift_card_redemption',
      message: 'Gift card redemption failed: insufficient balance. The order was created but no gift card credit was applied. Please contact support.'
    }
    // OR
    {
      stage: 'stock_reduction',
      message: 'Some inventory updates failed. Order is recorded; an operator will reconcile stock manually.'
    }
  ]
}

Handling pattern

const order = await client.orders.createOrder({ /* ... */ });

if (order.post_processing_warnings?.length) {
  for (const warning of order.post_processing_warnings) {
    if (warning.stage === 'gift_card_redemption') {
      // Alert the customer + create a support ticket
      // The customer paid full price but the gift card credit was not applied
      await flagForRetry(order.id, warning);
    }
    if (warning.stage === 'stock_reduction') {
      // Notify ops; inventory needs manual reconciliation
      console.warn('Stock reconciliation needed for order', order.id);
    }
  }
}
Customer metrics (total_purchases, lifetime value) are incremented via the atomic increment_customer_purchase_stats RPC. This eliminates lost-update races under concurrent order load, so purchase counts remain correct at high throughput. This is transparent to clients.

getOrder

Retrieve complete details for a specific order.
Reading orders requires a Secret Key. Publishable keys receive 403 Forbidden. Order data contains customer PII, addresses, and payment status β€” it must not be exposed to browsers.
const client = new Tybrite({ apiKey: process.env.TYBRITE_SECRET_KEY });
const order = await client.orders.getOrder({ id: 'order-uuid' });

updateOrder

Update fulfillment or payment status. Requires HMAC signature and Idempotency Key.
  • Idempotency: Use a unique key for each distinct update (e.g., update-payment-{order_id}-{timestamp}).
  • Protection: This prevents double-triggering side effects like accounting entries or inventory reduction on network retries.
const updated = await client.orders.updateOrder({
  id: 'order-uuid-here',
  idempotencyKey: `update-status-${orderId}-${Date.now()}`,
  xTimestamp: Math.floor(Date.now() / 1000),
  xSignature: '...',
  requestBody: {
    payment_status: 'paid', // Triggers auto-accounting & inventory reduction
    order_status: 'shipped',
    tracking_number: 'CARGO-123-ABC'
  }
});

Security & Error Handling

Error CodeMeaningResolution
401 UnauthorizedInvalid HMAC signatureVerify your secret key and payload concatenation.
401 UnauthorizedMissing X-TimestampEnsure the X-Timestamp header is sent.
401 UnauthorizedExpired TimestampEnsure your server clock is synced (5-min window).
403 ForbiddenPublishable Key UsedCreate orders using a Secret Key only.

Side Effects of payment_status: 'paid'

Transitioning an order to the paid state automatically triggers:
  1. Inventory Sync: Live stock reduction across variants.
  2. Accounting Engine: Double-entry bookkeeping entry creation.
  3. LTV Update: Increments customer lifetime value and purchase counts (via atomic RPC β€” safe under concurrent load).
  4. Promoter Logic: Marks loyalty points and promotion usage as finalized.

Response Codes

CodeEndpointMeaning
201POST /v1/ordersOrder created. Response includes post_processing_warnings? if any post-paid step failed.
200GET /v1/orders/{id}, PATCH /v1/orders/{id}Success. PATCH returns the updated order.
400AllInvalid request body β€” missing total_amount / payment_method / items, per-item missing product_id, or invalid tax/subtotal for a tax-exclusive store.
401AllInvalid API key, or invalid / expired HMAC signature.
403Read & writePublishable key used on an order endpoint. Orders are secret-key only.
404AllOrder not found, or a product_id referenced in items not found.
409POST /v1/ordersIdempotency key reused with a different payload.
429POST / PATCHRate limit exceeded (100/hr per key).
500AllServer error.