Skip to main content
Creates a new lottery ticket with one or more jugadas (bets). The ticket is created for a specific sorteo (lottery draw) and includes automatic commission calculation, multiplier resolution, and validation against restriction rules.

Authentication

Requires authentication. Available to roles: VENDEDOR, VENTANA, ADMIN.

Request Body

loteriaId
string
required
UUID of the lottery (Lotería).
sorteoId
string
required
UUID of the draw (Sorteo). Must belong to the specified lottery and not be in CLOSED status.
ventanaId
string
required
UUID of the sales point (Ventana).
vendedorId
string
UUID of the seller (Vendedor). Optional for ADMIN and VENTANA roles (allows impersonation). VENDEDOR users can only specify their own ID or omit this field.
clienteNombre
string
Customer name. Optional. Defaults to “CLIENTE CONTADO” if not provided. Max 100 characters.
jugadas
array
required
Array of bets (jugadas). At least one jugada is required.

Response Fields

id
string
UUID of the created ticket.
ticketNumber
string
Unique ticket number in format TYYMMDD-XXXXXX-CC (e.g., T250126-00000A-42). Generated server-side.
totalAmount
number
Total amount of all jugadas in the ticket.
status
string
Ticket status. Will be ACTIVE for newly created tickets. Possible values:
  • ACTIVE: Ticket is active
  • CANCELLED: Ticket was cancelled
  • EVALUATED: Sorteo has been evaluated, winners determined
  • PAID: Winner ticket has been paid
  • EXCLUDED: Ticket excluded from reports
loteriaId
string
UUID of the lottery.
sorteoId
string
UUID of the sorteo.
ventanaId
string
UUID of the ventana.
vendedorId
string
UUID of the vendedor who created the ticket.
clienteNombre
string
Customer name.
createdAt
string
ISO 8601 timestamp of ticket creation.
businessDate
string
Business date (Costa Rica timezone) when the ticket was created.
totalCommission
number
Total commission amount across all jugadas (sum of commissionAmount from each jugada).
jugadas
array
Array of created jugadas with commission snapshots.
sorteo
object
Sorteo details with formatted name.
vendedor
object
Vendedor information with print configuration.
ventana
object
Ventana information with print configuration (same structure as vendedor).
warnings
array
Optional array of warning messages (e.g., commission calculation warnings).

Validation Rules

Cutoff Validation

Tickets cannot be created within the cutoff window before a sorteo starts. The cutoff time is determined by:
  1. Restriction Rules (highest priority): User-specific, ventana-specific, or banca-specific rules
  2. Banca Settings: salesCutoffMinutes field
  3. Default: 1 minute before sorteo start
A grace period of 1 second is applied to the cutoff time.

Sales Hours Validation

Tickets can only be created within the sales hours defined in the lottery’s rulesJson configuration.

Lottery Rules Validation

The ticket must comply with lottery-specific rules including:
  • Minimum bet amounts
  • Number format requirements (2 or 3 digits)
  • Maximum numbers per ticket
  • REVENTADO bet rules

REVENTADO Validation

For REVENTADO bets:
  • A corresponding NUMERO bet must exist in the same ticket
  • The reventadoNumber must match an existing number with type=NUMERO

Multiplier Validation

  • Multipliers can only be applied to NUMERO bets (not REVENTADO)
  • If multiplierId is provided, it must be a valid active multiplier for the lottery
  • The multiplier value is snapshotted at creation time

Commission Calculation

Commissions are calculated automatically for each jugada using a hierarchical policy system:
  1. User Policy: Vendedor’s commissionPolicyJson
  2. Ventana Policy: Ventana’s commissionPolicyJson
  3. Banca Policy: Banca’s commissionPolicyJson
  4. Listero Policy: Listero user (Role.VENTANA) commissionPolicyJson
The first matching rule in the hierarchy is applied and snapshotted as:
  • commissionPercent: The percentage rate
  • commissionAmount: Calculated amount
  • commissionOrigin: Which policy level was used
  • commissionRuleId: Specific rule ID
  • listeroCommissionAmount: Commission for ventana-level user
These values are immutable snapshots and won’t change even if commission policies are later modified.

RBAC Filtering

VENDEDOR

  • Can only create tickets for themselves
  • Must have an assigned ventanaId
  • vendedorId is automatically set to their user ID

VENTANA

  • Can create tickets for any vendedor in their ventana
  • Must specify vendedorId when creating for a vendedor
  • Can only access vendedores assigned to their ventana

ADMIN

  • Can create tickets for any vendedor in any ventana
  • Must specify both vendedorId and ventanaId
  • Has full access across all bancas

Example Request

