EmiliaVision Webhook API Reference¶
Version: 2.0
Base URL: https://api.emiliavision.com/webhooks/v1/pos
Protocol: HTTPS only
Format: JSON
๐ Authentication¶
Webhook Token¶
Each integration receives a unique UUID token that must be included in the URL path.
Format: {base_url}/{token}
Example:
Token Security¶
- Tokens are validated on each request
- Invalid tokens return
401 Unauthorized - Tokens can be deactivated remotely if compromised
- Request new tokens via team@emiliavision.com
๐ Environments¶
Production (Default)¶
Development/Testing¶
Query Parameters: | Parameter | Values | Default | Description | |-----------|---------|---------|-------------| | env | dev, prod | prod | Target environment for data storage |
๐จ Request Specification¶
HTTP Method¶
POST
Headers¶
| Header | Required | Value | Description |
|---|---|---|---|
Content-Type | Yes | application/json | Request body format |
Content-Length | Yes | <size> | Payload size in bytes |
X-Request-ID | No | <uuid> | Your tracking ID for debugging |
Request Limits¶
| Limit | Value | Description |
|---|---|---|
| Max Payload Size | 10 MB | Returns 413 Payload Too Large if exceeded |
| Request Timeout | 30 seconds | Connection timeout |
| Rate Limit | 100 req/sec | Per token rate limiting |
| Burst Limit | 200 req/10sec | Short burst allowance |
๐ Event Types¶
1. session_opened¶
Sent when a new table/check is opened.
Required Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | event | string | Event type identifier | "session_opened" | | timestamp | ISO 8601 | When the session started | "2025-11-24T18:30:00-03:00" | | order_id | string | Your unique order identifier | "ORD-2025-0124" | | table_number | string | Table identifier | "Mesa 8" |
Optional Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | server.id | integer | Employee ID who opened | 72 | | server.name | string | Employee name | "Joรฃo Silva" | | party_size | integer | Number of guests | 4 |
Example Payload:
{
"event": "session_opened",
"timestamp": "2025-11-24T18:30:00-03:00",
"order_id": "ORD-2025-0124",
"table_number": "Mesa 8",
"server": {
"id": 72,
"name": "Joรฃo Silva"
},
"party_size": 4
}
2. items_added¶
Sent when items are added to an order.
Required Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | event | string | Event type identifier | "items_added" | | timestamp | ISO 8601 | When items were added | "2025-11-24T18:35:00-03:00" | | order_id | string | Order identifier | "ORD-2025-0124" | | table_number | string | Table identifier | "Mesa 8" | | items | array | List of items added | See items structure |
Items Array Structure: | Field | Type | Required | Description | Example | |-------|------|----------|-------------|---------| | timestamp | ISO 8601 | Yes | When this specific item was ordered | "2025-11-24T18:35:00-03:00" | | employee_id | integer | Yes | Who took the order | 72 | | name | string | Yes | Item name | "Focaccia" | | quantity | integer | Yes | Number ordered | 1 | | price | decimal | Yes | Unit price | 19.00 | | employee_name | string | No | Employee name | "Joรฃo Silva" | | item_id | string | No | Your item SKU | "ITEM-001" | | category | string | No | Item category | "Appetizers" | | modifiers | array | No | Customizations | ["Extra cheese"] |
Example Payload:
{
"event": "items_added",
"timestamp": "2025-11-24T18:35:00-03:00",
"order_id": "ORD-2025-0124",
"table_number": "Mesa 8",
"items": [
{
"timestamp": "2025-11-24T18:35:00-03:00",
"employee_id": 72,
"employee_name": "Joรฃo Silva",
"item_id": "ITEM-001",
"name": "Focaccia",
"category": "Appetizers",
"quantity": 1,
"price": 19.00,
"modifiers": []
},
{
"timestamp": "2025-11-24T18:35:00-03:00",
"employee_id": 72,
"employee_name": "Joรฃo Silva",
"item_id": "ITEM-002",
"name": "Agua com Gas",
"category": "Beverages",
"quantity": 2,
"price": 11.00,
"modifiers": ["Lemon"]
}
]
}
3. items_removed¶
Sent when items are cancelled or removed.
Required Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | event | string | Event type identifier | "items_removed" | | timestamp | ISO 8601 | When items were removed | "2025-11-24T18:40:00-03:00" | | order_id | string | Order identifier | "ORD-2025-0124" | | table_number | string | Table identifier | "Mesa 8" | | items | array | List of items removed | See structure above |
Optional Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | reason | string | Cancellation reason | "Customer changed mind" | | cancelled_by | object | Employee who cancelled | {"id": 72, "name": "Joรฃo Silva"} |
4. session_closed¶
Sent when check is closed/paid.
Required Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | event | string | Event type identifier | "session_closed" | | timestamp | ISO 8601 | When session ended | "2025-11-24T20:15:00-03:00" | | order_id | string | Order identifier | "ORD-2025-0124" | | table_number | string | Table identifier | "Mesa 8" |
Recommended Fields: | Field | Type | Description | Example | |-------|------|-------------|---------| | session_start | ISO 8601 | Original open time | "2025-11-24T18:30:00-03:00" | | session_end | ISO 8601 | Close time | "2025-11-24T20:15:00-03:00" | | duration_minutes | integer | Total duration | 105 | | totals.subtotal | decimal | Pre-tax/tip amount | 194.00 | | totals.tip | decimal | Tip amount | 25.22 | | totals.tax | decimal | Tax amount | 19.40 | | totals.total | decimal | Final amount | 238.62 | | payment.method | string | Payment type | "VISA_CREDIT" | | closed_by | object | Employee who closed | {"id": 96, "name": "Maria Santos"} |
Full Example:
{
"event": "session_closed",
"timestamp": "2025-11-24T20:15:00-03:00",
"order_id": "ORD-2025-0124",
"table_number": "Mesa 8",
"session_start": "2025-11-24T18:30:00-03:00",
"session_end": "2025-11-24T20:15:00-03:00",
"duration_minutes": 105,
"totals": {
"subtotal": 194.00,
"tip": 25.22,
"tax": 19.40,
"total": 238.62
},
"payment": {
"method": "VISA_CREDIT",
"fiscal_receipt": "NFe35251133111140001168650020000762241540579084"
},
"closed_by": {
"id": 96,
"name": "Maria Santos"
}
}
5. session_complete¶
Complete session data in a single webhook (alternative to multiple events).
This is ideal when you want to send everything at once after payment.
Example Payload:
{
"event": "session_complete",
"timestamp": "2025-11-24T20:15:00-03:00",
"order_id": "ORD-2025-0124",
"table_number": "Mesa 8",
"session_start": "2025-11-24T18:30:00-03:00",
"session_end": "2025-11-24T20:15:00-03:00",
"duration_minutes": 105,
"opened_by": {
"id": 72,
"name": "Joรฃo Silva"
},
"closed_by": {
"id": 96,
"name": "Maria Santos"
},
"items": [
{
"timestamp": "2025-11-24T18:35:00-03:00",
"employee_id": 72,
"name": "Focaccia",
"quantity": 1,
"price": 19.00
},
{
"timestamp": "2025-11-24T18:35:00-03:00",
"employee_id": 72,
"name": "Agua com Gas",
"quantity": 2,
"price": 11.00
},
{
"timestamp": "2025-11-24T18:45:00-03:00",
"employee_id": 72,
"name": "Carbonara Classica",
"quantity": 1,
"price": 85.00
},
{
"timestamp": "2025-11-24T19:50:00-03:00",
"employee_id": 96,
"name": "Tiramisu",
"quantity": 2,
"price": 36.00
}
],
"totals": {
"subtotal": 187.00,
"tip": 24.31,
"tax": 18.70,
"total": 230.01
},
"payment": {
"method": "VISA_CREDIT",
"transaction_id": "TXN-2025-5678",
"fiscal_receipt": "NFe35251133111140001168650020000762241540579084"
}
}
โ Response Codes¶
Success Responses¶
200 OK¶
Webhook successfully received and stored.
Response Body:
{
"status": "success",
"event_id": "019ab6ed-150a-7be1-920f-ab82305e5d41",
"message": "Webhook received and stored",
"received_at": "2025-11-24T18:30:00.123Z"
}
Response Fields: | Field | Type | Description | |-------|------|-------------| | status | string | Always "success" | | event_id | UUID | Unique identifier for this webhook event | | message | string | Confirmation message | | received_at | ISO 8601 | Server timestamp (UTC) |
Error Responses¶
401 Unauthorized¶
Invalid or inactive webhook token.
Response Body:
413 Payload Too Large¶
Request body exceeds 10MB limit.
Response Body:
429 Too Many Requests¶
Rate limit exceeded.
Response Body:
500 Internal Server Error¶
Server-side processing error.
Response Body:
503 Service Unavailable¶
Service temporarily unavailable.
Response Body:
๐ Retry Strategy¶
Recommended Retry Logic¶
import time
import requests
def send_webhook_with_retry(url, payload, max_retries=3):
"""
Send webhook with exponential backoff retry
"""
for attempt in range(max_retries):
try:
response = requests.post(
url,
json=payload,
timeout=10
)
if response.status_code == 200:
return response.json()
# Don't retry client errors
if 400 <= response.status_code < 500:
if response.status_code != 429: # Except rate limit
raise Exception(f"Client error: {response.status_code}")
# Retry server errors and rate limits
if response.status_code in [429, 500, 502, 503, 504]:
if attempt < max_retries - 1:
# Exponential backoff: 1s, 2s, 4s
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
raise Exception(f"HTTP {response.status_code}: {response.text}")
except requests.exceptions.Timeout:
if attempt < max_retries - 1:
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
raise
except requests.exceptions.ConnectionError:
if attempt < max_retries - 1:
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
raise
raise Exception(f"Max retries ({max_retries}) exceeded")
Retry Guidelines¶
| Error Type | Retry? | Strategy |
|---|---|---|
401 Unauthorized | No | Check token validity |
413 Payload Too Large | No | Reduce payload size |
429 Rate Limited | Yes | Wait 1 second minimum |
500 Server Error | Yes | Exponential backoff |
503 Unavailable | Yes | Exponential backoff |
| Network timeout | Yes | Exponential backoff |
| Connection error | Yes | Exponential backoff |
๐ Field Data Types¶
String Fields¶
- UTF-8 encoded
- Maximum 65,535 characters
- Examples:
table_number,order_id,name
Numeric Fields¶
- Decimals: Up to 2 decimal places for currency
- Integers: 32-bit signed integers
- Examples:
price(19.00),employee_id(72)
Timestamp Fields¶
- ISO 8601 format with timezone
- Format:
YYYY-MM-DDTHH:MM:SSยฑHH:MM - Example:
2025-11-24T18:30:00-03:00
Array Fields¶
- JSON arrays
- Can be empty
[] - Maximum 1000 items per array
Object Fields¶
- JSON objects
- Can be null or empty
{} - Nested up to 5 levels deep
๐ Supported Timezones¶
Include timezone information in all timestamps. Supported formats:
- Offset format:
2025-11-24T18:30:00-03:00(recommended) - UTC format:
2025-11-24T21:30:00Z - Named timezone: Not recommended, use offset instead
Common timezone offsets: - Sรฃo Paulo: -03:00 - New York: -05:00 (EST) / -04:00 (EDT) - London: +00:00 (GMT) / +01:00 (BST) - Tokyo: +09:00
๐งช Testing¶
Test Endpoint¶
Add ?env=dev to test without affecting production data:
Test with cURL¶
# Minimal test
curl -X POST \
"https://api.emiliavision.com/webhooks/v1/pos/YOUR_TOKEN?env=dev" \
-H "Content-Type: application/json" \
-d '{
"event": "test",
"table_number": "Test Table",
"timestamp": "2025-11-24T12:00:00-03:00"
}'
# Complete session test
curl -X POST \
"https://api.emiliavision.com/webhooks/v1/pos/YOUR_TOKEN?env=dev" \
-H "Content-Type: application/json" \
-d '{
"event": "session_complete",
"order_id": "TEST-001",
"table_number": "Mesa Test",
"session_start": "2025-11-24T12:00:00-03:00",
"session_end": "2025-11-24T13:00:00-03:00",
"items": [
{
"timestamp": "2025-11-24T12:10:00-03:00",
"employee_id": 1,
"name": "Test Item",
"quantity": 1,
"price": 10.00
}
],
"totals": {
"subtotal": 10.00,
"tip": 1.30,
"tax": 1.00,
"total": 12.30
}
}'
Validation Tool¶
Coming soon: Online webhook tester at https://test.emiliavision.com/webhook
๐ Integration Checklist¶
Minimum Required Fields¶
-
event- Event type -
table_number- Table identifier (CRITICAL!) -
timestamp- When event occurred -
order_id- Your unique identifier
Highly Recommended Fields¶
-
session_start- When table opened -
session_end- When check closed -
employee_id- Who performed actions -
items[].timestamp- When each item ordered -
totals- Financial summary
Nice to Have¶
-
employee_name- Human-readable names -
item_category- Menu categorization -
fiscal_receipt- Tax document number -
payment.method- How customer paid
๐ Support¶
Getting Help¶
- Technical Issues: team@emiliavision.com
- Integration Questions: team@emiliavision.com
- Token Requests: team@emiliavision.com
Response Times¶
- Critical issues: < 2 hours
- Integration support: < 4 hours
- Token generation: < 24 hours
Common Issues¶
| Issue | Solution |
|---|---|
| 401 errors | Verify token is correct and active |
| Timezone confusion | Always include timezone offset in timestamps |
| Missing table numbers | This is critical - ensure every payload has it |
| No employee IDs | Check if your POS tracks who takes orders |
Version History - v2.0 (2025-11) - Added environment parameter, enhanced examples - v1.0 (2025-10) - Initial release