> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gigstack.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Receipts API Guide

> Integration guide for Receipts

<Note>Start with [shared fields](/concepts/shared-fields), then the [Mexico](/countries/mexico) or [Colombia](/countries/colombia) guide. The CFDI, RFC, SAT catalog, and payment-complement examples below describe Mexico; they are not universal country requirements.</Note>

Create, manage, and stamp receipts that can be converted into CFDI invoices. The Receipts API handles pre-invoice document creation with flexible validity periods and SAT compliance for later stamping.

## Overview

The Receipts API provides comprehensive receipt management for pre-invoice documents. Create receipts with automatic calculations, flexible validity periods, and stamp them as CFDI invoices when needed.

## Key Features

* **Receipt Creation** - Create pre-invoice receipts with automatic calculations
* **Flexible Validity** - Set custom validity periods (day, week, month, etc.)
* **CFDI Stamping** - Convert receipts to compliant CFDI invoices
* **Client Integration** - Full client management and auto-creation support
* **Enhanced Metadata Support** - Track custom data, references, and business identifiers with full flexibility
* **Periodicity Control** - Manage receipt lifecycle and validity
* **Idempotency** - Prevent duplicate receipt creation

## Endpoints

### List Receipts

```http theme={null}
GET /receipts
```

Retrieve a paginated list of receipts.

**Query Parameters:**

* `limit` (integer, 1-100) - Number of results per page (default: 10)
* `next` (string) - Pagination cursor for next page
* `team` (string) - gigstack Connect: Target team ID
* `order_by` (string) - Field to sort by (default: `timestamp`)
* `sort` (string) - Sort direction (`asc`, `desc`)
* `created[gte]` / `created[gt]` / `created[lte]` / `created[lt]` - Filter by creation date (epoch ms, seconds, or ISO date)
* `client_id` (string) - Filter by the gigstack client ID
* `tax_id` (string) - Filter by the client's tax ID / RFC (e.g., `tax_id=PEGJ800101ABC`)

`status`, `valid_until` and `metadata` are accepted but **ignored** by this endpoint — they do not narrow the results. Filter on them client-side.

**Example Request:**

