Skip to main content
Three functions handle physical access control at event venues. All operate on tickets with status = false (sold) and update both Firestore and PostgreSQL with each scan.

Functions overview

FunctionAction
tickets_access_control_inRecord an attendee entering the venue
tickets_access_control_outRecord an attendee exiting the venue
tickets_access_control_coldBatch sync offline entry/exit events

tickets_access_control_in

Records an attendee’s entry. Handles three scenarios: first-time entry, re-entry after exit, and rejection if the ticket was already used for entry without a corresponding exit.

Endpoint

POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_in

Request body

data.ticket_id
string
required
The ticket ID to scan for entry. Must match a sold ticket (status = false).

Example

curl -X POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_in \
  -H "Content-Type: application/json" \
  -d '{"data": {"ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb"}}'

What it does

The function checks access_status and access_entry to determine the correct action:
access_statusaccess_entryOutcome
falsefalseFirst entry. Sets access_status = true, access_entry = true, appends "accessed" to ledger.
truefalseRe-entry after exit. Sets access_entry = true.
truetrueAlready inside. Rejects the scan.

Response

message
string
Outcome description.
status
number
200 on success, 400 on rejection.
data
object
First entry (200):
{
  "message": "Ticket Ingresando",
  "status": 200,
  "data": { "valido": true, "message": "Ticket Ingresando" }
}
Re-entry after exit (200):
{
  "message": "Ticket ReIngreso",
  "status": 200,
  "data": { "valido": true, "message": "Ticket ReIngreso" }
}
Already inside — rejected (400):
{
  "message": "Ticket ya Utilizado no puede volver Ingresar",
  "status": 400,
  "data": { "valido": false, "message": "Ticket ya Utilizado no puede volver Ingresar" }
}
Ticket not valid (400):
{
  "message": "Ticket no valido",
  "status": 400,
  "data": { "valido": false, "message": "Ticket no valido" }
}
Only tickets with status = false (sold) can be scanned. Unsold tickets (status = true) are rejected as invalid.

tickets_access_control_out

Records an attendee’s exit from the venue. Sets access_entry = false and appends a "came-out" ledger entry.

Endpoint

POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_out

Request body

data.ticket_id
string
required
The ticket ID to scan for exit. Must match a sold ticket (status = false) that has previously entered.

Example

curl -X POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_out \
  -H "Content-Type: application/json" \
  -d '{"data": {"ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb"}}'

What it does

The function checks access_status and access_entry before allowing exit:
access_statusaccess_entryOutcome
truetrueRecords exit. Sets access_entry = false, appends "came-out" to ledger.
falsefalseTicket never entered. Rejects the scan.

Response

Exit recorded (200):
{
  "message": "Ticket Salida",
  "status": 200,
  "data": { "valido": true, "message": "Ticket Salida" }
}
Ticket never entered — rejected (400):
{
  "message": "Ticket no Ingreso no puede salir",
  "status": 400,
  "data": { "valido": false, "message": "Ticket no Ingreso no puede salir" }
}
Ticket not valid (400):
{
  "message": "Ticket no valido",
  "status": 400,
  "data": { "valido": false, "message": "Ticket no valido" }
}

tickets_access_control_cold

Processes a batch of entry and exit events collected while a scanning device was offline. Each event in the batch is applied in order, and the results are written to both Firestore and PostgreSQL in a single batch commit.

Endpoint

POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_cold

Request body

data.tickets_cold
array
required
Array of access events to process. Each item represents a single scan recorded while offline.

Example

curl -X POST https://{region}-{project}.cloudfunctions.net/tickets_access_control_cold \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "tickets_cold": [
        {
          "ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
          "date": "2025-06-01T19:30:00-04:00",
          "tipo": "in"
        },
        {
          "ticket_id": "JAOTIiQrtU1fMWZZY2IZ-LqQTJHAGEkdwzrbcScWe",
          "date": "2025-06-01T19:31:00-04:00",
          "tipo": "in"
        },
        {
          "ticket_id": "JAOTIiQrtU1fMWZZY2IZ-nGxHQ00YzCg9PphEwlYb",
          "date": "2025-06-01T21:00:00-04:00",
          "tipo": "out"
        }
      ]
    }
  }'

What it does

  1. Iterates over each item in tickets_cold.
  2. Fetches the ticket from PostgreSQL. Skips if not found or already processed (deduplication using a procesados set).
  3. Determines the last action per ticket_id based on tipo: "in""accessed", "out""came-out".
  4. Appends the action to the ticket’s ledger.
  5. Commits all Firestore updates in a single batch.
  6. Runs a single bulk UPDATE against PostgreSQL.

Response

Success (200):
{
  "message": "Tickets Frios Sincronizados",
  "status": 200,
  "data": { "valido": true, "message": "Tickets Frios Sincronizados" }
}
If the same ticket_id appears multiple times in the batch, only the last occurrence is applied due to deduplication. Send events in chronological order to ensure the correct final state is persisted.

Build docs developers (and LLMs) love