Tickets

A ticket (a sales receipt your customer can later turn into a CFDI) is a paid sale that your point of sale records in Fiscalapi for Auto CFDI invoicing (CFDI: Mexico's electronic invoice). When you record it, you receive a code and its QR code URL, which you print on the sales receipt: your customer uses them to generate their invoice in the auto-invoice portal (auto-invoice: a CFDI your customer requests from a ticket; you remain the issuer). You include any sale your customers don't invoice in the global invoice for tickets (global invoice: factura global, one CFDI that groups a period's sales to the general public).

Each ticket belongs to an issuing person in your tenant (the space in Fiscalapi that holds your issuers, recipients, credits, and data) and stores the sale's line items and taxes with the same names as Create an invoice. Fiscalapi validates its structure, the SAT catalogs (SAT: Mexico's tax authority, Servicio de Administración Tributaria), and that the total matches to the cent. The taxes you declare are your responsibility.

Ticket statuses

A ticket's status comes as camelCase text in the status field. Only a ticket in pending status can be auto-invoiced, included in a global invoice, or canceled.

StatusWhat it means
pendingNot invoiced: your customer can auto-invoice it, or you can include it in a global invoice.
invoicingYour customer is stamping it (stamping: the certification by a SAT-authorized provider that makes a CFDI valid) in the portal.
invoicedIt has its own individual invoice, whose ID is in invoiceId.
globalizingA global invoice that includes it is being stamped.
globalizedIt's included in a global invoice, whose ID is in globalInvoiceId.
cancelledYou canceled it before it was invoiced. This status is final and releases its series and folio number (the issuer's own sequential number for the ticket).

New statuses may appear: treat an unknown value as a ticket you can't invoice yet.

Ticket model

The ticket model (Ticket) is the one that List tickets and Get a ticket by ID return. The line items come only with details=true, and the history only when you get a single ticket.

Properties

  • Name
    id
    Type
    string?
    Description

    The ticket ID, assigned by Fiscalapi.

  • Name
    personId
    Type
    string?
    Description

    The ID of the ticket's issuing person.

  • Name
    folio
    Type
    string?
    Description

    The point-of-sale folio number. It isn't the CFDI folio number: in the global invoice, it goes in itemSku (NoIdentificacion).

  • Name
    series
    Type
    string?
    Description

    The point-of-sale series, or null if the ticket has no series.

  • Name
    paymentDate
    Type
    string?
    Description

    The payment date and time in Mexico local time, with no time zone, exactly as the point of sale sent it.

  • Name
    paymentFormCode
    Type
    string?
    Description

    The form of payment (how the customer paid: cash, bank transfer, card; the FormaPago key). SAT catalog c_FormaPago.

  • Name
    currencyCode
    Type
    string?
    Description

    The sale's currency. SAT catalog c_Moneda.

  • Name
    exchangeRate
    Type
    number | decimal?
    Description

    The sale's exchange rate, or null for a sale in MXN.

  • Name
    expeditionZipCode
    Type
    string?
    Description

    The postal code of the place of issue (the postal code where the CFDI is issued).

  • Name
    subtotal
    Type
    number | decimal?
    Description

    The subtotal calculated by Fiscalapi.

  • Name
    totalTransferredTaxes
    Type
    number | decimal?
    Description

    The total of transferred taxes (traslado, a tax the issuer charges the recipient) calculated by Fiscalapi.

  • Name
    totalWithheldTaxes
    Type
    number | decimal?
    Description

    The total withholding (retención) calculated by Fiscalapi.

  • Name
    total
    Type
    number | decimal?
    Description

    The sale's total. It matches the calculated total to the cent.

  • Name
    status
    Type
    string?
    expandable
    Description

    The ticket status. See Ticket statuses.

    Type
    enum:
    Values
    "pending""invoicing""invoiced"
  • Name
    selfInvoiceEligible
    Type
    boolean?
    Description

    true if your customer can auto-invoice it today: the ticket is in pending and its auto-invoice window is still open. It's calculated on each query, with the current settings.

  • Name
    eligibleUntil
    Type
    string?
    Description

    The last moment of the auto-invoice window, or null if the window doesn't close. It's calculated on each query.

  • Name
    invoiceId
    Type
    string?
    Description

    The ID of the ticket's individual invoice, or null.

  • Name
    globalInvoiceId
    Type
    string?
    Description

    The ID of the global invoice that covers the ticket, or null.

  • Name
    createdAt
    Type
    string?
    Description

    The date and time the ticket was recorded.

  • Name
    items
    Type
    array of objects (TicketItem)?

    The sale's line items with their taxes. Only with details=true.

  • Name
    itemCode
    Type
    string?
    Description

    The SAT product or service key. SAT catalog c_ClaveProdServ.

  • Name
    itemSku
    Type
    string?
    Description

    The product's identifier in your point of sale.

  • Name
    quantity
    Type
    number | decimal?
    Description

    The quantity sold.

  • Name
    unitOfMeasurementCode
    Type
    string?
    Description

    The unit of measure. SAT catalog c_ClaveUnidad.

  • Name
    description
    Type
    string?
    Description

    The product or service description.

  • Name
    unitPrice
    Type
    number | decimal?
    Description

    The unit price before taxes.

  • Name
    discount
    Type
    number | decimal?
    Description

    The line item's discount.

  • Name
    taxObjectCode
    Type
    string?
    Description

    The tax object (whether an item is subject to tax, ObjetoImp). SAT catalog c_ObjetoImp.

  • Name
    itemTaxes
    Type
    array of objects (TicketItemTax)?

    The line item's taxes.

  • Name
    taxCode
    Type
    string?
    Description

    The tax. SAT catalog c_Impuesto.

  • Name
    taxTypeCode
    Type
    string?
    Description

    The factor type: Tasa (rate), Cuota (fixed amount), or Exento (exempt).

  • Name
    taxRate
    Type
    number | decimal?
    Description

    The tax rate or fixed amount.

  • Name
    taxFlagCode
    Type
    string?
    Description

    Transferred tax (T) or withholding (R).

  • Name
    events
    Type
    array of objects (TicketEvent)?

    The ticket's history, in order. Only in Get a ticket by ID with details=true.

  • Name
    type
    Type
    string?
    Description

    What happened; for example, ingested, invoiced, or cancelled. New types may appear.

  • Name
    occurredAt
    Type
    string?
    Description

    The date and time of the event.

  • Name
    actorType
    Type
    string?
    Description

    Who caused it: tenant (your tenant), portal (your customer in the portal), or system (a Fiscalapi process).

  • Name
    invoiceId
    Type
    string?
    Description

    The ID of the event's invoice, or null.


POST/api/v4/tickets

Create a ticket

This endpoint records a paid sale and uses 1 ticket credit from the authenticated person. It returns 201 with the ticket code and its QR code URL. The CFDI issued for the ticket is version 4.0, an income invoice (type I, the regular sales invoice), and not an export.

Its payment method (whether the CFDI is paid in full when issued, PUE, or later or in installments, PPD; not how the customer pays) is PUE (paid in full when the CFDI is issued, Pago en una sola exhibición).

Before charging, Fiscalapi checks that the issuing person belongs to your tenant and has complete tax details, a current CSD (Certificado de Sello Digital, the digital seal certificate used to sign CFDIs), and stamps (stamp: one credit, used each time you stamp a CFDI), because each auto-invoice uses one stamp from their balance. It also checks that the payment date is no more than 5 minutes in the future and that the total matches the calculated total to the cent.

Idempotency-Key header

The Idempotency-Key header is optional and accepts up to 64 characters. Use it to retry safely: if you repeat the same idempotency key with the same body, the endpoint returns 200 with the original ticket and doesn't charge again. The same key with a different body returns 422. Use a new key for each sale.

Without a key, the issuer can have only one active ticket with the same series and folio number: a duplicate returns 409, without charging, with the ticket that already has them in data.existingTicketId. To record that folio number again, cancel the existing ticket and record it again, which uses another credit.

Request body

  • Name
    issuer
    Type
    object (TicketIssuer)
    required

    The issuing person, by reference.

  • Name
    id
    Type
    string
    required
    Description

    The ID of the issuing person in your tenant that invoices the ticket.

  • Name
    folio
    Type
    string
    required
    Description

    The point-of-sale folio number, 1 to 40 characters, without the vertical bar character.

  • Name
    series
    Type
    string?
    Description

    The point-of-sale series, 1 to 25 characters, without the vertical bar character. If you omit it, the ticket has no series.

  • Name
    paymentDate
    Type
    string
    required
    Description

    The payment date and time in yyyy-MM-ddTHH:mm:ss format, in Mexico local time. This field doesn't use the X-TIME-ZONE header.

  • Name
    paymentFormCode
    Type
    string
    required
    Description

    The form of payment used to settle the sale. SAT catalog c_FormaPago. It doesn't accept "99" (por definir, to be defined).

  • Name
    currencyCode
    Type
    string?
    Description

    The sale's currency. SAT catalog c_Moneda. It doesn't accept "XXX".

    Default:
    MXN
  • Name
    exchangeRate
    Type
    number | decimal?
    Description

    The sale's exchange rate. With MXN, omit it or send null; with another currency, it's required and greater than 0.

  • Name
    expeditionZipCode
    Type
    string?
    Description

    The place-of-issue postal code, 5 digits. If you omit it, Fiscalapi uses the issuing person's.

  • Name
    total
    Type
    number | decimal
    required
    Description

    The total the point of sale charged. It must match, to the cent, the total calculated from the line items and taxes.

  • Name
    items
    Type
    array of objects (TicketItem)
    required

    The sale's line items, from 1 to 1,500.

  • Name
    itemCode
    Type
    string
    required
    Description

    The SAT product or service key, 8 characters. SAT catalog c_ClaveProdServ.

  • Name
    itemSku
    Type
    string
    required
    Description

    The product's identifier in your point of sale.

  • Name
    quantity
    Type
    number | decimal
    required
    Description

    The quantity sold, greater than 0 and with up to 6 decimal places.

  • Name
    unitOfMeasurementCode
    Type
    string
    required
    Description

    The unit of measure. SAT catalog c_ClaveUnidad.

  • Name
    description
    Type
    string
    required
    Description

    The description, 1 to 1,000 characters, without the vertical bar character.

  • Name
    unitPrice
    Type
    number | decimal
    required
    Description

    The unit price before taxes, with up to 6 decimal places.

  • Name
    discount
    Type
    number | decimal?
    Description

    The line item's discount, with up to 6 decimal places.

    Default:
    0
  • Name
    taxObjectCode
    Type
    string
    required
    Description

    The tax object. SAT catalog c_ObjetoImp. With 02, the line item carries at least one tax; with 01, 03, 04, or 05, it carries no taxes.

  • Name
    itemTaxes
    Type
    array of objects (TicketItemTax)?

    The line item's taxes, with the same fields as an invoice's. If the line item has no taxes, omit it or send an empty list.

  • Name
    taxCode
    Type
    string
    required
    Description

    The tax. SAT catalog c_Impuesto.

  • Name
    taxTypeCode
    Type
    string
    required
    Description

    The factor type: Tasa (rate), Cuota (fixed amount), or Exento (exempt).

  • Name
    taxRate
    Type
    number | decimal
    required
    Description

    The tax rate or fixed amount; for example, "0.160000".

  • Name
    taxFlagCode
    Type
    string
    required
    Description

    Transferred tax (T) or withholding (R).

Response

The body is the same in the 201 for a new ticket and in the 200 for a repeat with the same key.

  • Name
    id
    Type
    string?
    Description

    The ticket ID.

  • Name
    ticketCode
    Type
    string?
    Description

    The ticket code without hyphens, 12 characters. Print it in groups of 4 separated by hyphens; the portal accepts both forms.

  • Name
    qrUrl
    Type
    string?
    Description

    The portal URL that opens the ticket. Print it as a QR code on the sales receipt. See Code and QR code.

  • Name
    status
    Type
    string?
    Description

    The ticket status; when you record it, pending.

  • Name
    selfInvoiceEligible
    Type
    boolean?
    Description

    true if your customer can auto-invoice it today.

  • Name
    eligibleUntil
    Type
    string?
    Description

    The last moment of the auto-invoice window, or null if the window doesn't close.

  • Name
    subtotal
    Type
    number | decimal?
    Description

    The calculated subtotal.

  • Name
    totalTransferredTaxes
    Type
    number | decimal?
    Description

    The calculated total of transferred taxes.

  • Name
    totalWithheldTaxes
    Type
    number | decimal?
    Description

    The calculated total withholding.

  • Name
    total
    Type
    number | decimal?
    Description

    The calculated total, equal to the one you sent.

Errors

Validation failures arrive in ValidationFailure with the field that failed, before any charge. In the messages, <dato> is the tax detail the issuing person is missing, n is the available balance, and m is the required amount.

StatusWhen it happensMessage
400The issuer or its id is missing.'issuer.id' es obligatorio: la persona emisora del tenant que facturará el ticket.
400The folio number is missing or doesn't match its format.'folio' es obligatorio y debe tener de 1 a 40 caracteres sin el carácter '|'.
400The series doesn't match its format.'series' debe tener de 1 a 25 caracteres sin el carácter '|'; si se omite, el ticket queda sin serie.
400The form of payment is 99.'paymentFormCode' no puede ser 99 (por definir): un ticket es una venta ya pagada; usa la forma con la que se pagó.
400The currency is XXX.'currencyCode' no puede ser XXX: un ticket es una venta con importes.
400There's an exchange rate with MXN.'exchangeRate' no aplica con la moneda MXN (también es MXN si se omite 'currencyCode'): omítelo o envíalo null.
400The exchange rate is missing with another currency, or isn't greater than 0.'exchangeRate' es obligatorio con una moneda distinta de MXN y debe ser mayor que 0.
400There are no line items.'items' debe tener al menos un concepto.
400There are more than 1,500 line items.Un ticket admite como máximo 1500 conceptos (items).
400A line item with tax object (whether an item is subject to tax, ObjetoImp) 02 has no taxes.'itemTaxes' es obligatorio con taxObjectCode 02 (sí objeto de impuesto): agrega al menos un impuesto.
400A line item with tax object 01, 03, 04, or 05 has taxes.'itemTaxes' debe ir vacío con taxObjectCode 01, 03, 04 o 05: esos conceptos no desglosan impuestos.
400The Idempotency-Key header is longer than 64 characters.El header Idempotency-Key admite como máximo 64 caracteres.
403The authenticated person doesn't have enough ticket credits.Saldo insuficiente. Disponible: n, Requerido: m
403Your subscription doesn't include Auto CFDI invoicing. See Permissions and subscription.Para ingerir tickets tu suscripción debe incluir: Auto CFDI.
409The issuer already has an active ticket with that series and folio number. Its id is in data.existingTicketId.Ya hay un ticket activo con esa serie y folio para el emisor: 'data.existingTicketId' es el ticket que lo tiene. Para volver a ingerirlo, cancela ese ticket primero.
409Another record with the same series and folio number, or with the same key, changed at the same time. Repeat the request.Otro ticket con la misma serie y folio o la misma Idempotency-Key cambió mientras se ingería este. Intenta de nuevo.
422The key was already used with a different body.La Idempotency-Key ya se usó con otro cuerpo: una key identifica un solo ticket. Usa una key nueva para otro ticket.
422The total doesn't match to the cent. The total you sent is in data.expectedTotal, and the calculated one is in data.computedTotal.'total' no cuadra al centavo con el total calculado de los conceptos e impuestos: 'data.expectedTotal' es el enviado y 'data.computedTotal' el calculado.
422The payment date is more than 5 minutes in the future.'paymentDate' no puede ser posterior a ahora por más de 5 minutos: revisa el reloj del punto de venta.
422The issuing person doesn't belong to your tenant.'issuer.id' no es una persona de tu organización.
422The issuing person is missing a tax detail.La persona emisora no tiene <dato>: complétalo en sus datos fiscales para ingerir tickets.
422The issuing person doesn't have a current CSD.La persona emisora no tiene un CSD vigente (certificado y llave privada): cárgalo para ingerir tickets.
422The issuing person has no stamps.La persona emisora no tiene timbres: cada autofactura consume uno de su saldo. Transfiérele timbres para ingerir tickets.

Catalog keys and decimals use the same messages as invoice issuance: see SAT catalog keys and Decimal places in amounts, quantities, and rates.

Request

POST
/api/v4/tickets
curl --location 'https://test.fiscalapi.com/api/v4/tickets' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--header 'Idempotency-Key: pos-01-F-1001' \
--data-raw '{
  "issuer": { "id": "<person_id>" },
  "folio": "F-1001",
  "series": "A",
  "paymentDate": "2026-10-10T12:30:00",
  "paymentFormCode": "01",
  "total": 116.00,
  "items": [
    {
      "itemCode": "50202306",
      "itemSku": "SKU-1",
      "quantity": 1,
      "unitOfMeasurementCode": "H87",
      "description": "Refresco",
      "unitPrice": 100.00,
      "taxObjectCode": "02",
      "itemTaxes": [
        { "taxCode": "002", "taxTypeCode": "Tasa", "taxRate": "0.160000", "taxFlagCode": "T" }
      ]
    }
  ]
}'

Response

{
    "data": {
        "id": "9f8e7d6c-1b2a-4c3d-8e9f-0a1b2c3d4e5f",
        "ticketCode": "K7M2Q9X4TB3H",
        "qrUrl": "https://test.factura.fiscalapi.com/t/K7M2Q9X4TB3H",
        "status": "pending",
        "selfInvoiceEligible": true,
        "eligibleUntil": "2026-10-31T23:59:59.000",
        "subtotal": 100,
        "totalTransferredTaxes": 16,
        "totalWithheldTaxes": 0,
        "total": 116
    },
    "succeeded": true,
    "message": "",
    "details": "",
    "httpStatusCode": 201
}

GET/api/v4/tickets

List tickets

This endpoint returns your tenant's tickets, paginated and sorted by payment date. Each filter applies only if you send it. Use it to gather a period's pending tickets and build your global invoice for tickets.

For a grid, GET /api/v4/tickets/load returns your tenant's tickets with the DevExtreme load options (filtering, sorting, paging, and grouping) and returns its LoadResult, without the response envelope. It validates its parameters like the other load queries; see ValidationFailure.

Query parameters

  • Name
    status
    Type
    string?
    Description

    One or more statuses in camelCase. For several, repeat the parameter; for example, status=pending&status=invoiced.

  • Name
    personId
    Type
    string?
    Description

    The ID of the issuing person. A person from another tenant returns an empty list.

  • Name
    globalInvoiceId
    Type
    string?
    Description

    The ID of the global invoice that covers the tickets. An invoice from another tenant returns an empty list.

  • Name
    from
    Type
    string?
    Description

    The first payment day, inclusive, as a Mexico local date in YYYY-MM-DD format. It goes together with to.

  • Name
    to
    Type
    string?
    Description

    The last payment day, inclusive, as a Mexico local date in YYYY-MM-DD format. It goes together with from.

  • Name
    details
    Type
    boolean?
    Description

    With true, each ticket includes its line items with their taxes.

    Default:
    false
  • Name
    pageNumber
    Type
    integer | number?
    Description

    The page number, starting at 1.

    Default:
    1
  • Name
    pageSize
    Type
    integer | number?
    Description

    Tickets per page, from 1 to 50.

    Default:
    10

Errors

Each failure arrives as a validation failure on the parameter. In the messages, <valor> is the value received.

StatusWhen it happensMessage
400A status doesn't exist.'status' no admite '<valor>': usa pending, invoicing, invoiced, globalizing, globalized, cancelled (repite 'status' para varios).
400Only one of the two period bounds is sent.'from' y 'to' van juntos: envía ambos (fechas YYYY-MM-DD de México) o ninguno.
400The from date isn't in YYYY-MM-DD format.'from' debe ser una fecha YYYY-MM-DD.
400The to date isn't in YYYY-MM-DD format.'to' debe ser una fecha YYYY-MM-DD.
400The period's start is after its end.'from' no puede ser posterior a 'to'.
400The page size isn't between 1 and 50.'pageSize' debe estar entre 1 y 50.

Request

GET
/api/v4/tickets?status=pending&personId=<id>&from=2026-10-01&to=2026-10-31
curl --location 'https://test.fiscalapi.com/api/v4/tickets?status=pending&personId=<person_id>&from=2026-10-01&to=2026-10-31&pageNumber=1&pageSize=50' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'

Response

{
    "data": {
        "items": [
            {
                "id": "9f8e7d6c-1b2a-4c3d-8e9f-0a1b2c3d4e5f",
                "personId": "4b1c2d3e-5f60-4a7b-8c9d-0e1f2a3b4c5d",
                "folio": "F-1001",
                "series": "A",
                "paymentDate": "2026-10-10T12:30:00.000",
                "paymentFormCode": "01",
                "currencyCode": "MXN",
                "exchangeRate": null,
                "expeditionZipCode": "42501",
                "subtotal": 100,
                "totalTransferredTaxes": 16,
                "totalWithheldTaxes": 0,
                "total": 116,
                "status": "pending",
                "selfInvoiceEligible": true,
                "eligibleUntil": "2026-10-31T23:59:59.000",
                "invoiceId": null,
                "globalInvoiceId": null,
                "createdAt": "2026-10-10T12:31:00.000"
            }
        ],
        "pageNumber": 1,
        "totalPages": 1,
        "totalCount": 1,
        "hasPreviousPage": false,
        "hasNextPage": false
    },
    "succeeded": true,
    "message": "",
    "details": "",
    "httpStatusCode": 200
}

GET/api/v4/tickets/<id>

Get a ticket by ID

This endpoint returns a ticket with its status, its invoices, and its auto-invoice window. With details=true, it also includes its line items with their taxes and its history.

Query parameters

  • Name
    details
    Type
    boolean?
    Description

    With true, it includes the ticket's line items and history.

    Default:
    false

Errors

In the message, which arrives in details, <id> is the ticket ID.

StatusWhen it happensMessage
404The ticket doesn't exist or belongs to another tenant.No such resource for the given Id: <id>

Request

GET
/api/v4/tickets/<id>?details=true
curl --location 'https://test.fiscalapi.com/api/v4/tickets/<ticket_id>?details=true' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'

Response

{
    "data": {
        "id": "9f8e7d6c-1b2a-4c3d-8e9f-0a1b2c3d4e5f",
        "personId": "4b1c2d3e-5f60-4a7b-8c9d-0e1f2a3b4c5d",
        "folio": "F-1001",
        "series": "A",
        "paymentDate": "2026-10-10T12:30:00.000",
        "paymentFormCode": "01",
        "currencyCode": "MXN",
        "exchangeRate": null,
        "expeditionZipCode": "42501",
        "subtotal": 100,
        "totalTransferredTaxes": 16,
        "totalWithheldTaxes": 0,
        "total": 116,
        "status": "pending",
        "selfInvoiceEligible": true,
        "eligibleUntil": "2026-10-31T23:59:59.000",
        "invoiceId": null,
        "globalInvoiceId": null,
        "createdAt": "2026-10-10T12:31:00.000",
        "items": [
            {
                "itemCode": "50202306",
                "itemSku": "SKU-1",
                "quantity": 1,
                "unitOfMeasurementCode": "H87",
                "description": "Refresco",
                "unitPrice": 100,
                "discount": 0,
                "taxObjectCode": "02",
                "itemTaxes": [
                    { "taxCode": "002", "taxTypeCode": "Tasa", "taxRate": 0.16, "taxFlagCode": "T" }
                ]
            }
        ],
        "events": [
            { "type": "ingested", "occurredAt": "2026-10-10T12:31:00.000", "actorType": "tenant", "invoiceId": null }
        ]
    },
    "succeeded": true,
    "message": "",
    "details": "",
    "httpStatusCode": 200
}

GET/api/v4/tickets/<id>/code

Get a ticket code

This endpoint returns the ticket code and its QR code URL, the same ones that Create a ticket returned. Use it to reprint a sales receipt.

Errors

In the message, which arrives in details, <id> is the ticket ID.

StatusWhen it happensMessage
404The ticket doesn't exist or belongs to another tenant.No such resource for the given Id: <id>

Request

GET
/api/v4/tickets/<id>/code
curl --location 'https://test.fiscalapi.com/api/v4/tickets/<ticket_id>/code' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'

Response

{
    "data": {
        "ticketCode": "K7M2Q9X4TB3H",
        "qrUrl": "https://test.factura.fiscalapi.com/t/K7M2Q9X4TB3H"
    },
    "succeeded": true,
    "message": "",
    "details": "",
    "httpStatusCode": 200
}

DELETE/api/v4/tickets/<id>

Cancel a ticket

This endpoint cancels a ticket in pending status and releases its series and folio number so you can record it again. The ticket credit used when it was recorded isn't refunded. It requires Auto CFDI invoicing in your subscription.

You don't cancel an invoiced ticket here: cancel its invoice. When the cancellation of its individual invoice is confirmed with cancellation reason (one of the SAT keys 01 to 04) 02 (issued with errors, no replacement CFDI) or 03 (the transaction did not take place), the ticket returns to pending.

With reason 01 (issued with errors, replaced by a related CFDI), it stays linked to the replacement CFDI (CFDI replacement: you issue a corrected CFDI related to the original with relationship type 04, then cancel the original with reason 01) if the replacement relates to the original with type 04. For the global invoice, see Replace a global invoice for tickets.

Errors

In the messages, <id> is the ticket ID and <estado> is its current status.

StatusWhen it happensMessage
403Your subscription doesn't include Auto CFDI invoicing. See Permissions and subscription.Para cancelar tickets tu suscripción debe incluir: Auto CFDI.
404The ticket doesn't exist or belongs to another tenant.No such resource for the given Id: <id>
409The ticket isn't in pending.Solo se cancela un ticket en estado pending y este está en <estado>: ya se facturó, se está facturando o ya estaba cancelado. El crédito de ticket de la ingesta no se devuelve.
409The ticket's status changed while it was being canceled. Repeat the request.El ticket cambió de estado mientras se cancelaba (alguien lo estaba facturando). Intenta de nuevo.

Request

DELETE
/api/v4/tickets/<id>
curl --location --request DELETE 'https://test.fiscalapi.com/api/v4/tickets/<ticket_id>' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'

Response

{
    "data": true,
    "succeeded": true,
    "message": "",
    "details": "",
    "httpStatusCode": 200
}

POST/api/v4/invoices

Create a global invoice for tickets

This endpoint stamps the global invoice with the standard request of Create an invoice. With ticketId, Fiscalapi reserves the tickets before it deducts the stamp: all of them or none. When the CFDI is saved, the tickets move to globalized, with the invoice ID in globalInvoiceId. If the PAC (Proveedor Autorizado de Certificación, a SAT-authorized provider that stamps CFDIs) rejects the CFDI, the tickets return to their previous status and the stamp is refunded.

The example covers ticket F-1002, a sale of 166.00 with a soft drink of 100.00 at 16% IVA (Mexico's value-added tax, VAT) and still water of 50.00 at 0%. Its two tax groups go in two line items with the same ticketId, and each line item adds up what the ticket stored in its group. Global invoice for tickets explains how to build the line items and the CFDI.

Rules for ticketId

The items[].ticketId field is optional. Without it, the invoice is issued as usual.

RuleWhat happens if it isn't met
It goes only in an income global invoice, with typeCode I and globalInformation.400 on the line item's ticketId.
The global invoice carries the issuer by reference.400 on Issuer.Id.
The ticket belongs to your tenant and to the same issuing person, and is in the same currency as the global invoice.400 on the line item's ticketId.
The ticket's line items reflect the saved ticket.400 on the ticketId of the ticket's first line item.
The ticket is in pending, or in globalized in the global invoice you're replacing.409 with data.unavailableTickets, without charging or reserving tickets.

Retries

A 400 or a 409 doesn't charge the stamp or leave tickets reserved. On a 409, data.unavailableTickets contains the id and status of each ticket that was no longer available: query the pending tickets again and build the global invoice again. Don't retry the same request unchanged.

If the PAC doesn't respond, or responds with a server error and no rejection code, the result is uncertain because the CFDI may have been stamped. Fiscalapi returns the unexpected error and keeps the stamp, the folio number, and the reserved tickets so they can be reviewed. Don't issue another global invoice with those tickets: check your invoices and the tickets, and if they're still in globalizing, contact support with the traceIdentifier from the response.

Errors

Failures arrive as a validation failure, with the field in PascalCase; for example, Items[0].TicketId. In the messages, i is the line item's position, starting at 0.

StatusWhen it happensMessage
400A line item has a ticketId and the invoice isn't an income global invoice.'items[i].ticketId' solo aplica en una factura global de ingreso: 'typeCode' I con 'globalInformation'. Quita el ticketId o emite la factura global.
400The ticketId is empty or longer than 36 characters.'items[i].ticketId' debe tener de 1 a 36 caracteres: el id del ticket.
400The global invoice with tickets carries the issuer by value. It arrives on Issuer.Id.La factura global con tickets requiere el emisor por referencia ('issuer.id'): la persona emisora de los tickets.
400The ticket doesn't exist or belongs to another tenant.'items[i].ticketId' no es un ticket de tu organización.
400The ticket belongs to another issuing person.'items[i].ticketId' es un ticket de otra persona emisora: la factura global lleva solo tickets de su emisor, indicado por referencia ('issuer.id').
400The ticket is in another currency.'items[i].ticketId' es un ticket en otra moneda: la factura global lleva solo tickets de su moneda ('currencyCode').
400The ticket's line items don't reflect the saved ticket.Los conceptos con el ticket de 'items[i].ticketId' (<conceptos>) no reflejan ese ticket: la suma de sus importes (quantity × unitPrice), la de sus descuentos y la de sus impuestos por impuesto, tipo de factor y tasa deben ser las de los conceptos del ticket. Un ticket con impuestos distintos va en un concepto por cada grupo de impuestos, todos con el mismo ticketId.
409A ticket is no longer available. The tickets and their status are in data.unavailableTickets.Uno o más tickets ya no están disponibles para la factura global (solo entra un ticket en estado pending): 'data.unavailableTickets' dice cuáles y su estado. No se cobró el timbre ni quedó tomado ningún ticket.

In the message about line items that don't reflect the ticket, <conceptos> is the list of line items with that ticket; for example, items[0], items[1]. The invoice's other errors are those of Create a global invoice.

Request

POST
/api/v4/invoices
curl --location 'https://test.fiscalapi.com/api/v4/invoices' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
  "versionCode": "4.0",
  "series": "G",
  "date": "2026-11-01T10:00:00",
  "paymentFormCode": "01",
  "paymentMethodCode": "PUE",
  "currencyCode": "MXN",
  "exchangeRate": 1,
  "typeCode": "I",
  "expeditionZipCode": "42501",
  "exportCode": "01",
  "globalInformation": {
    "periodicityCode": "04",
    "monthCode": "10",
    "year": 2026
  },
  "issuer": { "id": "<person_id>" },
  "recipient": {
    "tin": "XAXX010101000",
    "legalName": "PUBLICO EN GENERAL",
    "zipCode": "42501",
    "taxRegimeCode": "616",
    "cfdiUseCode": "S01"
  },
  "items": [
    {
      "ticketId": "<ticket_id>",
      "itemCode": "01010101",
      "itemSku": "F-1002",
      "quantity": 1,
      "unitOfMeasurementCode": "ACT",
      "description": "Venta",
      "unitPrice": 100.000000,
      "discount": 0,
      "taxObjectCode": "02",
      "itemTaxes": [
        { "taxCode": "002", "taxTypeCode": "Tasa", "taxRate": "0.160000", "taxFlagCode": "T" }
      ]
    },
    {
      "ticketId": "<ticket_id>",
      "itemCode": "01010101",
      "itemSku": "F-1002",
      "quantity": 1,
      "unitOfMeasurementCode": "ACT",
      "description": "Venta",
      "unitPrice": 50.000000,
      "discount": 0,
      "taxObjectCode": "02",
      "itemTaxes": [
        { "taxCode": "002", "taxTypeCode": "Tasa", "taxRate": "0.000000", "taxFlagCode": "T" }
      ]
    }
  ]
}'

Response 409

{
    "data": {
        "unavailableTickets": [
            { "ticketId": "9f8e7d6c-1b2a-4c3d-8e9f-0a1b2c3d4e5f", "status": "invoiced" }
        ]
    },
    "succeeded": false,
    "message": "Sorry, it's not me, it's you.",
    "details": "Uno o más tickets ya no están disponibles para la factura global (solo entra un ticket en estado pending): 'data.unavailableTickets' dice cuáles y su estado. No se cobró el timbre ni quedó tomado ningún ticket.",
    "httpStatusCode": 409
}

Was this page helpful?