```bash theme={null}
# All receipts for a given RFC
curl -X GET "https://api.gigstack.io/v2/receipts?tax_id=PEGJ800101ABC&limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Receipts for a specific client ID
curl -X GET "https://api.gigstack.io/v2/receipts?client_id=client_xxx&limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

**Example Response:**

```json theme={null}
{
    "message": "Receipts retrieved successfully",
    "data": [
        {
            "id": "receipt_1234567890",
            "client": {
                "id": "client_1234567890",
                "name": "Juan Pérez García",
                "tax_id": "PEGJ800101ABC"
            },
            "status": "pending",
            "total": 1160.0,
            "subtotal": 1000.0,
            "taxes": 160.0,
            "currency": "MXN",
            "periodicity": "month",
            "payment_form": "03",
            "created": 1677651234,
            "validUntil": 1680243234,
            "url": "https://invoicing.gigstack.pro/autofactura?id=receipt_1234567890"
        }
    ],
    "has_more": false,
    "total_results": 1
}
```

### Create Receipt

```http theme={null}
POST /receipts
```

Create a new receipt with items and client information. Receipts are pre-invoice documents that can be later stamped as CFDI invoices.

**Key Features:**

* Automatic amount calculations with taxes
* Flexible validity periods
* Client auto-creation support
* Metadata support for tracking
* Custom payment form codes
* Idempotency support to prevent duplicate receipts

**Request Body:**

```json theme={null}
{
    "client": {
        "id": "client_1234567890"
    },
    "currency": "MXN",
    "exchange_rate": 1.0,
    "items": [
        {
            "id": "service_1234567890",
            "quantity": 2,
            "unit_price": 1000.0
        }
    ],
    "periodicity": "month",
    "payment_form": "03",
    "idempotency_key": "receipt-key-12345",
    "metadata": {
        "order_id": "ORD-12345",
        "department": "Sales",
        "project_code": "PROJ-2024-Q1",
        "external_reference": "EXT-ABC-789",
        "priority": "high",
        "custom_tags": ["recurring", "priority-client"]
    }
}
```

**Optional Fields:**

* `idempotency_key` (string) - Stable key for one receipt. A repeated creation returns `400 resource_conflict` with the existing receipt ID in the details. Retrieve the receipt rather than creating a new key for the same sale.
* `exchange_rate` (number) - Exchange rate for currency conversion. If not provided, the latest rate from our rates collection will be used automatically.

#### Periodicity Options

> ### ⚠️ On receipts the value is `two_month` — singular
>
> The receipts endpoints accept exactly these five values:
>
> ```
> day | week | two_weeks | month | two_month
> ```
>
> **Team settings use `two_months` — plural** (`PUT /v2/teams/{id}/settings`, field `defaults.periodicity`). The two endpoints genuinely disagree, and neither one accepts the other's spelling. This is not a typo in the docs; it is the current state of the API, kept as-is because normalizing it would break live integrations. Do not copy a periodicity value from one endpoint's payload into the other's — look it up.
>
> Sending `two_months` to a receipts endpoint fails validation with a `400` naming the allowed enum values.

| Value | Receipt is valid until |
| - | - |
| `day` | End of the current day |
| `week` | End of the current week |
| `two_weeks` | 2 weeks from creation, end of that day |
| `month` | End of the current month — **the default** when `periodicity` is omitted |
| `two_month` | End of the current month |

> **`two_month` currently behaves the same as `month`.** The validity calculation is keyed on the plural spelling, so the singular value the schema accepts falls through to the default branch and yields end-of-current-month rather than end-of-next-month. If you need a receipt to stay valid into the following month, set `invoice_config.validUntil` explicitly instead of relying on `two_month`.

**Payment Form Codes:**

* `01` - Cash
* `02` - Check
* `03` - Electronic transfer
* `04` - Credit card
* `05` - Electronic money
* `06` - Digital money
* `99` - To be defined

**Idempotency:**

Keep one `idempotency_key` for the same receipt across retry attempts. This prevents a repeated key from creating another receipt; it is not a success-response replay or a universal exactly-once guarantee.

* If the key already exists, the verified creation response is `400` with `error.code: "resource_conflict"` and the existing receipt ID in the details. Retrieve that ID with `GET /receipts/{id}` and compare it with the intended sale.
* Use a new key for a different business receipt, never merely to bypass the duplicate error. The [receipt recipe](/recipes/receipt) shows the observed response and creation flow.
* Common patterns: use UUIDs, combine order ID with timestamp, or use external system references

**Example with Client Auto-Creation:**

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client": {
      "search": {
        "on_key": "tax_id",
        "on_value": "PEGJ800101ABC",
        "auto_create": true,
        "safety_check": false
      },
      "name": "Juan Pérez García",
      "email": "juan.perez@ejemplo.com",
      "tax_id": "PEGJ800101ABC",
      "tax_system": "601"
    },
    "currency": "MXN",
    "items": [
      {
        "description": "Professional services",
        "quantity": 1,
        "unit_price": 5000.00,
        "product_key": "80141503",
        "unit_key": "E48",
        "taxes": [
          {
            "type": "IVA",
            "rate": 0.16
          }
        ]
      }
    ],
    "periodicity": "month",
    "payment_form": "03"
  }'
```

### Get Receipt

```http theme={null}
GET /receipts/{id}
```

Retrieve a specific receipt by ID.

**Example Request:**

```bash theme={null}
curl -X GET https://api.gigstack.io/v2/receipts/receipt_1234567890 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Stamp Receipt

```http theme={null}
POST /receipts/{id}/stamp
```

Convert a receipt into a CFDI invoice by stamping it with SAT.

**Stamp Options:**

* `client` - Stamp to the associated client
* `general_public_national` - Stamp to Mexican general public
* `general_public_foreign` - Stamp to foreign general public

**Request Body:**

```json theme={null}
{
    "stamp_to": "client",
    "fiscal_information": {
        "legal_name": "Juan Pérez García",
        "tax_id": "PEGJ800101ABC",
        "tax_system": "601",
        "zip": "01000"
    },
    "date": 1677651234000
}
```

**Example Request:**

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts/receipt_1234567890/stamp \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stamp_to": "client",
    "date": 1677651234000
  }'
```

