SARAH

Webhook Events

Complete reference of all available events in Sarah's webhooks

Last updated: 2025-01-26

This is the complete reference of all events supported in Sarah's webhooks, both for inbound and outbound.

Available Events

Sales

sales.created

Triggered when a new sale is created.

Structure:

json
{
  "event": "sales.created",
  "data": {
    "sale": {
      "id": 789,
      "company_id": 42,
      "customer_id": 123,
      "box_id": 5,
      "total": 15000.00,
      "status": "pending",
      "payment_method": "cash",
      "items": [
        {
          "id": 1,
          "product_id": 456,
          "quantity": 2,
          "price": 7500.00,
          "subtotal": 15000.00
        }
      ],
      "created_at": "2025-01-26T12:34:56.789Z"
    }
  }
}

Main fields:

  • id: Unique sale ID
  • company_id: Company ID
  • customer_id: Customer ID (can be null)
  • box_id: Cash register ID
  • total: Sale total
  • status: Status (pending, paid, cancelled)
  • payment_method: Payment method
  • items: Array of sale items

sales.paid

Triggered when a sale is marked as paid.

Structure:

json
{
  "event": "sales.paid",
  "data": {
    "sale": {
      "id": 789,
      "company_id": 42,
      "total": 15000.00,
      "status": "paid",
      "paid_at": "2025-01-26T12:35:00.000Z",
      "payment_method": "mercadopago",
      "payment_id": "mp_payment_123"
    }
  }
}

sales.cancelled

Triggered when a sale is canceled.

Structure:

json
{
  "event": "sales.cancelled",
  "data": {
    "sale": {
      "id": 789,
      "company_id": 42,
      "status": "cancelled",
      "cancelled_at": "2025-01-26T12:36:00.000Z",
      "cancellation_reason": "Customer requested cancellation"
    }
  }
}

Billing

invoice.issued

Triggered when an electronic fiscal receipt (AFIP/ARCA) is issued.

Structure:

json
{
  "event": "invoice.issued",
  "data": {
    "invoice": {
      "id": 101,
      "company_id": 42,
      "sale_id": 789,
      "type": "A",
      "point_of_sale": 1,
      "number": 12345,
      "cae": "12345678901234",
      "cae_expiration": "2025-02-26T00:00:00.000Z",
      "total": 18150.00,
      "issued_at": "2025-01-26T12:37:00.000Z"
    }
  }
}

Main fields:

  • type: Receipt type (A, B, C, etc.)
  • point_of_sale: Point of sale
  • number: Receipt number
  • cae: Electronic Authorization Code
  • cae_expiration: CAE expiration date

Inventory

movement.created

Triggered when an inventory movement is created (entry, exit, transfer, etc.).

Structure:

json
{
  "event": "movement.created",
  "data": {
    "movement": {
      "id": 555,
      "company_id": 42,
      "type": "IN",
      "deposit_id": 10,
      "product_id": 456,
      "amount": 10,
      "reason": "Purchase",
      "created_at": "2025-01-26T12:38:00.000Z"
    }
  }
}

Movement types:

  • IN: Stock entry
  • OUT: Stock exit
  • TRANSFER: Transfer between warehouses
  • ADJUSTMENT: Inventory adjustment

product.upserted

Triggered when a product is created or updated.

Structure:

json
{
  "event": "product.upserted",
  "data": {
    "product": {
      "id": 123,
      "company_id": 42,
      "sku": "ABC-001",
      "name": "Example Product",
      "description": "Product description",
      "base_price": 1500.00,
      "stock": 40,
      "category_id": 5,
      "mark": "Example Brand",
      "enable": true,
      "photo": "https://example.com/photo.jpg",
      "updated_at": "2025-01-26T12:39:00.000Z"
    }
  }
}

Note: This event is triggered both on creation and update. Use updated_at to determine if it's new or updated.

product.stock_updated

Triggered when a product's stock changes.

Structure:

json
{
  "event": "product.stock_updated",
  "data": {
    "product": {
      "id": 123,
      "company_id": 42,
      "sku": "ABC-001",
      "previous_stock": 50,
      "current_stock": 40,
      "change": -10,
      "deposit_id": 10,
      "updated_at": "2025-01-26T12:40:00.000Z"
    }
  }
}

Usage in Inbound

When sending events to Sarah (inbound), you must follow the exact structure shown above. Sarah will validate:

  1. That the event is in the list of supported events
  2. That the data structure is correct according to event type
  3. That required fields are present

Inbound Send Example

http
POST /api/integration/in
Authorization: Bearer sk_live_abc123...
Content-Type: application/json
x-idempotency-key: product.upserted:123

{
  "event": "product.upserted",
  "data": {
    "product": {
      "id": 123,
      "sku": "ABC-001",
      "name": "Updated Product",
      "base_price": 1600.00,
      "stock": 45
    }
  }
}

Usage in Outbound

When receiving events from Sarah (outbound), events will follow the same structure. You can use fields to:

  • Trigger actions: Execute workflows in Make/Zapier
  • Sync data: Update external systems
  • Notifications: Send alerts or emails
  • Analytics: Log events for analysis

Handler Example

javascript
export async function POST(request) {
  const { event, data } = await request.json();

  switch (event) {
    case 'sales.created':
      await notifyNewSale(data.sale);
      await syncToCRM(data.sale);
      break;
    
    case 'product.stock_updated':
      if (data.product.current_stock < 10) {
        await sendLowStockAlert(data.product);
      }
      break;
    
    case 'invoice.issued':
      await sendInvoiceEmail(data.invoice);
      break;
  }

  return new Response(JSON.stringify({ status: 'ok' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' }
  });
}

Extensibility

Sarah is designed to be extensible. In the future new events can be added:

  • customer.created
  • customer.updated
  • deposit.created
  • promotion.activated
  • order.shipped

Unrecognized events are safely ignored (no-op) to maintain forward compatibility.

Best Practices

  1. Handle all events you might need, even if you don't use them now
  2. Validate structure before processing
  3. Use idempotency keys to avoid duplicate processing
  4. Log events for debugging and auditing
  5. Handle errors gracefully - don't fail entire webhook due to one problematic event