API and developers

Webhooks

Receive real-time order events via webhooks.

Overview

Webhooks let your system receive automatic notifications when events occur in YaVendio, such as a new order being created. Instead of polling the API, YaVendio sends an HTTP POST to the URL you configure.

Available events

Event Description
order.created A new order is created
order.status_changed Order status changes

Set up a webhook

1. Register your URL

curl -X POST https://api.ya.onl/v1/webhooks \
  -H "X-API-Key: yv_live_v1_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/yavendio",
    "events": ["order.created"],
    "description": "Order notifications"
  }'

Response:

{
  "id": "ep_2bNzYPyBRuC1mMYXXAvgSSuz4Fz",
  "url": "https://your-server.com/webhooks/yavendio",
  "events": ["order.created"],
  "is_active": true,
  "description": "Order notifications",
  "created_at": "2026-03-22T10:00:00Z",
  "secret": "whsec_5LTSI03vOvKsLGbAibiB7GGgLDdJMtGk"
}

The secret field is only shown once, when creating the webhook. Store it securely — you'll need it to verify signatures.

2. Verify the signature

Each delivery includes three headers for verification:

Header Description
Svix-Id Unique message ID
Svix-Timestamp UNIX timestamp of the signature
Svix-Signature HMAC-SHA256 signature of the payload

Verification example in Python:

import hmac
import hashlib
import base64

def verify_webhook(payload: bytes, headers: dict, secret: str) -> bool:
    msg_id = headers["Svix-Id"]
    timestamp = headers["Svix-Timestamp"]
    signature = headers["Svix-Signature"]

    # Build the signed message
    to_sign = f"{msg_id}.{timestamp}.{payload.decode()}".encode()

    # Decode the secret (strip "whsec_" prefix and base64 decode)
    secret_bytes = base64.b64decode(secret.replace("whsec_", ""))

    # Calculate the expected signature
    expected = base64.b64encode(
        hmac.new(secret_bytes, to_sign, hashlib.sha256).digest()
    ).decode()

    # Compare with the received signature (format: "v1,<base64>")
    received = signature.split(",")[1] if "," in signature else signature
    return hmac.compare_digest(expected, received)

You can also use the official Svix library:

pip install svix
from svix.webhooks import Webhook

wh = Webhook("whsec_5LTSI03vOvKsLGbAibiB7GGgLDdJMtGk")
payload = wh.verify(request.body, request.headers)

3. Payload format

The order.created payload contains the full order in JSON:

{
  "id": 176,
  "created_at": "2026-03-22T04:39:33.560884Z",
  "merchant_id": 1113,
  "currency": "PEN",
  "total_amount": "205.0",
  "delivery_fee": "10.0",
  "status": "pending",
  "payment_terms": "pending",
  "payment_method": "yape",
  "customer": {
    "name": "Juan Perez",
    "phone_number": "51999000111"
  },
  "variants": [
    {
      "id": 6110,
      "name": "AZUL - S",
      "quantity": 1,
      "base_price": 205.0
    }
  ]
}

The payload uses YaVendio's internal schema. If the structure changes (e.g., a new field is added), it is the receiver's responsibility to adapt.

Manage webhooks

List registered webhooks

curl https://api.ya.onl/v1/webhooks -H "X-API-Key: yv_live_v1_your_api_key"

Disable a webhook

curl -X PATCH https://api.ya.onl/v1/webhooks/{webhook_id} \
  -H "X-API-Key: yv_live_v1_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}'

Delete a webhook

curl -X DELETE https://api.ya.onl/v1/webhooks/{webhook_id} \
  -H "X-API-Key: yv_live_v1_your_api_key"

Check delivery attempts

curl https://api.ya.onl/v1/webhooks/{webhook_id}/deliveries/{message_id} \
  -H "X-API-Key: yv_live_v1_your_api_key"

Retries

If your server does not respond with a 2xx status code, YaVendio will automatically retry delivery with exponential backoff. After multiple consecutive failures, the webhook will be automatically disabled.

Limits

  • Maximum 20 webhooks per merchant
  • Delivery timeout: 30 seconds
  • Events are delivered chronologically, but exactly-once delivery is not guaranteed — design your receiver to be idempotent
Need help?