### Reopen Receipt

```http theme={null}
POST /receipts/{id}/reopen
```

Return a receipt whose self-invoicing failed to `pending`, so the client can try again from the self-invoicing portal. Clears `automatic_invoice_error`.

Only a receipt that is **not** `pending` and has **no** entries in `invoices[]` can be reopened. An already-pending receipt, or one that produced a CFDI, answers `409` — reopening never cancels a CFDI. The optional `reason` (up to 500 characters) is kept on the receipt for your own audit trail and is not returned by the API.

**Example Request:**

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts/receipt_1234567890/reopen \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "El cliente pidió corregir su RFC" }'
```

Answers `200` with the receipt in `data`, back at `status: pending`.

### Cancel Receipt

```http theme={null}
DELETE /receipts/{id}
```

Cancel a receipt. This action cannot be undone.

**Example Request:**

```bash theme={null}
curl -X DELETE https://api.gigstack.io/v2/receipts/receipt_1234567890 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Receipt Structure

### Receipt Status

| Status | Description |
| - | - |
| `pending` | Receipt created, awaiting stamping |
| `stamped` | Receipt converted to CFDI invoice |
| `expired` | Receipt validity period expired |
| `canceled` | Receipt canceled |

### Validity Periods

Receipts have configurable validity periods based on the `periodicity` parameter:

* **day**: Valid until end of creation day
* **week**: Valid until end of creation week
* **two\_weeks**: Valid for 14 days from creation
* **month**: Valid until end of creation month (default)
* **two\_month** (singular — see the [box above](#periodicity-options)): accepted, but currently resolves to end of creation month, same as `month`

Anything not in that list is rejected. In particular `two_months` (plural) is a **team-settings** value, not a receipts value.

When the exact expiry matters, set `invoice_config.validUntil` (epoch ms) rather than deriving it from `periodicity`.

## Complex Receipt Examples

### Receipt with Multiple Items

```json theme={null}
{
    "client": {
        "id": "client_1234567890"
    },
    "currency": "MXN",
    "items": [
        {
            "id": "service_001",
            "quantity": 2,
            "unit_price": 1000.0
        },
        {
            "description": "Installation service",
            "quantity": 1,
            "unit_price": 500.0,
            "product_key": "72121400",
            "unit_key": "E48",
            "taxes": [
                {
                    "type": "IVA",
                    "rate": 0.16
                }
            ]
        }
    ],
    "periodicity": "two_weeks",
    "payment_form": "04"
}
```

### Receipt with USD Currency and Exchange Rate

```json theme={null}
{
    "client": {
        "id": "client_1234567890"
    },
    "currency": "USD",
    "exchange_rate": 18.5,
    "items": [
        {
            "description": "International consulting",
            "quantity": 10,
            "unit_price": 100.0,
            "product_key": "80141503",
            "unit_key": "HUR",
            "taxes": [
                {
                    "type": "IVA",
                    "rate": 0.0,
                    "factor": "Exento"
                }
            ]
        }
    ],
    "periodicity": "month",
    "payment_form": "03"
}
```

### Receipt with Custom Invoice Configuration

```json theme={null}
{
    "client": {
        "id": "client_1234567890"
    },
    "currency": "MXN",
    "items": [
        {
            "id": "service_1234567890",
            "quantity": 1
        }
    ],
    "periodicity": "month",
    "payment_form": "03",
    "invoice_config": {
        "serie": "B",
        "folio": 456
    },
    "metadata": {
        "project_id": "PROJ-2024-001",
        "department": "Engineering"
    }
}
```

## Enhanced Metadata Support

The receipts API now supports flexible metadata storage that preserves all custom properties you provide. This enhancement allows you to:

* **Store Any Custom Properties** - Add any key-value pairs relevant to your business
* **Preserve Data Structure** - All metadata properties are returned exactly as submitted
* **Track Business References** - Store external IDs, project codes, and system identifiers
* **Support Complex Data** - Use nested objects, arrays, and mixed data types

### Metadata Usage Examples

**Basic Tracking:**

```json theme={null}
{
    "metadata": {
        "order_id": "ORD-12345",
        "department": "Sales"
    }
}
```

**Advanced Tracking:**

```json theme={null}
{
    "metadata": {
        "project": {
            "code": "PROJ-2024-Q1",
            "manager": "Alice Smith",
            "budget_category": "consulting"
        },
        "external_systems": {
            "crm_id": "CRM-789",
            "erp_reference": "ERP-ABC-123"
        },
        "tags": ["priority", "recurring", "b2b"],
        "workflow_stage": "approved",
        "custom_fields": {
            "delivery_date": "2024-03-15",
            "special_instructions": "Rush order"
        }
    }
}
```

**Integration Identifiers:**

```json theme={null}
{
    "metadata": {
        "stripe_session_id": "cs_test_123",
        "shopify_order_id": "shop_456",
        "quickbooks_reference": "QB-789",
        "internal_workflow_id": "WF-2024-001"
    }
}
```

## Common Scenarios

### 1. Create Monthly Receipt (Standard)

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client": {"id": "client_1234567890"},
    "currency": "MXN",
    "items": [{
      "id": "service_1234567890",
      "quantity": 1
    }],
    "periodicity": "month",
    "payment_form": "03",
    "idempotency_key": "receipt-2024-0123",
    "metadata": {
      "order_reference": "ORD-2024-0123"
    }
  }'
```

### 2. Create Weekly Receipt

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client": {"id": "client_1234567890"},
    "currency": "MXN",
    "items": [{
      "description": "Weekly rental",
      "quantity": 1,
      "unit_price": 2000.00,
      "product_key": "81111500",
      "unit_key": "DAY",
      "taxes": [{"type": "IVA", "rate": 0.16}]
    }],
    "periodicity": "week",
    "payment_form": "01"
  }'
```

### 3. Stamp Receipt to Client

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts/receipt_1234567890/stamp \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stamp_to": "client"
  }'
