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

# Preview Invoice PDF

> Accepts the exact same request body as `POST /organizations/{organizationId}/invoices`, runs the exact same catalog/CFDI 4.0 validations, but never timbra (no PAC call) and never persists anything — no invoice, no cuota consumida, no idempotencyKey handling. Returns a PDF clearly marked as 'VISTA PREVIA — NO VÁLIDO FISCALMENTE' so it can never be confused with a real representación impresa.

Generates a PDF preview of a CFDI 4.0 invoice **without stamping it at the SAT and without persisting anything**. Use this to let a user review an invoice's data before confirming the real emission — stamping has a cost (every timbre is billed by the PAC) and can't be easily undone (it requires a formal cancellation).

Accepts the **exact same request body** as [Create Invoice](/api-reference/invoices/create) — same `CreateInvoiceDto` shape, same `type`, `customer`/`customerId`, `items[]`, etc. — and runs the exact same SAT catalog / CFDI 4.0 validations, so a payload that would fail to stamp also fails to preview with the same `400`.

<Note>
  This endpoint never calls the PAC, never writes an invoice record, and never
  consumes your plan's CFDI quota. It also ignores `idempotencyKey` if sent —
  previews have nothing to deduplicate, since nothing is persisted.
</Note>

The resulting PDF is visibly marked as a preview so it can never be mistaken for a real representación impresa:

* A red banner reading **"VISTA PREVIA — NO VÁLIDO FISCALMENTE"**
* No folio fiscal (UUID)
* No digital seals (sellos)
* No SAT verification QR code

None of those exist until the CFDI is actually stamped, so the preview simply omits them.

## Authentication

Accepts **either**:

* A Supabase Bearer session (`Authorization: Bearer <token>`) — the authenticated user must be a member of `organizationId`.
* An API key (`X-API-Key: sk_...`) with the `write:invoices` scope — the key's own organization must match `organizationId` in the URL, or the request is rejected with `403 Forbidden`.

## Path Parameters

| Parameter        | Type          | Required | Description     |
| ---------------- | ------------- | -------- | --------------- |
| `organizationId` | string (UUID) | Yes      | Organization ID |

## Request Body

