# What invoice gets generated

How BeeL. decides between standard and simplified, how it picks a rectification code (R1–R5), and which series is used.

Every Stripe event that produces an invoice goes through the same few decisions. The result is one of: a **standard** invoice (`type: STANDARD`), a **simplified** invoice (`type: SIMPLIFIED`), or a **corrective** (`type: CORRECTIVE` with a `rectification_code` R1–R5).

If you're new to which AEAT codes map to which API values, [Invoice types](/verifactu/invoice-types) is the canonical translation page.

## Forward invoices: STANDARD vs SIMPLIFIED

When BeeL. receives a payment success event (`payment_intent.succeeded`, `invoice.paid`, etc.), it creates one invoice. The type depends on one thing: whether the customer has **full fiscal data**. A buyer with a NIF (or foreign identifier) and a complete address always gets a standard invoice, at any amount.

```text
                    Stripe payment received
                             │
                             ▼
           Does the customer have full fiscal data
                     (NIF + address)?
             │                                │
            Yes                               No
             │                                │
             ▼                                ▼
         STANDARD                    Amount ≤ 3 000 €?
      (any amount)                    │             │
                                     Yes            No
                                      │             │
                                      ▼             ▼
                                 SIMPLIFIED     Draft saved —
                                 (without the   issuer notified
                                  NIF)
```

### Standard whenever the buyer is identified

A simplified invoice never identifies its recipient: it keeps the customer's name, email and address, not the NIF or `alternative_id`, and it is not linked to the customer. A buyer who supplies a NIF and address is therefore always invoiced as `STANDARD`, whatever the amount, so the invoice carries the data they provided. Without full fiscal data, a charge up to 3,000 € gives a `SIMPLIFIED` invoice — missing data never forces a standard one — and a larger one is saved as a draft (below).

