Quick Start
Follow these steps to complete a full end-to-end integration with the Vendora POS API.
Obtain your sandbox credentials
Contact your Vendora integration manager to receive your sandbox API key, Store Code and POS Code. These are pre-configured in this portal.
Validate your credentials
Call the auth/validate endpoint to confirm your key is active and inspect the assigned vendor, store, POS and scopes.
POST /api/v1/pos/auth/validate
Headers:
X-Vendora-Api-Key: <your key>
X-Vendora-Store-Code: <your store code>
X-Vendora-POS-Code: <your POS code>
X-Request-ID: <uuid per request>
# Response envelope:
{
"status": 200,
"code": "SUCCESS",
"response": {
"api_key": { "name": "...", "abilities": [...] },
"vendor": { "name": "..." },
"store": { "code": "...", "name": "..." },
"pos": { "code": "...", "name": "..." }
}
}Retrieve available products
Fetch the list of active draw products. Each product includes price, quantity, draw date and optional promotion (coupon) details.
GET /api/v1/pos/products
Headers: (same as above)
# Key response fields (in envelope.response.products[]):
{
"product_id": 251,
"product_name": "Lulu Grand Draw",
"price": 35.0,
"minimal_quantity": 1,
"maximal_quantity": 10,
"available_quantity": 1250,
"draw_date": "2025-01-15T20:00:00Z",
"coupon": { "id": 1, "buy_x": 2, "get_y": 1 } // nullable
}Check available tickets (optional)
For ticket-selection mode, fetch available ticket IDs for a specific product. For quantity mode, skip this step.
GET /api/v1/pos/products/{product_id}/available-tickets
# Returns: envelope.response.available_ticket_ids (array of ticket ID strings)Create a ticket hold
Reserve tickets before completing the sale. The hold locks tickets for a limited time window. Use the Idempotency-Key header to safely retry failed requests.
POST /api/v1/pos/ticket-holds
Headers:
Idempotency-Key: <stable-uuid-per-cart-item>
Body (quantity mode):
{
"product_id": 251,
"quantity": 2
}
Body (ticket-selection mode):
{
"product_id": 251,
"ticket_ids": ["T-001", "T-002"]
}
# Promotional hold also requires:
{
"vendor_customer_id": "CUST-abc123",
"coupon_id": 1
}
# Key response fields:
{
"hold_reference": "HOLD-abc",
"expires_at": "2025-01-15T14:35:00Z",
"total_payable": 70.00,
"tickets": [
{ "ticket_id": "T-001", "ticket_type": "PAID", "amount": 35.00 },
{ "ticket_id": "T-002", "ticket_type": "FREE", "amount": 0.00 }
]
}Upsert the customer
Create or update the customer record in Vendora. The vendor_customer_id returned must be included in the sale request.
POST /api/v1/pos/customers/upsert
Body:
{
"vendor_customer_id": "CUST-<your-stable-id>",
"first_name": "Ahmed",
"last_name": "Al-Rashid",
"email": "...",
"mobile": "501234567",
"mobile_country_id": 217,
"nationality": "AE",
"date_of_birth": "1990-01-15",
"document_type": "PASSPORT",
"document_number": "A12345678",
"document_expiry_date": "2028-06-30",
"document_country_id": 217,
"address_line_1": "...",
"country_id": 217
}Submit the sale
Submit the completed sale with all hold references, KYC data and payment details. Use the same Idempotency-Key as the hold to safely retry.
POST /api/v1/pos/sales
Headers:
Idempotency-Key: <same key as hold>
Body:
{
"vendor_customer_id": "CUST-abc123",
"holds": [{ "hold_reference": "HOLD-abc" }],
"customer": { /* same as upsert body */ },
"payment": {
"method": "CASH",
"amount": 70.00,
"currency": "AED",
"result": "PAID",
"collected_by": "VENDOR"
},
"recipient_email": "..."
}Retrieve the issued order
After a successful sale, retrieve the transaction to confirm ticket issuance and e-ticket delivery status.
GET /api/v1/pos/transactions/{order_reference}
# Key response fields:
{
"order_reference": "ORD-abc",
"payment_status": "PAID",
"ticket_status": "ISSUED",
"e_ticket": { "status": "QUEUED" | "SENT" | "FAILED" }
}Download the e-ticket PDF (when available)
The e-ticket PDF is proxied through the Nitro server. It returns application/pdf binary data directly.
GET /api/storefront/orders/{order_reference}/e-ticket
# Returns: application/pdf binary
# Headers: Content-Disposition: attachment; filename="Vendora-e-ticket-{ref}.pdf"
# Cache-Control: no-storeVendora Response Envelope
Every Vendora API response wraps business data in a consistent envelope. Business data is always in response, never in data.
{
"status": 200,
"code": "SUCCESS", // endpoint-specific, may differ per operation
"message": "...",
"tracing_id": "trace-abc123", // preserve for support requests
"version": "1.0",
"errors": null, // array of error objects when status != 2xx
"response": { ... }, // ← business data is always here, not "data"
"encrypted_data": null
}Required Headers
| Header | Source | Required |
|---|---|---|
X-Vendora-Api-Key | Private runtime config (NUXT_VENDORA_API_KEY) | Required |
X-Vendora-Store-Code | Private runtime config (NUXT_VENDORA_STORE_CODE) | Required |
X-Vendora-POS-Code | Private runtime config (NUXT_VENDORA_POS_CODE) | Required |
X-Request-ID | Generated per request (UUID v4) | Required |
Idempotency-Key | Generated per logical action, stored in session | Optional |
Content-Type | application/json for POST bodies | Optional |