Skip to content

POS Webhook Integration - Basic Guide

Last Updated: 2025-11-24
Version: 1.0
Audience: POS System Integrators

Overview

This guide provides instructions for integrating your POS system with EmiliaVision via webhooks. Our webhook receiver accepts any valid JSON payload and stores it for processing.

Webhook Endpoint

URL Format: https://api.emiliavision.com/webhooks/v1/pos/{token}?env={environment}

  • Method: POST
  • Content-Type: application/json
  • Authentication: Token in URL path (provided by EmiliaVision)
  • Environment: Optional query parameter to target dev/prod (defaults to prod)

Environment Parameter

Use the optional env query parameter to control which environment receives your data:

  • Production (default): https://api.emiliavision.com/webhooks/v1/pos/{token} or ?env=prod
  • Development/Testing: https://api.emiliavision.com/webhooks/v1/pos/{token}?env=dev

When to use ?env=dev: - Testing integration - Development environments - Sandbox/staging data - Non-production orders

When to use ?env=prod or no parameter: - Live production data - Real customer orders - Production systems

Authentication

Each integration receives a unique webhook token (UUID format). This token: - Must be included in the URL path - Is validated on each request - Can be deactivated remotely if needed - Should be kept secure and not shared

Example: 019ab6ed-150a-7be1-920f-ab82305e5d41

Request Format

Headers

Content-Type: application/json
Content-Length: <payload_size>

Body

Send any valid JSON payload. We store it exactly as received.

Example Payload:

{
  "event": "order_created",
  "timestamp": "2025-11-24T18:30:00-03:00",
  "order_id": "ORD-2025-0124",
  "table": "Mesa 8",
  "items": [
    {
      "id": "ITEM-001",
      "name": "Focaccia",
      "quantity": 1,
      "price": 19.00
    }
  ],
  "total": 41.00
}

Response Codes

Code Meaning Action
200 Success Webhook received and stored
401 Unauthorized Token invalid or inactive - contact EmiliaVision
413 Payload Too Large Reduce payload size (max 10MB)
500 Server Error Retry with exponential backoff
503 Service Unavailable Retry with exponential backoff

Success Response

{
  "status": "success",
  "event_id": "019ab6ed-150a-7be1-920f-ab82305e5d41",
  "message": "Webhook received and stored",
  "received_at": "2025-11-24T18:30:00.123Z"
}

Error Response

{
  "detail": "Invalid or inactive webhook token"
}

Rate Limits

  • Limit: 100 requests per second per token
  • Burst: Up to 200 requests in 10 seconds
  • Over-limit: Returns 429 Too Many Requests

Payload Guidelines

Size Limits

  • Maximum: 10 MB per request
  • Recommended: < 1 MB for optimal performance

Format

  • Required: Valid JSON
  • Flexible: Any structure accepted
  • Encoding: UTF-8

Best Practices

  1. Include timestamps: Use ISO 8601 format with timezone
  2. Include identifiers: Order IDs, table numbers, transaction IDs
  3. Use consistent field names: Helps with future processing
  4. Include event type: Helps with categorization

Testing

Using curl

# Production (default)
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"event": "order_created", "timestamp": "2025-11-24T18:30:00Z", "order_id": "ORD-001"}' \
  https://api.emiliavision.com/webhooks/v1/pos/YOUR_TOKEN_HERE

# Development/Testing environment
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"event": "test", "timestamp": "2025-11-24T18:30:00Z", "test": true}' \
  "https://api.emiliavision.com/webhooks/v1/pos/YOUR_TOKEN_HERE?env=dev"

# With file
curl -X POST \
  -H "Content-Type: application/json" \
  -d @payload.json \
  "https://api.emiliavision.com/webhooks/v1/pos/YOUR_TOKEN_HERE?env=dev"

Using Python

import requests
import json
from datetime import datetime, timezone

# Your webhook token
TOKEN = "019ab6ed-150a-7be1-920f-ab82305e5d41"