```

### 4. Stamp to General Public

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/receipts/receipt_1234567890/stamp \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stamp_to": "general_public_national",
    "fiscal_information": {
      "legal_name": "Público en General",
      "tax_id": "XAXX010101000",
      "tax_system": "616",
      "zip": "01000"
    }
  }'
```

## Receipt Workflows

### Standard Receipt Workflow

```mermaid theme={null}
graph LR
    A[Create Receipt] --> B[Receipt Pending]
    B --> C[Customer Views Receipt]
    C --> D[Stamp as CFDI]
    D --> E[Invoice Generated]
```

### Receipt with Auto-Client Creation

```mermaid theme={null}
graph LR
    A[Create Receipt] --> B[Search Client]
    B --> C{Client Found?}
    C -->|No| D[Create Client]
    C -->|Yes| E[Use Existing]
    D --> F[Create Receipt]
    E --> F
```

### Receipt Validity Management

```mermaid theme={null}
graph LR
    A[Receipt Created] --> B[Set Validity Period]
    B --> C{Within Period?}
    C -->|Yes| D[Can Stamp]
    C -->|No| E[Expired]
    D --> F[Stamp as CFDI]
```

## Best Practices

1. **Set appropriate periodicity** - Choose validity periods based on your workflow
2. **Leverage enhanced metadata** - Store any custom data, external references, and business identifiers; all properties are preserved exactly as submitted
3. **Include complete item information** - Ensure accurate calculations
4. **Validate clients first** - Check fiscal data before creating receipts
5. **Monitor receipt expiration** - Stamp receipts before they expire
6. **Handle exchange rates** - Set proper rates for foreign currency receipts
7. **Test stamping process** - Validate CFDI generation in staging
8. **Structure metadata thoughtfully** - Use consistent naming conventions and organize data logically for easy retrieval and filtering
9. **Use idempotency keys** - Always provide an `idempotency_key` when creating receipts to prevent duplicates, especially when retrying failed requests or processing webhook events

## Related Resources

* [Clients API](/guides/clients) - Manage receipt recipients
* [Services API](/guides/services) - Configure receipt items
* [Payments API](/guides/payments) - Process payments for receipts
* [Invoices API](/guides/invoices) - View stamped receipts as invoices

## Error Handling

### At a glance

