Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /api/purchase_orders/anonymous/ | Public | Create an anonymous purchase |
GET | /api/purchase_orders/validate_qr/ | Public | Validate a single QR code |
POST | /api/purchase_orders/validate-bulk-qr/ | Public | Validate multiple QR codes |
GET | /api/purchase_orders/ | Auth | List orders (admin: all; user: own) |
GET | /api/purchase_orders/{id}/ | Auth | Retrieve a single order |
POST | /api/purchase_orders/create/ | Auth | Create an authenticated order |
PUT | /api/purchase_orders/{id}/update/ | Auth | Update an order |
DELETE | /api/purchase_orders/{id}/delete/ | Auth | Delete an order |
GET | /api/tickets_purchase_orders/ | Admin | List ticket line items |
POST /api/purchase_orders/anonymous/
The primary public endpoint for ticket purchases. No authentication or account is needed — only an email address. The service layer validates stock and visit capacity, creates the order atomically, decrementsoccupied_slots on each ticket, and increments occupied_slots on the selected visit.
A QR image is generated automatically after the order is saved (via
post_save signal). The qr_image URL will be available when you retrieve the order by ID.Request body
Buyer’s email address. Used as the sole identifier for anonymous orders. Must contain
@.One or more ticket line items to purchase.
ID of the
Visits record for the selected date. Create or look up a visit first using POST /api/visits/create/.Numeric ID of the payment method:
1— Card2— PayPal3— Cash
curl example
JavaScript example
Response — 201 Created
true on successful order creation.Human-readable confirmation message.
The newly created
PurchaseOrders primary key.Unique code for this order, formatted as
ANON-{order_id}. Use this to track or reference the purchase.Combined total price across all currencies (simplified sum). For per-currency breakdowns, retrieve the order by ID.
The email address confirmed for this order.
Error responses
| Scenario | Status | Response |
|---|---|---|
Missing email | 400 | {"error": "Email es requerido para compras anónimas"} |
| No tickets selected | 400 | {"error": "Debe seleccionar al menos un ticket"} |
| Invalid ticket ID | 400 | {"error": "Ticket con ID X no existe"} |
Quantity <= 0 | 400 | {"error": "Cantidad debe ser mayor a 0 para el ticket ..."} |
| Ticket out of stock | 400 | {"error": "Stock insuficiente para ... Disponible: N, Solicitado: M"} |
| Visit not found | 400 | {"error": "La visita con ID X no existe"} |
| Visit capacity exceeded | 400 | {"error": "No hay cupos suficientes en la visita. Disponibles: N, Solicitados: M"} |
| Invalid payment method | 400 | {"error": "Método de pago con ID X no existe"} |
GET /api/purchase_orders/validate_qr/
Validates a scanned QR code and returns the order status and access decision. No authentication required — intended for use at the park entrance. Supports three QR formats:- JSON (primary):
{"order_id": 42, "email": "...", "verification": "abc123..."}— includes SHA-256 integrity check - Legacy full:
Order ID: 42 | Email: [email protected] - Simple:
42(order ID only)
Query parameters
The raw string content from the scanned QR code. For JSON format, pass the JSON string directly.
curl example
Response
Whether the QR data is structurally valid and the order exists.
true only when status == "PAID". Use this field to make the gate decision.Current order status:
PAID, PENDING, CANCELLED, or FAILED.Human-readable message describing the access decision.
The matched order ID.
Email address on the order.
ISO date of the visit (
YYYY-MM-DD).Total number of tickets across all line items.
Total amount in Costa Rican colones.
Total amount in US dollars.
Per-ticket breakdown.
true if the QR was in JSON format and the SHA-256 hash matched. Always false for legacy formats.POST /api/purchase_orders/validate-bulk-qr/
Validates up to 100 QR codes in a single request. Useful for pre-checking a group booking or auditing a batch of tickets at the entrance.Request body
List of raw QR strings to validate. Maximum 100 items per request. Supports all three QR formats (JSON, legacy full, simple).
Response
Number of QR codes submitted.
Number of QR codes that resolved to a
PAID order.Number of QR codes that failed validation.
Percentage of valid QRs, rounded to 2 decimal places.
Per-QR result objects.
GET /api/tickets_purchase_orders/
Lists allTicketsPurchaseOrder line items (the join table between an order and a ticket type). Primarily used by admins to audit what was purchased in each order.
This endpoint is at the URL prefix
/api/tickets_purchase_orders/, separate from /api/purchase_orders/.Response fields
Line item primary key.
Foreign key to the parent
PurchaseOrders record.Foreign key to the
Tickets record.Quantity purchased for this ticket type in this order.
Computed read-only property:
amount × ticket.price.Model reference
PurchaseOrders
| Field | Type | Description |
|---|---|---|
id | integer | Auto-generated primary key |
order_date | date | Set automatically on creation |
purchase_date | date | Set automatically on creation |
email | string | Buyer’s email (max 50 chars) |
status | string | PENDING | PAID | CANCELLED | FAILED |
total_price | decimal(12,2) | Combined total across all currencies |
total_crc | decimal(12,2) | Subtotal for CRC-denominated tickets |
total_usd | decimal(12,2) | Subtotal for USD-denominated tickets |
qr_image | image | Auto-generated QR image path (under qr_codes/) |
visit | FK → Visits | The selected visit date |
user | FK → User | null | null for anonymous orders |
TicketsPurchaseOrder (line items)
| Field | Type | Description |
|---|---|---|
id | integer | Auto-generated primary key |
purchase_order | FK → PurchaseOrders | Parent order |
ticket | FK → Tickets | Ticket type |
amount | integer | Quantity purchased |
subtotal | decimal | Computed: amount × ticket.price (read-only property) |
QR code format
Each order generates a QR image automatically via apost_save Django signal. The QR encodes a JSON payload:
verification_hash is a 16-character prefix of the SHA-256 digest computed from {order_id}-{email}-{purchase_date}-{total_price_crc}. The validate_qr endpoint re-computes this hash on every request to detect altered QR data.
Anonymous purchase flow
The complete end-to-end flow for a guest buyer:- Get available tickets —
GET /api/tickets/available/ - Create or retrieve a visit for the desired date —
POST /api/visits/create/ - Submit the purchase —
POST /api/purchase_orders/anonymous/ - Receive confirmation — the response includes
confirmation_codeandorder_id - QR generated automatically — available on the order record as
qr_image - Email invoice sent — the frontend triggers EmailJS after a successful response
- Entry validation — staff scan the QR at the gate using
GET /api/purchase_orders/validate_qr/
