Skip to main content
A virtual office is the online equivalent of a physical box office. It does not require a collaborator to be physically present — sales flow through a web or mobile client that calls these endpoints directly. All state is managed in PostgreSQL, specifically the tickets and tickets_blocked tables.
Virtual office functions mirror the core ticket operations (tickets_lock, tickets_list_event_sales, tickets_unlock_param) but are namespaced with _virtual to allow separate permission scoping and auditing for online sales channels.

List All Event Tickets

tickets_list_event_virtual returns every ticket for an event. This is typically used to render a seat map before a customer selects seats.
POST /tickets_list_event_virtual
Content-Type: application/json
{
  "data": {
    "event_id": "JAOTIiQrtU1fMWZZY2IZ"
  }
}
data.event_id
string
required
The event ID to list tickets for.

Response Fields

data.valido
boolean
true when tickets were found.
data.response
array
Full ticket rows from the tickets table. Includes all columns: ticket_id, seat_id, zone, color, status, access_status, access_entry, event_id, event_name, seat_row, ledger, date_start, date_end, date_created, date_updated.
Success (200)
{
  "message": "Evento Encontrado",
  "status": 200,
  "data": {
    "valido": true,
    "response": [
      {
        "ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
        "seat_id": "VIP1",
        "zone": "VIP",
        "color": "#FFD700",
        "status": true,
        "event_id": "JAOTIiQrtU1fMWZZY2IZ",
        "event_name": "Festival de Verano 2024"
      }
    ]
  }
}

List Tickets with Sales Status

tickets_list_event_sales_virtual returns tickets with a computed status that reflects both sold state and active holds. Use this endpoint to show a customer-facing seat map where temporarily reserved seats appear as unavailable.
POST /tickets_list_event_sales_virtual
Content-Type: application/json
{
  "data": {
    "event_id": "JAOTIiQrtU1fMWZZY2IZ"
  }
}
data.event_id
string
required
The event ID to fetch the sales view for.

Response Fields

data.response[].status
boolean
Computed field. false if the ticket is either blocked in tickets_blocked (status_d is set by the LEFT JOIN) or already sold (status = false in tickets). true only when the seat is both unblocked and unsold.
data.response[].status_real
boolean
The raw status column value from tickets before block evaluation.
data.response[].status_offline
boolean
true when the ticket has been assigned to an offline office and is not available for online purchase.
Success (200)
{
  "message": "Evento Encontrado",
  "status": 200,
  "data": {
    "valido": true,
    "response": [
      {
        "ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
        "seat_id": "VIP1",
        "zone": "VIP",
        "color": "#FFD700",
        "status": false,
        "status_real": true,
        "status_offline": false,
        "event_id": "JAOTIiQrtU1fMWZZY2IZ"
      }
    ]
  }
}

Lock Tickets (Reserve for Checkout)

tickets_lock_virtual places a time-limited hold on one or more tickets, preventing them from being sold to another customer while the first customer is in the checkout flow.
POST /tickets_lock_virtual
Content-Type: application/json
{
  "data": {
    "ticketd_reserved": [
      "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
      "JAOTIiQrtU1fMWZZY2IZ-LqQTJHAGEkdwzrbcScWe"
    ],
    "reserved_time": 600
  }
}
data.ticketd_reserved
array
required
Array of composite ticket IDs to lock. All tickets must be available (unsold and not already blocked) or the entire request is rejected.
data.reserved_time
number
required
Hold duration in seconds. The locked_up timestamp is computed as now() + reserved_time. After this time the hold expires and the ticket becomes available again.

Validation Logic

The function performs two checks before inserting into tickets_blocked:
  1. Sold check — Queries tickets for the requested IDs. Any ticket where status = false (already sold) is added to nodisponible and the request fails.
  2. Block check — Queries tickets_blocked for the same IDs. Any already-blocked ticket is added to nodisponible and the request fails.
Both checks must pass for all tickets before any hold is written. Success (200)
{
  "message": "Tickets blocked",
  "status": 200,
  "data": {
    "valido": true,
    "tickets": [
      "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
      "JAOTIiQrtU1fMWZZY2IZ-LqQTJHAGEkdwzrbcScWe"
    ]
  }
}
Tickets unavailable (400)
{
  "message": "Tickets no disponibles",
  "status": 400,
  "data": {
    "valido": false,
    "nodisponible": [
      "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb"
    ]
  }
}

Unlock Tickets by ID

tickets_unlock_param_virtual explicitly releases holds for specific tickets, typically called when a customer abandons the checkout or after a successful order is created.
POST /tickets_unlock_param_virtual
Content-Type: application/json
{
  "data": {
    "ticketd_reserved": [
      "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb"
    ]
  }
}
data.ticketd_reserved
array
required
Array of composite ticket IDs to release from tickets_blocked. Deletes matching rows regardless of whether locked_up has expired.
Success (200)
{
  "message": "Actualizado",
  "status": 200,
  "data": { "valido": true }
}
Always call tickets_unlock_param_virtual after a successful order creation, even though tickets_lock_virtual sets an expiry. Explicit release ensures the seat map updates immediately without waiting for the locked_up window to close.

Build docs developers (and LLMs) love