POST/api/storefront/context/validatescope: none

Validate Credentials

Validates the configured API key and returns the vendor, store, POS and granted scopes. Use as a connectivity check.

Success Response

{
  "success": true,
  "data": {
    "valid":        true,
    "api_key_name": "Sandbox Key",
    "vendor_name":  "Demo Vendor",
    "store_code":   "STORE01",
    "store_name":   "Demo Store",
    "pos_code":     "POS01",
    "pos_name":     "Terminal 1",
    "abilities":    ["products:read", "customers:write", "tickets:hold", "sales:write", "sales:read"]
  }
}
ℹ️ This endpoint validates the server-side API key configured in NUXT_VENDORA_API_KEY. Your browser never sees the key.
GET/api/storefront/productsscope: products:read

List Active Products

Returns all active draw products available for the configured store and POS terminal.

Success Response

{
  "success": true,
  "data": [
    {
      "product_id":         "251",
      "product_name":       "Grand Lucky Draw",
      "product_type":       "Grand Draw",
      "series_no":          "GLD-2025-A",
      "price":              35.00,
      "minimal_quantity":   1,
      "maximal_quantity":   10,
      "available_quantity": 1250,
      "draw_date":          "2025-01-15T20:00:00.000Z",
      "coupon":             { "coupon_id": 1, "name": "Buy 2 Get 1", "buy_x": 2, "get_y": 1 },
      "currency":           "AED"
    }
  ]
}
ℹ️ An empty array is a valid response — it means no draws are currently active, not an error.
POST/api/storefront/customersscope: customers:write

Upsert Customer

Creates or updates a customer in the Vendora system. The returned vendor_customer_id must be used in all subsequent hold and sale requests for this customer.

Request Body

{
  "vendor_customer_id":  "CUST-your-stable-id",  // your stable internal customer ID
  "first_name":          "Ahmed",
  "last_name":           "Al-Rashid",
  "email":               "[email protected]",
  "mobile":              "501234567",
  "mobile_country_id":   217,                    // UAE = 217
  "nationality":         "AE",
  "date_of_birth":       "1990-01-15",
  "document_type":       "PASSPORT",             // "PASSPORT" | "EMIRATES_ID"
  "document_number":     "A12345678",
  "document_expiry_date":"2028-06-30",
  "document_country_id": 217,
  "address_line_1":      "Apt 5, Building 3",
  "country_id":          217
}

Success Response

{
  "success": true,
  "data": {
    "vendor_customer_id": "CUST-your-stable-id",
    "profile_complete":   true,
    "review_required":    false
  }
}
⚠️ KYC document numbers are never stored in the session or logged. They are forwarded directly to Vendora in the request body only.
⚠️ If review_required is true, this customer cannot complete promotional holds. Contact your integration manager.
POST/api/storefront/holdsscope: tickets:hold

Create Hold

Reserves one or more tickets for a limited time. Returns the hold reference, expiry time, ticket details and total payable amount.

Request Body

// Quantity mode:
{
  "product_id": "251",
  "quantity":   2
}

// Ticket-selection mode:
{
  "product_id":  "251",
  "ticket_ids":  ["T-001", "T-002"]
}

// Promotional hold (also requires vendor_customer_id and coupon_id):
{
  "product_id":          "251",
  "quantity":            3,
  "vendor_customer_id":  "CUST-your-stable-id",
  "coupon_id":           1
}

Success Response

{
  "success": true,
  "data": {
    "hold_reference": "HOLD-abc123",
    "product_id":     251,
    "expires_at":     "2025-01-15T14:35:00Z",
    "total_payable":  70.00,
    "coupon_applied": true,
    "tickets": [
      { "ticket_id": "T-001", "ticket_type": "PAID", "amount": 35.00 },
      { "ticket_id": "T-002", "ticket_type": "PAID", "amount": 35.00 },
      { "ticket_id": "T-003", "ticket_type": "FREE", "amount": 0.00  }
    ]
  }
}
⚠️ A 409 TICKET_SELECTION_UNAVAILABLE response means the requested tickets were taken by a concurrent request. Refresh availability and reselect.
ℹ️ Send an Idempotency-Key header to safely retry this request without creating a duplicate hold.
DELETE/api/storefront/holds/:holdReferencescope: tickets:hold

Release Hold

Releases a hold early. Called when the user removes an item from cart. Holds also expire automatically on the Vendora backend.

Success Response

{ "success": true, "data": { "released": true } }
ℹ️ If the hold is already expired or completed, the Vendora backend returns success — this is idempotent.
POST/api/storefront/checkoutscope: sales:write

Create Sale

Finalises the sale. Requires all hold references, full customer KYC and payment details. Atomic locking and duplicate protection are handled by the Vendora backend.

Request Body

{
  "vendor_customer_id": "CUST-your-stable-id",
  "holds": [
    { "hold_reference": "HOLD-abc123" }
  ],
  "customer": { /* same fields as upsert */ },
  "payment": {
    "method":       "CASH",
    "amount":       70.00,
    "currency":     "AED",
    "result":       "PAID",
    "collected_by": "VENDOR"
  },
  "recipient_email": "[email protected]"
}

Success Response

{
  "success": true,
  "data": {
    "order_reference":       "ORD-xyz789",
    "vendor_order_id":       "VORD-001",
    "vendor_order_reference":"VORD-REF-001",
    "payment_status":        "PAID",
    "ticket_status":         "ISSUED",
    "total_amount":          70.00,
    "currency":              "AED",
    "ticket_count":          3,
    "e_ticket_status":       "QUEUED"
  }
}
ℹ️ Send the same Idempotency-Key as the hold to prevent duplicate sale creation on network retry.
⚠️ The payment.amount must match the hold total_payable. A mismatch returns PRICE_VALIDATION_FAILED.
GET/api/vendor-dashboard/transactionsscope: sales:read

List Transactions

Returns the vendor's transaction history. Requires an active portal session (dashboard login).

Query Parameters

ParameterTypeRequiredDescription
statusstringNoFilter by transaction status (PENDING, PAID, CANCELLED)
pageintegerNoPage number (default: 1)
per_pageintegerNoItems per page (default: 20, max: 100)

Success Response

{
  "success": true,
  "data": [
    {
      "order_reference":       "ORD-xyz789",
      "payment_status":        "PAID",
      "ticket_count":          3,
      "total_amount":          70.00,
      "currency":              "AED",
      "customer_email_masked": "a***@example.test",
      "store_code":            "STORE01",
      "created_at":            "2025-01-15T14:35:00Z"
    }
  ]
}
ℹ️ Customer email is masked in all dashboard responses — full PII is never returned to the browser.
GET/api/storefront/orders/:orderReference/e-ticketscope: sales:read

Download E-Ticket PDF

Proxies the binary PDF from Vendora. Returns application/pdf. Available only after e_ticket.status is "SENT".

Success Response

// Binary PDF response
Content-Type: application/pdf
Content-Disposition: attachment; filename="Vendora-e-ticket-{ref}.pdf"
Cache-Control: no-store, private
ℹ️ The PDF is not cached and is streamed directly from Vendora. The API key never appears in the download URL.
⚠️ Returns 502 if the e-ticket is not yet ready (status QUEUED) or 404 if not found.