Skip to main content

Overview

Your platform pushes events to Vambe as they happen. Each event is a canonical JSON payload — you map your own data onto Vambe’s shape, so there is no per-provider code on Vambe’s side. All inbound endpoints are:
POST https://api.vambe.me/api/public/apps/{appId}/events/{event}
EventPathPurpose
Order/events/orderA paid/created order.
Checkout/events/checkoutAn abandoned checkout to recover.
Fulfillment/events/fulfillmentA shipment created/updated.
Product upsert/events/productCreate or update a product.
Product delete/events/product/deleteRemove a product.

Authenticating your webhooks

Every request must be signed with your app’s signing secret (the signing_secret from Create Your App). Compute an HMAC-SHA256 (hex) over the string {timestamp}.{rawBody} and send:
HeaderValue
x-vambe-timestampCurrent time in epoch milliseconds.
x-vambe-signatureHMAC_SHA256(signing_secret, "{timestamp}.{rawBody}") as hex.
Sign and send the exact same body bytes. Vambe verifies the signature against the raw request body — re-serializing differently will fail verification. Requests older than 5 minutes are rejected.
import crypto from 'crypto';

function postEvent(appId, event, payload, signingSecret) {
  const timestamp = Date.now().toString();
  const body = JSON.stringify(payload); // sign and send these exact bytes
  const signature = crypto
    .createHmac('sha256', signingSecret)
    .update(`${timestamp}.${body}`)
    .digest('hex');

  return fetch(`https://api.vambe.me/api/public/apps/${appId}/events/${event}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-vambe-timestamp': timestamp,
      'x-vambe-signature': signature,
    },
    body,
  });
}
A 2xx response means the event was accepted. Retry on any non-2xx — Vambe is idempotent on the entity’s external id.

The envelope

Every payload is an envelope with two optional routing fields plus the entity:
{
  "external_store_id": "store_12345",
  "event_id": "evt_abc",
  "order": { "...": "..." }
}
external_store_id
string
Your identifier for the merchant store. Used to resolve the installation (see below).
event_id
string
Your event id. Advisory today; reserved for explicit de-duplication.

Resolving the installation

A single app can be installed by many merchants, so Vambe must map each webhook to the right installation:
  • Multi-store: send external_store_id matching the external_id Vambe captured from your account_info_url. Vambe resolves by (app, external_id).
  • Single installation: if the app has exactly one installation, it resolves automatically even without external_store_id.
If no installation can be resolved, Vambe responds 404.

Order

POST /api/public/apps/{appId}/events/order
{
  "external_store_id": "store_12345",
  "order": {
    "external_id": "1001",
    "external_name": "#1001",
    "currency": "CLP",
    "total_price": 29990,
    "status_url": "https://myecommerce.com/orders/1001/status",
    "details_url": "https://admin.myecommerce.com/orders/1001",
    "customer": {
      "name": "Jane Doe",
      "phone": "+56912345678",
      "email": "jane@example.com"
    },
    "line_items": [
      { "external_product_id": "sku-001", "quantity": 2 }
    ],
    "metadata": { "note": "gift wrap" }
  }
}
The customer phone is the most important field: it is how Vambe links the order to the WhatsApp contact. Send it in E.164 format when possible. Products are matched by external_product_id against the catalog you synced.

Checkout (abandoned)

POST /api/public/apps/{appId}/events/checkout
{
  "external_store_id": "store_12345",
  "checkout": {
    "external_id": "chk_555",
    "external_name": "Checkout 555",
    "currency": "CLP",
    "total_price": 19990,
    "recover_url": "https://myecommerce.com/checkout/chk_555",
    "details_url": "https://admin.myecommerce.com/checkouts/chk_555",
    "customer": {
      "name": "Jane Doe",
      "phone": "+56912345678",
      "email": "jane@example.com"
    },
    "line_items": [
      { "external_product_id": "sku-001", "quantity": 1 }
    ]
  }
}
customer.phone and recover_url are required for recovery: Vambe resolves (or creates) the contact by phone and records the abandoned checkout with its recovery link.

Fulfillment

POST /api/public/apps/{appId}/events/fulfillment
{
  "external_store_id": "store_12345",
  "fulfillment": {
    "order_external_id": "1001",
    "fulfillment_external_id": "ful_900",
    "tracking_number": "TRACK123",
    "type": "delivery",
    "delivery_address": {
      "recipient_name": "Jane Doe",
      "phone": "+56912345678",
      "address_line_1": "Av. Siempre Viva 742",
      "address_line_2": null,
      "city": "Santiago",
      "region": "RM",
      "country": "CL",
      "postal_code": "8320000"
    }
  }
}
FieldNotes
order_external_idLinks the shipment to the order.
fulfillment_external_idUnique id of this fulfillment (Vambe upserts on it).
typedelivery or pickup (defaults to delivery).

Products

Products are incremental — each event affects only the product you send. Vambe never deletes the rest of your catalog from a webhook.

Upsert (create or update)

POST /api/public/apps/{appId}/events/product
{
  "external_store_id": "store_12345",
  "product": {
    "external_id": "sku-001",
    "name": "Premium Coffee Beans",
    "description": "Arabica from Colombia, medium roast.",
    "price": 12990,
    "currency": "CLP",
    "sku": "COF-001",
    "file_url": "https://cdn.myecommerce.com/coffee.jpg",
    "image_urls": ["https://cdn.myecommerce.com/coffee.jpg"],
    "metadata": [{ "key": "roast", "value": "medium" }]
  }
}
Vambe upserts by (external_id, store): a new external_id is created, an existing one is updated. Product embeddings (for AI search and recommendations) run automatically.

Delete

POST /api/public/apps/{appId}/events/product/delete
{
  "external_store_id": "store_12345",
  "external_id": "sku-001"
}
This soft-deletes the product for that store.
Catalog over webhook is the push model. If you’d rather have Vambe pull your full catalog instead, that is handled by the products_list outbound capability — talk to the Vambe team about which model fits your platform.