# For production
URL_PROD = f"https://api.emiliavision.com/webhooks/v1/pos/{TOKEN}"
# For development/testing
URL_DEV = f"https://api.emiliavision.com/webhooks/v1/pos/{TOKEN}?env=dev"

# Sample payload
payload = {
    "event": "order_created",
    "timestamp": datetime.now(timezone.utc).isoformat(),
    "order_id": "TEST-001",
    "table": "Mesa 8",
    "total": 41.00
}

# Send to development environment for testing
response = requests.post(
    URL_DEV,
    json=payload,
    timeout=10
)

print(f"Status: {response.status_code}")
print(f"Response: {response.json()}")

# Send to production (when ready)
# response = requests.post(URL_PROD, json=payload, timeout=10)

Error Handling

Retry Strategy

Implement exponential backoff for failed requests:

import time
import requests

def send_webhook_with_retry(url, payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, timeout=10)

            if response.status_code == 200:
                return response.json()

            if response.status_code == 401:
                # Don't retry authentication errors
                raise Exception("Invalid token")

            if response.status_code in [500, 503]:
                # Retry server errors
                wait_time = (2 ** attempt)  # 1s, 2s, 4s
                time.sleep(wait_time)
                continue

            # Other errors
            raise Exception(f"HTTP {response.status_code}")

        except requests.exceptions.Timeout:
            wait_time = (2 ** attempt)
            time.sleep(wait_time)

    raise Exception("Max retries exceeded")

Logging

Log webhook attempts for debugging:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def send_webhook(url, payload):
    logger.info(f"Sending webhook to {url}")
    logger.debug(f"Payload: {json.dumps(payload, indent=2)}")

    try:
        response = requests.post(url, json=payload)
        logger.info(f"Response: {response.status_code}")
        return response
    except Exception as e:
        logger.error(f"Webhook error: {e}")
        raise

Security

Token Protection

  • Store tokens in environment variables or secure vaults
  • Never commit tokens to version control
  • Rotate tokens periodically (contact EmiliaVision)

HTTPS

All webhook endpoints use HTTPS with TLS 1.2+. HTTP is not supported.

IP Whitelisting

Contact EmiliaVision if you need IP whitelisting for additional security.

Support

Getting Help

  • Email: team@emiliavision.com
  • Documentation: https://docs.emiliavision.com
  • Status Page: https://status.emiliavision.com

Token Management

To request a new token or manage existing tokens: 1. Contact your EmiliaVision account manager 2. Provide: Restaurant name, location, and use case 3. Receive: Token and configuration details

Troubleshooting

Issue Solution
401 Unauthorized Verify token is correct and active
413 Payload Too Large Reduce payload size or split into multiple requests
Timeout Check network connectivity and retry
500/503 Errors Wait and retry with exponential backoff

Appendix: Example Payloads

Order Created

{
  "event": "order_created",
  "timestamp": "2025-11-24T18:30:00-03:00",
  "order_id": "ORD-2025-0124",
  "table": "Mesa 8",
  "server": "João Silva",
  "items": [
    {
      "id": "ITEM-001",
      "name": "Focaccia",
      "quantity": 1,
      "price": 19.00
    },
    {
      "id": "ITEM-002",
      "name": "Agua com Gas",
      "quantity": 2,
      "price": 11.00
    }
  ],
  "subtotal": 41.00,
  "tax": 4.10,
  "total": 45.10
}

Payment Completed

{
  "event": "payment_completed",
  "timestamp": "2025-11-24T20:15:00-03:00",
  "order_id": "ORD-2025-0124",
  "payment_method": "VISA_CREDIT",
  "amount": 41.00,
  "tip": 4.10,
  "total_paid": 45.10,
  "transaction_id": "TXN-2025-5678",
  "nfe": "35250933111140001168650020000692041393134125"
}

Table Status Change

{
  "event": "table_status_change",
  "timestamp": "2025-11-24T17:00:00-03:00",
  "table": "Mesa 8",
  "old_status": "available",
  "new_status": "occupied",
  "party_size": 4
}

Note: This is a generic webhook guide. Specific data format requirements and processing logic are handled separately by EmiliaVision. You can send any valid JSON structure.