<Callout type="info">
  **The simplified threshold no longer applies.** Earlier, each connection compared the charge against `simplificada_threshold` (default 400 €) and issued a simplified invoice below it even when the buyer had a NIF. The field is deprecated: the API still accepts and returns it, but it has no effect on the invoice type. See [Connection settings](/stripe/connection-settings#simplified-threshold-deprecated).
</Callout>

### What "fiscal data" means

BeeL. checks the resolved customer (after [customer mapping](/stripe/customer-mappings)) for:

- `nif` (Spanish) **or** `alternative_id` (foreign), AND
- A complete address

### Buyers outside Spain

For a buyer outside Spain, BeeL. takes the identifier from the Stripe tax ID when there is one, and otherwise derives one from the payment. What completes the recipient is therefore the **address**: street, city, postal code and country. A checkout that only collects country and postal code gives an incomplete address.

That matters when the sale cannot be documented on a simplified invoice: intra-EU supplies of goods (`EXENTA_ART_25`) and operations not subject by place of supply (`NO_SUJETA_LOCALIZACION`) — see [Simplified vs standard](/verifactu/simplified-vs-standard#on-the-f2-path) and [Data conversion](/stripe/data-conversion#verifactu-classification) for which buyers get them. With an incomplete address the charge waits in **Needs attention** as `SIMPLIFIED_INVOICE_NOT_ALLOWED`. [Generate a draft](/payment-events/generateCompanyPaymentEventDraft) to get a standard invoice with the recipient left for you to complete, then issue it. Retrying does not help: it reads the same Stripe payment again. To invoice these charges on their own, set the billing address collection of your Checkout to required.

A sale to a buyer outside Spain that a simplified invoice can document, such as an EU consumer under the OSS regime, is still issued as simplified.

### Charges that cannot be invoiced automatically

A charge that cannot be invoiced on its own is not dropped and does not wait as a skipped event: BeeL. saves it as a **draft** and emails the issuer (Live connections only), and the draft appears in **Needs attention** (*Necesita atención* in the dashboard). The draft is `STANDARD` with the recipient left for you to complete. Two cases do this:

- **Above 3,000 € without fiscal data.** A simplified invoice is not allowed above that amount, so a charge whose customer has no NIF or address is saved as a draft. Fill in the NIF (or foreign identifier) and address, then issue it — issuing it before that is rejected and does not consume a number.
- **NIF rejected by the AEAT.** When the AEAT definitively rejects the buyer's NIF, the invoice is not issued and is never downgraded to a simplified one. Correct the NIF or the name, then issue the draft.

Retrying the event does not help, because a retry reads the recipient from the same Stripe payment again. To avoid the case for future charges, collect tax IDs and the billing address in Stripe.

## Forward invoices: numbering

BeeL. resolves the invoice **series** at issuance time:

1. Look up your **default series** for the resolved document type (standard or simplified)
2. Allocate the next number on that series

If you delete the default for standard or simplified invoices, the next Stripe webhook that needs it fails until you set a new default. One exception: without a default standard series, a charge up to 3,000 € whose lines a simplified invoice can carry is issued as `SIMPLIFIED` in your simplified series — without the customer's NIF, like any F2.

<Callout type="warn">
  **You need at least two default series in each environment**: one for `STANDARD` invoices and one for `SIMPLIFIED`. Plus one for `CORRECTIVE` if you process refunds.
</Callout>

## Corrective invoices: refunds and credit notes

Refunds and credit notes produce a corrective in BeeL.

| Stripe event | BeeL `rectification_type` | `rectification_code` source |
|---|---|---|
| `refund.created` / `refund.updated` (once the refund has succeeded) | `TOTAL` if this refund matches the full payment, `PARTIAL` otherwise | Derived from `refund.reason` |
| `credit_note.created` | `TOTAL` if this note credits the full payment, `PARTIAL` otherwise | Derived from `credit_note.reason` |

`rectification_code` is an enum on the API request (`R1`/`R2`/`R3`/`R4`/`R5`) — the same names AEAT uses. See [Corrective invoices](/verifactu/corrective-invoices) for the canonical R1–R5 reference.

### Mapping Stripe's reason to R1–R5

The mapping is **fixed** — not configurable per connection. It depends on **two inputs**: the original invoice's `type` and the Stripe reason value.

**Rule 1 — Original was `SIMPLIFIED`:**

| Condition | BeeL `rectification_code` |
|---|---|
| Any refund or credit note on a `SIMPLIFIED` | **`R5`** (always) |

`R5` is the only valid corrective code for a simplified original, per VeriFactu spec (Art. 80.1–80.2 LIVA). The Stripe reason value is ignored on simplified originals.

**Rule 2 — Original was `STANDARD` (or a previous corrective):**

| Stripe `reason` value | BeeL `rectification_code` |
|---|---|
| `duplicate` | **`R4`** (resto de causas — duplicate charge is a non-error correction) |
| `fraudulent` | **`R4`** (resto de causas) |
| `requested_by_customer` | **`R1`** (most common — customer asked for the refund) |
| `order_change` | `R1` |
| `product_unsatisfactory` | `R1` |
| `expired_uncaptured_charge` | `R1` |
| Anything else, blank, or `null` | `R1` (default fallback) |

`R2` and `R3` are not auto-emitted from Stripe events — they need explicit fiscal context (insolvency, bad debt) that Stripe doesn't model. Issue those manually via the [corrective invoice endpoint](/invoices/createCompanyCorrectiveInvoice) when applicable.

### Multiple refunds on the same payment

A single Stripe charge can receive **multiple partial refunds** over time. Each refund produces its own corrective in BeeL:

```text
Original payment:    121 €  →  Invoice INV-2026/00042  (type: STANDARD, ACCEPTED)

Refund #1 (re_abc):  -40 €  →  RECTIF-2026/00012  (type: CORRECTIVE, rectification_code: R1, PARTIAL)
Refund #2 (re_def):  -30 €  →  RECTIF-2026/00013  (type: CORRECTIVE, rectification_code: R1, PARTIAL)
Refund #3 (re_ghi):  -51 €  →  RECTIF-2026/00014  (type: CORRECTIVE, rectification_code: R1, PARTIAL — sums to full refund)
```

Each refund is deduplicated by its own Stripe refund ID (`re_…`), not by the payment intent. So multiple refunds on the same payment cannot collide.

If a **single refund equals the full payment amount**, BeeL. emits a `TOTAL` corrective (the original moves to `VOIDED`). If a sequence of partial refunds eventually sums to the full amount, each one is still `PARTIAL` — BeeL. doesn't retro-promote the chain to `TOTAL`.

### The corrective is for exactly what was refunded

A corrective's total is always the exact amount Stripe returned, to the cent. BeeL. scales the original's tax-inclusive amounts down to the refund, so base plus tax adds up to the refunded amount: refunding 21.00 € of a 121.00 € invoice declares −21.00 €, never −21.01 €. When the split leaves a cent over, it goes to the tax of the line with the most tax, never to an exempt line.

### Credit notes (Stripe Billing)

`credit_note.created` is Stripe Billing's native primitive for crediting a customer (subscription downgrades, prorations, manual credits). Some specifics:

- The mapping table above applies the same way — `credit_note.reason` runs through the same R1–R4 / R5 rules
- With a coupon on the Stripe Invoice, the corrective credits what the note actually credits — the discounted amount, not the gross line
- A credit note against a Stripe Invoice that was never paid produces no corrective, because no BeeL. invoice was ever issued for it
- Voiding a credit note in Stripe does not undo the corrective it produced; see [Supported events](/stripe/supported-events#events-that-raise-a-review-item)
- Each credit note is deduplicated by its Stripe credit note ID (`cn_…`)

### Finding the original invoice

For a refund or credit note, BeeL. needs the original BeeL. invoice to link the corrective to:

1. Identify the Stripe charge the refund or credit note belongs to
2. Look up the BeeL. invoice issued for that charge
3. Build the corrective referencing it

If the original isn't found, the event is retried later. Possible causes:

- The refund arrived **before** the original payment webhook (out-of-order delivery) — BeeL. retries on a backoff
- The original was issued outside BeeL (legacy data, ad-hoc) — manual handling required
- The connection that processed the original was deleted — relink and retry the event

### Multi-currency note

Stripe refunds and credit notes can in principle be denominated in any currency. BeeL. only processes EUR — non-EUR refunds are skipped the same way non-EUR payments are.

## What can't be generated

| Scenario | Outcome | Why |
|---|---|---|
| Partial refund on a `SIMPLIFIED` original | Corrective with `rectification_code: R5`, `rectification_type: PARTIAL` | Allowed; `SIMPLIFIED`'s only valid code is `R5` |
| Refund larger than the original | Skipped | Likely data error in Stripe; investigate |
| Refund on an already-voided invoice | Skipped | `TOTAL` correctives are terminal |
| Currency ≠ EUR | Skipped | BeeL. only emits EUR-denominated invoices |
| Amount = 0 € | Skipped | No invoice generated for free transactions |

The full skip list is in [Edge cases and limits](/stripe/edge-cases-and-limits).

## Finding generated invoices

Invoices BeeL. generates from Stripe carry **system metadata** you can filter the invoice list by — most usefully `external_customer_id` (the Stripe `cus_…`) and `external_payment_id` (the PaymentIntent / Charge / Stripe Invoice id). To pull a customer's invoice history in one call:

```bash
curl -g "https://app.beel.es/api/v1/companies/{company_id}/invoices?metadata[external_customer_id]=cus_ULGk8bzIr88aag" \
  -H "Authorization: Bearer $BEEL_API_KEY"
```

The `-g` flag tells `curl` not to treat `[ ]` as glob characters; SDKs encode them automatically. `external_customer_id` is present whenever the payment carried a customer — flows with no customer (Terminal, payment links without customer collection; see [When the recipient ends up incomplete](/stripe/customer-mappings#when-the-recipient-ends-up-incomplete)) won't have it. The complete list of system keys, query rules and limits lives in [Filtering by metadata](/guides/filtering-by-metadata).

## Related

<Related>

- [Invoice types](/verifactu/invoice-types) — the canonical `type` ↔ AEAT (F1/F2/R*) mapping
- [Supported events](/stripe/supported-events) — which events produce an invoice
- [Data conversion](/stripe/data-conversion) — how line items, taxes and totals get mapped
- [Customer mappings](/stripe/customer-mappings) — how the recipient is resolved
- [Corrective invoices](/verifactu/corrective-invoices) — R1–R5 fundamentals
- [Filtering by metadata](/guides/filtering-by-metadata) — find generated invoices by Stripe customer or payment id

</Related>

---

Full OpenAPI spec: https://docs.beel.es/api/openapi