| Status | When | Retry the same request? | What you should do |
| - | - | - | - |
| `400` | Validation/state failure, or `resource_conflict` for a repeated creation key | Depends on code | Fix invalid input; for a duplicate, retrieve and reconcile the original receipt rather than changing its key. |
| `401` | Missing/invalid token, or no resolvable team | No | Re-authenticate. |
| `403` | The receipt belongs to another team | No | Use `?team=` (gigstack Connect). |
| `404` | Receipt or its client not found, or the receipt's `livemode` does not match the key | No | Check the id, and that you are using the key for that environment. |
| `409` | A concurrent request is auto-creating the same client/service | **Yes**, after a short backoff | Retry once. |
| `429` | **Team credit limit reached** on `POST /receipts` | No, until raised | See below. |
| `500` | Downstream stamping service failed | Maybe | See below. |

### 429 — Team credit limit reached

`POST /v2/receipts` consumes a team credit **before** the receipt is created:

```json theme={null}
{
    "success": false,
    "error": {
        "code": "team_credit_limit_reached",
        "message": "Team credit limit reached",
        "details": "Team credit limit reached (500/500)"
    },
    "timestamp": 1718451000000
}
```

Not a rate limit — backing off will not help. Raise `credit_limit` on the team (`PUT /v2/teams/{id}`) or contact gigstack. Nothing was created and nothing was charged.

> The invoice endpoints report the same condition with a different body (`credit_limit` / `used_credits` at the top level). See [Invoices → 429](/guides/invoices#429-—-team-credit-limit-reached).

### 400 — Invalid periodicity

```json theme={null}
{
    "success": false,
    "error": {
        "code": "validation_failed",
        "message": "Invalid request body",
        "details": ["periodicity: must be one of day, week, two_weeks, month, two_month"]
    }
}
```

Almost always caused by sending `two_months` (plural), which is the **team-settings** spelling. See the [periodicity box](#periodicity-options).

### 400 — Invalid `stamp_to` combination

`POST /receipts/{id}/stamp` enforces two rules:

```json theme={null}
{
    "error": "Invalid request",
    "message": "fiscal_information cannot be provided when stamp_to is general_public"
}
```

```json theme={null}
{
    "error": "Missing client information",
    "message": "fiscal_information is required when stamp_to is client and receipt has no client"
}
```

**Do:** for `general_public_national` / `general_public_foreign`, omit `fiscal_information` entirely — gigstack supplies the SAT generic receiver. For `stamp_to: "client"`, either the receipt must already reference a client, or you must pass `fiscal_information` yourself.

### 404 — Client not found while stamping

```json theme={null}
{
    "error": "Client not found",
    "message": "Client not found in database"
}
```

The receipt references a client id that no longer exists. Re-stamp passing `fiscal_information` explicitly, or recreate the client.

### 400 — Cannot cancel

`DELETE /receipts/{id}` only accepts receipts that are still open:

```json theme={null}
{
    "success": false,
    "error": {
        "code": "invalid_request_body",
        "message": "Cannot cancel receipt with status: completed. Only pending receipts can be cancelled."
    }
}
```

```json theme={null}
{
    "success": false,
    "error": {
        "code": "invalid_request_body",
        "message": "Cannot cancel receipt that has already expired (validUntil is in the past)."
    }
}
```

Both are terminal — an already-stamped or already-expired receipt cannot be cancelled through the API. If a stamped receipt produced an invoice you need to void, cancel the **invoice** instead (`DELETE /v2/invoices/{id}`).

### 500 — Stamping failed downstream

```json theme={null}
{
    "error": "…the underlying service's message…",
    "message": "Failed to process receipt: 400 Bad Request"
}
```

The receipt reached the stamping service and it refused. The `error` field carries the real reason — most often incomplete fiscal data on the resolved receiver (missing `tax_system`, `zip`, or an RFC the SAT rejects). Read the receipt again before deciding to stamp: inspect its status, `invoices` and any error. Fix an identified validation problem, but do not assume a `500` proves the provider did not issue a document. If the outcome is ambiguous, reconcile it with support before another stamp.

### Failed Client Fiscal Information

When a client's fiscal information fails validation (invalid RFC or EFOS blacklist), receipt creation is rejected with `400`. Update the client (`PUT /v2/clients/{id}`) and retry.

***

For additional assistance, contact [support@gigstack.io](mailto:support@gigstack.io)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.