curl -X POST https://api.example.com/api/v1/tickets \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "loteriaId": "123e4567-e89b-12d3-a456-426614174000",
    "sorteoId": "223e4567-e89b-12d3-a456-426614174000",
    "ventanaId": "323e4567-e89b-12d3-a456-426614174000",
    "vendedorId": "423e4567-e89b-12d3-a456-426614174000",
    "clienteNombre": "Juan Pérez",
    "jugadas": [
      {
        "number": "05",
        "amount": 1000,
        "type": "NUMERO",
        "multiplierId": "523e4567-e89b-12d3-a456-426614174000"
      },
      {
        "number": "12",
        "amount": 500,
        "type": "NUMERO"
      },
      {
        "amount": 200,
        "type": "REVENTADO",
        "reventadoNumber": "05"
      }
    ]
  }'

Example Response

{
  "success": true,
  "data": {
    "id": "623e4567-e89b-12d3-a456-426614174000",
    "ticketNumber": "T260303-00042A-15",
    "totalAmount": 1700,
    "status": "ACTIVE",
    "loteriaId": "123e4567-e89b-12d3-a456-426614174000",
    "sorteoId": "223e4567-e89b-12d3-a456-426614174000",
    "ventanaId": "323e4567-e89b-12d3-a456-426614174000",
    "vendedorId": "423e4567-e89b-12d3-a456-426614174000",
    "clienteNombre": "Juan Pérez",
    "createdAt": "2026-03-03T14:30:00.000Z",
    "businessDate": "2026-03-03",
    "totalCommission": 93.5,
    "jugadas": [
      {
        "id": "723e4567-e89b-12d3-a456-426614174000",
        "number": "05",
        "amount": 1000,
        "type": "NUMERO",
        "reventadoNumber": null,
        "multiplierId": "523e4567-e89b-12d3-a456-426614174000",
        "finalMultiplierX": 75,
        "commissionPercent": 5.5,
        "commissionAmount": 55,
        "commissionOrigin": "user",
        "commissionRuleId": "823e4567-e89b-12d3-a456-426614174000",
        "listeroCommissionAmount": 10
      },
      {
        "id": "823e4567-e89b-12d3-a456-426614174001",
        "number": "12",
        "amount": 500,
        "type": "NUMERO",
        "reventadoNumber": null,
        "multiplierId": null,
        "finalMultiplierX": 70,
        "commissionPercent": 5.5,
        "commissionAmount": 27.5,
        "commissionOrigin": "user",
        "commissionRuleId": "823e4567-e89b-12d3-a456-426614174000",
        "listeroCommissionAmount": 5
      },
      {
        "id": "823e4567-e89b-12d3-a456-426614174002",
        "number": "05",
        "amount": 200,
        "type": "REVENTADO",
        "reventadoNumber": "05",
        "multiplierId": null,
        "finalMultiplierX": 75,
        "commissionPercent": 5.5,
        "commissionAmount": 11,
        "commissionOrigin": "user",
        "commissionRuleId": "823e4567-e89b-12d3-a456-426614174000",
        "listeroCommissionAmount": 2
      }
    ],
    "sorteo": {
      "id": "223e4567-e89b-12d3-a456-426614174000",
      "name": "TICA 7:00 PM",
      "scheduledAt": "2026-03-03T19:00:00.000Z",
      "status": "SCHEDULED"
    },
    "vendedor": {
      "id": "423e4567-e89b-12d3-a456-426614174000",
      "printName": "Vendedor #1",
      "printPhone": "+506 8888-8888",
      "printWidth": 48,
      "printFooter": "Gracias por su compra",
      "printBarcode": true
    },
    "ventana": {
      "id": "323e4567-e89b-12d3-a456-426614174000",
      "printName": "Ventana Central",
      "printPhone": "+506 2222-2222",
      "printWidth": 48,
      "printFooter": null,
      "printBarcode": true
    }
  }
}

Error Responses

400 Bad Request

{
  "success": false,
  "error": "VALIDATION_ERROR",
  "message": "At least one jugada is required"
}

403 Forbidden

{
  "success": false,
  "error": "FORBIDDEN",
  "message": "No tienes permiso para vender a nombre de otro usuario"
}

404 Not Found

{
  "success": false,
  "error": "NOT_FOUND",
  "message": "Sorteo no encontrado"
}

409 Conflict - Cutoff Exceeded

{
  "success": false,
  "error": "CONFLICT",
  "message": "Venta bloqueada: faltan 0 min para el sorteo (cutoff=1 min, source=DEFAULT)"
}

409 Conflict - Sorteo Closed

{
  "success": false,
  "error": "CONFLICT",
  "message": "No se pueden crear tickets en un sorteo cerrado"
}

Notes

  • All timestamps are in UTC but business date calculations use Costa Rica timezone (America/Costa_Rica)
  • Commission snapshots are immutable and provide historical accuracy
  • Multiplier values are resolved and snapshotted at creation time
  • The ticketNumber is generated server-side using a sequential counter with check digits
  • Activity logs are created automatically for audit trail

Build docs developers (and LLMs) love