# Tickets de compra

> Guarde la foto de un ticket que el emisor pagó sin factura, con la tienda, su RFC y el total, y pida la factura o márquelo como no deducible.

Sus usuarios pagan gasolina, comidas y papelería con ticket, y la factura se queda pendiente. Mande la foto (o el PDF) de cada ticket con sus datos: la tienda, su RFC, la fecha, el total, la forma de pago, el folio, los datos que pide su portal (Web ID, sucursal…) y la liga de facturación del QR. Luego pida la factura a la tienda o márquelo como no deducible. Cuando la factura de esa tienda llega con las [descargas del SAT](https://fiscalisto.com/docs/api/descargas-del-sat), el ticket queda `invoiced` solo.

Es lo mismo que **Gastos › Tickets de compra** en la app.

## Guardar un ticket

Mande el archivo en base64 con su `file_type` (`image/jpeg`, `image/png`, `image/webp` o `application/pdf`), de hasta 8 MB. Reduzca la foto antes de mandarla (2,000 px del lado mayor bastan). Si su app ya leyó el código QR, mándelo en `qr_text`: es la fuente más confiable de la liga del portal, y si la tienda factura con Fiscalisto llena solo el folio y el total.

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/purchase_receipts \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "/9j/4AAQSkZJRgABAQAAAQABAAD...",
    "file_type": "image/jpeg",
    "qr_text": "https://facturacion.laspalmas.mx/?ticket=A-48213",
    "store_name": "Gasolinera Las Palmas",
    "store_tax_id": "GLP0503158A2",
    "date": "2026-10-30",
    "total": 348.5
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const purchaseReceipt = await fiscalisto.purchaseReceipts.create({
  file: "/9j/4AAQSkZJRgABAQAAAQABAAD...",
  file_type: "image/jpeg",
  qr_text: "https://facturacion.laspalmas.mx/?ticket=A-48213",
  store_name: "Gasolinera Las Palmas",
  store_tax_id: "GLP0503158A2",
  date: "2026-10-30",
  total: 348.5,
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

purchase_receipt = fiscalisto.purchase_receipts.create({
    "file": "/9j/4AAQSkZJRgABAQAAAQABAAD...",
    "file_type": "image/jpeg",
    "qr_text": "https://facturacion.laspalmas.mx/?ticket=A-48213",
    "store_name": "Gasolinera Las Palmas",
    "store_tax_id": "GLP0503158A2",
    "date": "2026-10-30",
    "total": 348.5,
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$purchaseReceipt = $fiscalisto->purchaseReceipts->create([
    'file' => '/9j/4AAQSkZJRgABAQAAAQABAAD...',
    'file_type' => 'image/jpeg',
    'qr_text' => 'https://facturacion.laspalmas.mx/?ticket=A-48213',
    'store_name' => 'Gasolinera Las Palmas',
    'store_tax_id' => 'GLP0503158A2',
    'date' => '2026-10-30',
    'total' => 348.5,
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	purchaseReceipt, err := client.PurchaseReceipts.Create(ctx, &fiscalisto.CreatePurchaseReceiptParams{
		File:       "/9j/4AAQSkZJRgABAQAAAQABAAD...",
		FileType:   "image/jpeg",
		QrText:     fiscalisto.String("https://facturacion.laspalmas.mx/?ticket=A-48213"),
		StoreName:  fiscalisto.String("Gasolinera Las Palmas"),
		StoreTaxID: fiscalisto.String("GLP0503158A2"),
		Date:       fiscalisto.String("2026-10-30"),
		Total:      fiscalisto.Float64(348.5),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(purchaseReceipt.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreatePurchaseReceiptParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = fiscalisto.purchaseReceipts().create(new CreatePurchaseReceiptParams()
        .setFile("/9j/4AAQSkZJRgABAQAAAQABAAD...")
        .setFileType("image/jpeg")
        .setQrText("https://facturacion.laspalmas.mx/?ticket=A-48213")
        .setStoreName("Gasolinera Las Palmas")
        .setStoreTaxId("GLP0503158A2")
        .setDate("2026-10-30")
        .setTotal(348.5));
System.out.println(purchaseReceipt.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = await fiscalisto.PurchaseReceipts.CreateAsync(new CreatePurchaseReceiptParams
{
    File = "/9j/4AAQSkZJRgABAQAAAQABAAD...",
    FileType = "image/jpeg",
    QrText = "https://facturacion.laspalmas.mx/?ticket=A-48213",
    StoreName = "Gasolinera Las Palmas",
    StoreTaxId = "GLP0503158A2",
    Date = "2026-10-30",
    Total = 348.5m,
});
```

Contesta `201` con el ticket guardado. Fiscalisto no lee la foto: guarda los datos que usted mande (`store_tax_id`, `total`, `date`, `fields`…) y los que falten se llenan después con `POST /v1/purchase_receipts/{id}`. Para encontrar la factura cuando llega del SAT hacen falta `store_tax_id` y `total`. El mismo archivo dos veces contesta el ticket que ya estaba.

Guardar tickets no gasta timbres. Cada ticket cuenta en el límite diario de tickets de compra: 100 al día en pruebas y 5,000 en producción. Ver [Límites](https://fiscalisto.com/docs/api/limites).

## Corregir sus datos

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/purchase_receipts/rct_OufpKqnrvx9p4X \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "total": 348.5,
    "payment_method": "tarjeta",
    "use": "G03"
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const purchaseReceipt = await fiscalisto.purchaseReceipts.update("rct_OufpKqnrvx9p4X", {
  total: 348.5,
  payment_method: "tarjeta",
  use: "G03",
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

purchase_receipt = fiscalisto.purchase_receipts.update("rct_OufpKqnrvx9p4X", {
    "total": 348.5,
    "payment_method": "tarjeta",
    "use": "G03",
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$purchaseReceipt = $fiscalisto->purchaseReceipts->update('rct_OufpKqnrvx9p4X', [
    'total' => 348.5,
    'payment_method' => 'tarjeta',
    'use' => 'G03',
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	purchaseReceipt, err := client.PurchaseReceipts.Update(ctx, "rct_OufpKqnrvx9p4X", &fiscalisto.UpdatePurchaseReceiptParams{
		Total:         fiscalisto.Float64(348.5),
		PaymentMethod: fiscalisto.String("tarjeta"),
		Use:           fiscalisto.String("G03"),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(purchaseReceipt.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.UpdatePurchaseReceiptParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = fiscalisto.purchaseReceipts().update("rct_OufpKqnrvx9p4X", new UpdatePurchaseReceiptParams()
        .setTotal(348.5)
        .setPaymentMethod("tarjeta")
        .setUse("G03"));
System.out.println(purchaseReceipt.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = await fiscalisto.PurchaseReceipts.UpdateAsync("rct_OufpKqnrvx9p4X", new UpdatePurchaseReceiptParams
{
    Total = 348.5m,
    PaymentMethod = "tarjeta",
    Use = "G03",
});
```

Solo cambia lo que mande; `null` borra un dato. `use` es el uso de la factura que se pide: por omisión G03 si el régimen del emisor lo permite, si no S01, y solo acepta los usos de gastos que permite su régimen.

## Pedir la factura

`POST /v1/purchase_receipts/{id}/request` con `method`:

- `fiscalisto`: la tienda factura con Fiscalisto (`store.on_fiscalisto` es `true`, su QR es una liga de autofactura). La factura se timbra al momento con los datos fiscales del emisor, la tienda la manda a `reply_to` y el ticket queda `invoiced` con su `invoice_uuid`.
- `email`: le mandamos a la tienda (`to`, o `store.email`) los datos fiscales del emisor, los del ticket y la foto. Las respuestas llegan a `reply_to`, o al correo de respuesta del emisor. El ticket queda `requested`.
- `portal` o `manual`: usted la pidió en el portal de la tienda (`store.portal_url`) o en persona. Solo queda `requested`.

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/purchase_receipts/rct_OufpKqnrvx9p4X/request \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "portal"
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const purchaseReceipt = await fiscalisto.purchaseReceipts.requestInvoice("rct_OufpKqnrvx9p4X", { method: "portal" });
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

purchase_receipt = fiscalisto.purchase_receipts.request_invoice("rct_OufpKqnrvx9p4X", {"method": "portal"})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$purchaseReceipt = $fiscalisto->purchaseReceipts->requestInvoice('rct_OufpKqnrvx9p4X', ['method' => 'portal']);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	purchaseReceipt, err := client.PurchaseReceipts.RequestInvoice(ctx, "rct_OufpKqnrvx9p4X", &fiscalisto.RequestPurchaseReceiptInvoiceParams{
		Method: "portal",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(purchaseReceipt.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.RequestPurchaseReceiptInvoiceParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = fiscalisto.purchaseReceipts().requestInvoice("rct_OufpKqnrvx9p4X", new RequestPurchaseReceiptInvoiceParams().setMethod("portal"));
System.out.println(purchaseReceipt.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = await fiscalisto.PurchaseReceipts.RequestInvoiceAsync("rct_OufpKqnrvx9p4X", new RequestPurchaseReceiptInvoiceParams
{
    Method = "portal",
});
```

Para pedirla, el emisor necesita su razón social, régimen fiscal y código postal; si falta alguno contesta `purchase_receipt_invalid` y dice cuál.

## Cuando llega la factura

No tiene que hacer nada: si con las descargas del SAT llega una factura recibida de esa tienda (mismo RFC, al RFC del emisor, por el mismo total con hasta un peso de diferencia y de la fecha de la compra a 120 días después), el ticket queda `invoiced` e `invoice` trae la factura (`sat_…`). Si la recibió por otro lado, use `mark_invoiced`, con `invoice` si sabe cuál es:

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/purchase_receipts/rct_OufpKqnrvx9p4X/mark_invoiced \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice": "sat_OufpKqnrvx9p1Dn"
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const purchaseReceipt = await fiscalisto.purchaseReceipts.markInvoiced("rct_OufpKqnrvx9p4X", { invoice: "sat_OufpKqnrvx9p1Dn" });
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

purchase_receipt = fiscalisto.purchase_receipts.mark_invoiced("rct_OufpKqnrvx9p4X", {"invoice": "sat_OufpKqnrvx9p1Dn"})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$purchaseReceipt = $fiscalisto->purchaseReceipts->markInvoiced('rct_OufpKqnrvx9p4X', ['invoice' => 'sat_OufpKqnrvx9p1Dn']);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	purchaseReceipt, err := client.PurchaseReceipts.MarkInvoiced(ctx, "rct_OufpKqnrvx9p4X", &fiscalisto.MarkPurchaseReceiptInvoicedParams{
		Invoice: fiscalisto.String("sat_OufpKqnrvx9p1Dn"),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(purchaseReceipt.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.MarkPurchaseReceiptInvoicedParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = fiscalisto.purchaseReceipts().markInvoiced("rct_OufpKqnrvx9p4X", new MarkPurchaseReceiptInvoicedParams()
        .setInvoice("sat_OufpKqnrvx9p1Dn"));
System.out.println(purchaseReceipt.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var purchaseReceipt = await fiscalisto.PurchaseReceipts.MarkInvoicedAsync("rct_OufpKqnrvx9p4X", new MarkPurchaseReceiptInvoicedParams
{
    Invoice = "sat_OufpKqnrvx9p1Dn",
});
```

Una factura cubre un solo ticket.

## Si no le dan factura

`POST /v1/purchase_receipts/{id}/mark_non_deductible` lo deja como gasto no deducible. `reopen` lo deshace: vuelve a `requested` si ya se había pedido, si no a `pending`.

Dos avisos que trae cada ticket:

- `cash_over_limit`: se pagó en efectivo más de $2,000. Aunque tenga factura, ese gasto no es deducible (LISR art. 27, fr. III).
- `days_left_in_month`: los días que le quedan al mes de la compra, en hora de México. La ley no le pone plazo al comprador, pero muchas tiendas solo facturan dentro del mes.

## Consultar

`GET /v1/purchase_receipts` los lista del más reciente al más antiguo, con `status` para ver solo `pending`, `requested`, `invoiced` o `non_deductible`. `DELETE /v1/purchase_receipts/{id}` borra el ticket y su archivo.