Same shape as [Create Invoice](/api-reference/invoices/create#request-body) — see that page for the full field reference (`customer`/`customerId`, `items[]`, `taxes[]`, etc.). `idempotencyKey` is accepted for shape compatibility but ignored.

## Example Request

```bash cURL theme={null}
curl -X POST https://api.timbrix.mx/organizations/550e8400-e29b-41d4-a716-446655440000/invoices/preview/pdf \
  -H "Authorization: Bearer <your_token>" \
  -H "Content-Type: application/json" \
  -o preview.pdf \
  -d '{
    "series": "A",
    "folioNumber": "1",
    "date": "2026-07-30T15:50:00",
    "paymentForm": "01",
    "paymentMethod": "PUE",
    "use": "G03",
    "customerId": "590ce6c56d04f840aa8438af",
    "items": [
      {
        "quantity": 1,
        "amount": 100,
        "productId": "60f1c3e-prod-8421"
      }
    ]
  }'
```

```typescript TypeScript SDK theme={null}
// Returns a Blob — render it in an <iframe>/<embed> or offer it as a download.
const pdf = await timbrix.invoices.previewPdf(
  "550e8400-e29b-41d4-a716-446655440000",
  {
    series: "A",
    folioNumber: "1",
    date: "2026-07-30T15:50:00",
    paymentForm: "01",
    paymentMethod: "PUE",
    use: "G03",
    customerId: "590ce6c56d04f840aa8438af",
    items: [
      {
        quantity: 1,
        amount: 100,
        productId: "60f1c3e-prod-8421",
      },
    ],
  }
)
```

## Example Response

This endpoint does not return a JSON body — it returns the generated PDF file directly in the response body with:

| Header                | Value                                                   |
| --------------------- | ------------------------------------------------------- |
| `Content-Type`        | `application/pdf`                                       |
| `Content-Disposition` | `inline; filename="preview-<series>-<folioNumber>.pdf"` |

## Common Errors

### 400 Bad Request

Invalid or incomplete invoice payload — identical validation rules to [Create Invoice](/api-reference/invoices/create#400-bad-request): an issuing organization without complete fiscal data, sending both/neither `customer` and `customerId`, sending both/neither `productId` and the inline concept fields on an item, or a customer whose RFC/régimen/uso CFDI combination fails SAT catalog validation.

```json theme={null}
{
  "statusCode": 400,
  "message": "La organización no tiene datos fiscales completos (RFC, razón social, régimen fiscal y código postal). Complétalos en PUT /organizations/:organizationId/legal antes de generar una vista previa.",
  "error": "BAD_REQUEST"
}
```

### 401 Unauthorized

Missing or invalid Bearer token / API key.

### 403 Forbidden

The authenticated user is not a member of `organizationId`, the API key does not have the `write:invoices` scope, or the API key belongs to a different organization than the one in the URL.

### 404 Not Found

`customerId` does not exist, or (for `type: "E"`) `relatedInvoiceUuid` does not match any invoice — in either case, belonging to a different organization than `organizationId` counts as not found.


## OpenAPI

````yaml POST /organizations/{organizationId}/invoices/preview/pdf
openapi: 3.1.0
info:
  title: Timbrix API
  description: >-
    REST API with OAuth2 server for managing organizations, members, and
    webhooks
  version: '1.0'
  contact: {}
servers:
  - url: https://api.timbrix.mx
    description: Production
security: []
tags:
  - name: organizations
    description: Organization management endpoints
  - name: oauth
    description: OAuth2 authentication and authorization
  - name: webhooks
    description: Webhook configuration and delivery
  - name: users
    description: User information endpoints
  - name: api-keys
    description: API Keys management and validation
  - name: invoices
    description: CFDI 4.0 invoice creation, listing, and cancellation
paths:
  /organizations/{organizationId}/invoices/preview/pdf:
    post:
      tags:
        - invoices
      summary: Preview a CFDI 4.0 invoice as an unstamped PDF
      description: >-
        Accepts the exact same request body as `POST
        /organizations/{organizationId}/invoices`, runs the exact same
        catalog/CFDI 4.0 validations, but never timbra (no PAC call) and never
        persists anything — no invoice, no cuota consumida, no idempotencyKey
        handling. Returns a PDF clearly marked as 'VISTA PREVIA — NO VÁLIDO
        FISCALMENTE' so it can never be confused with a real representación
        impresa.
      operationId: InvoicesController_previewPdf
      parameters:
        - name: organizationId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInvoiceDto'
      responses:
        '200':
          description: PDF de vista previa del CFDI
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        '400':
          description: Invalid invoice payload
        '403':
          description: API key does not belong to `organizationId`
        '404':
          description: customerId not found
      security:
        - apiKey: []
        - bearer: []
components:
  schemas:
    CreateInvoiceDto:
      type: object
      properties:
        type:
          type: string
          example: I
          enum:
            - I
            - E
            - T
          description: 'Ingreso, Egreso, or Traslado (default: I)'
        relatedInvoiceUuid:
          type: string
          example: d3bfbc57-44af-4390-a064-f0afab85e5df
          description: >-
            Required when `type` is `E` (Egreso/nota de crédito) — UUID fiscal
            of the original Ingreso CFDI it credits. Must belong to this
            organization and be a vigente Ingreso.
        series:
          type: string
          example: A
        folioNumber:
          type: string
          example: '1'
        date:
          type: string
          example: '2026-07-30T22:50:00'
        paymentForm:
          type: string
          example: '01'
          description: >-
            SAT forma de pago catalog code — required unless `type` is `T`
            (Traslado)
        paymentMethod:
          type: string
          example: PUE
          enum:
            - PUE
            - PPD
          description: 'Default: PUE'
        currency:
          type: string
          example: MXN
          description: 'Default: MXN'
        exchange:
          type: number
          example: 1
          description: 'Default: 1'
        export:
          type: string
          example: '01'
          description: 'SAT clave de exportación catalog code — default: 01'
        use:
          type: string
          example: G03
          description: SAT uso CFDI catalog code
        customer:
          $ref: '#/components/schemas/InvoiceCustomerDto'
        customerId:
          type: string
          description: Existing customer ID — mutually exclusive with `customer`
        items:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        idempotencyKey:
          type: string
          description: >-
            Client-supplied key to safely retry this request without
            double-stamping. If an invoice was already created for this
            organization with the same key, that invoice is returned instead of
            stamping again.
          example: order-8421-attempt-1
      required:
        - series
        - folioNumber
        - date
        - use
        - items
    InvoiceCustomerDto:
      type: object
      properties:
        legalName:
          type: string
          example: ESCUELA KEMPER URGATE SA DE CV
        taxId:
          type: string
          example: EKU9003173C9
        taxSystem:
          type: string
          example: '601'
          description: >-
            SAT régimen fiscal code — required unless the customer is público en
            general
        zip:
          type: string
          example: '45079'
      required:
        - legalName
        - taxId
    InvoiceItemDto:
      type: object
      properties:
        quantity:
          type: number
          example: 1
        productId:
          type: string
          description: >-
            Existing product/service ID — mutually exclusive with
            `productKey`/`unitKey`/`description`/`unitPrice` (inline concept
            data)
        description:
          type: string
          example: Servicio de consultoría
          description: Required unless `productId` is provided
        unitPrice:
          type: number
          example: 100
          description: Required unless `productId` is provided
        amount:
          type: number
          example: 100
        productKey:
          type: string
          example: '84111506'
          description: Required unless `productId` is provided
        unitKey:
          type: string
          example: E48
          description: Required unless `productId` is provided
        unit:
          type: string
          example: E48
        taxObject:
          type: string
          example: '02'
        taxes:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceTaxDto'
      required:
        - quantity
        - amount
    InvoiceTaxDto:
      type: object
      properties:
        type:
          type: string
          example: '002'
        factorType:
          type: string
          example: Tasa
        rate:
          type: string
          example: '0.160000'
        base:
          type: number
          example: 100
        amount:
          type: number
          example: 16
        withholding:
          type: boolean
          description: >-
            true = retención (Impuestos.Retenciones), false/omitted = traslado
            (Impuestos.Traslados)
          example: false
      required:
        - type
        - factorType
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'API Key for authentication (format: sk_...)'
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http

````