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

# Create credit notes

> Create a credit note that cancels or decreases an invoice, and send it through Peppol.

## Overview

A [credit note](/glossary#credit-note) decreases or cancels an invoice that you issued. Typical causes are:

* **Refund** - the customer returns goods or cancels a service.
* **Correction** - the invoice had a wrong price, quantity or amount.
* **Discount after the invoice** - you give a price adjustment for an invoice that is already sent.
* **Cancellation** - the invoice was issued in error.

A credit note uses the same endpoints, the same JSON fields and the same UBL BIS Billing 3.0 rules as an invoice. If you did not send an invoice before, read [Create e-invoices](/guides/creating-invoices) first.

For a credit note that your company issues as the buyer, see [Self-billing credit notes](/guides/self-billing#self-billing-credit-notes).

## Differences from an invoice

| Field | Credit note | Invoice |
| - | - | - |
| `document_type` | `"CREDIT_NOTE"` | `"INVOICE"` (default) |
| `invoice_id` | The credit note number, for example `CN-2026-001` | The invoice number |
| `note` | Recommended: the number of the original invoice and the reason for the credit | Optional |
| `items` and totals | The credited quantities and amounts, as positive values | The invoiced quantities and amounts |

<Note>
  The JSON document has no field for the number of the original invoice. Write the number of the original invoice in `note`. The `purchase_order` field keeps its meaning: it is the order number of the customer, and the API writes it to the order reference and the buyer reference of the UBL document.
</Note>

## Example credit note

The original invoice `INV-2026-001` has 10 units at €100.00. The customer returns 2 units. The credit note is for €242.00 (2 × €100.00 plus 21% VAT).

```json Credit note theme={null}
{
  "document_type": "CREDIT_NOTE",
  "invoice_id": "CN-2026-001",
  "invoice_date": "2026-10-15",
  "due_date": "2026-11-14",
  "currency": "EUR",
  "purchase_order": "PO-12345",
  "note": "Credit note for invoice INV-2026-001: 2 units returned",
  "vendor_name": "E-INVOICE BV",
  "vendor_tax_id": "BE1018265814",
  "vendor_address": "Brusselsesteenweg 119/A, 1980 Zemst, BE",
  "vendor_email": "billing@e-invoice.be",
  "customer_name": "OpenPeppol VZW",
  "customer_tax_id": "BE0848934496",
  "customer_address": "Robert Schumanplein 6 bus 5, 1040 Brussel, BE",
  "items": [
    {
      "description": "Professional services (credit)",
      "quantity": 2,
      "unit": "C62",
      "unit_price": 100.00,
      "amount": 200.00,
      "tax_rate": "21.00"
    }
  ],
  "subtotal": 200.00,
  "total_tax": 42.00,
  "invoice_total": 242.00,
  "amount_due": 242.00
}
```

This credit note has positive amounts. Replace the vendor fields with the data of your company. The API rejects a document if the Peppol ID of the vendor is not one of the `peppol_ids` of your company.

Save this payload as `credit-note.json`. The code samples on this page read that file.

## Create and send a credit note

<Note>
  Validation is not a separate mandatory call. `POST /api/documents/` rejects a payload that does not pass the same rules. Use `POST /api/validate/json` while you develop, because it returns all rule failures and the generated UBL.
</Note>

To validate the credit note, send the same body to `POST /api/validate/json`. See [Validation during development](/guides/validation).

<Note>
  Develop and test with a sandbox company. A sandbox company runs in test mode: the API sends each document as UBL XML to the contact email address of the company, and nothing goes to the Peppol network. The API host and the endpoints are the same as for a production company. See [Test mode and sandbox companies](/environments).
</Note>

<Steps>
  <Step title="Create the credit note">
    Send the payload to `POST /api/documents/`.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.e-invoice.be/api/documents/" \
        -H "Authorization: Bearer $E_INVOICE_API_KEY" \
        -H "Content-Type: application/json" \
        -d @credit-note.json
      ```

      ```javascript Node.js theme={null}
      import { readFile } from "node:fs/promises";

      const creditNote = await readFile("credit-note.json", "utf8");

      const response = await fetch("https://api.e-invoice.be/api/documents/", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.E_INVOICE_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: creditNote,
      });

      const result = await response.json();
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${JSON.stringify(result)}`);
      }
      console.log(result.id, result.state);
      ```

      ```python Python theme={null}
      import json
      import os

      import requests

      with open("credit-note.json", encoding="utf-8") as file:
          credit_note = json.load(file)

      response = requests.post(
          "https://api.e-invoice.be/api/documents/",
          headers={"Authorization": f"Bearer {os.environ['E_INVOICE_API_KEY']}"},
          json=credit_note,
          timeout=30,
      )
      if not response.ok:
          raise SystemExit(f"HTTP {response.status_code}: {response.text}")
      result = response.json()
      print(result["id"], result["state"])
      ```

      ```php PHP theme={null}
      <?php
      $creditNote = file_get_contents("credit-note.json");

      $ch = curl_init("https://api.e-invoice.be/api/documents/");
      curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
          "Authorization: Bearer " . getenv("E_INVOICE_API_KEY"),
          "Content-Type: application/json",
        ],
        CURLOPT_POSTFIELDS => $creditNote,
      ]);

      $body = curl_exec($ch);
      $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      if ($status !== 201) {
        throw new RuntimeException("HTTP $status: $body");
      }
      $result = json_decode($body, true);
      echo $result["id"] . " " . $result["state"] . PHP_EOL;
      ```

      ```csharp C# theme={null}
      using System.Net.Http.Headers;
      using System.Text;
      using System.Text.Json;

      var creditNote = await File.ReadAllTextAsync("credit-note.json");

      using var client = new HttpClient();
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
          "Bearer", Environment.GetEnvironmentVariable("E_INVOICE_API_KEY"));

      var response = await client.PostAsync(
          "https://api.e-invoice.be/api/documents/",
          new StringContent(creditNote, Encoding.UTF8, "application/json"));

      var body = await response.Content.ReadAsStringAsync();
      if (!response.IsSuccessStatusCode)
      {
          throw new Exception($"HTTP {(int)response.StatusCode}: {body}");
      }

      using var result = JsonDocument.Parse(body);
      Console.WriteLine(
          $"{result.RootElement.GetProperty("id")} {result.RootElement.GetProperty("state")}");
      ```
    </CodeGroup>

    The API returns `201` and the document in the `DRAFT` state. The response has all fields of the document. This example shows a selection. Amounts in the response are strings.

    ```json Response (201) theme={null}
    {
      "id": "doc-1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
      "created_at": "2026-10-15T09:30:00Z",
      "document_type": "CREDIT_NOTE",
      "state": "DRAFT",
      "direction": "OUTBOUND",
      "invoice_id": "CN-2026-001",
      "invoice_date": "2026-10-15",
      "due_date": "2026-11-14",
      "currency": "EUR",
      "vendor_name": "E-INVOICE BV",
      "vendor_tax_id": "BE1018265814",
      "customer_name": "OpenPeppol VZW",
      "customer_tax_id": "BE0848934496",
      "subtotal": "200.00",
      "total_tax": "42.00",
      "invoice_total": "242.00",
      "amount_due": "242.00"
    }
    ```

    Keep the `id`. You use it in the next step.
  </Step>

  <Step title="Send the credit note">
    Call `POST /api/documents/{document_id}/send` with the `id` from the create response. The call is the same as for an invoice. Replace the sender Peppol ID in the query parameters with the Peppol ID of your company.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.e-invoice.be/api/documents/$DOCUMENT_ID/send?sender_peppol_scheme=0208&sender_peppol_id=1018265814&receiver_peppol_scheme=0208&receiver_peppol_id=0848934496" \
        -H "Authorization: Bearer $E_INVOICE_API_KEY"
      ```

      ```javascript Node.js theme={null}
      const documentId = process.env.DOCUMENT_ID; // the "id" from the create response

      const query = new URLSearchParams({
        sender_peppol_scheme: "0208",
        sender_peppol_id: "1018265814",
        receiver_peppol_scheme: "0208",
        receiver_peppol_id: "0848934496",
      });

      const response = await fetch(
        `https://api.e-invoice.be/api/documents/${documentId}/send?${query}`,
        {
          method: "POST",
          headers: { Authorization: `Bearer ${process.env.E_INVOICE_API_KEY}` },
        },
      );

      const result = await response.json();
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${JSON.stringify(result)}`);
      }
      console.log(result.state);
      ```

      ```python Python theme={null}
      import os

      import requests

      document_id = os.environ["DOCUMENT_ID"]  # the "id" from the create response

      response = requests.post(
          f"https://api.e-invoice.be/api/documents/{document_id}/send",
          headers={"Authorization": f"Bearer {os.environ['E_INVOICE_API_KEY']}"},
          params={
              "sender_peppol_scheme": "0208",
              "sender_peppol_id": "1018265814",
              "receiver_peppol_scheme": "0208",
              "receiver_peppol_id": "0848934496",
          },
          timeout=30,
      )
      if not response.ok:
          raise SystemExit(f"HTTP {response.status_code}: {response.text}")
      print(response.json()["state"])
      ```

      ```php PHP theme={null}
      <?php
      $documentId = getenv("DOCUMENT_ID"); // the "id" from the create response

      $query = http_build_query([
          "sender_peppol_scheme" => "0208",
          "sender_peppol_id" => "1018265814",
          "receiver_peppol_scheme" => "0208",
          "receiver_peppol_id" => "0848934496",
      ]);

      $ch = curl_init("https://api.e-invoice.be/api/documents/$documentId/send?$query");
      curl_setopt_array($ch, [
          CURLOPT_POST => true,
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_HTTPHEADER => [
              "Authorization: Bearer " . getenv("E_INVOICE_API_KEY"),
          ],
      ]);

      $body = curl_exec($ch);
      $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      if ($status >= 400) {
          throw new RuntimeException("HTTP $status: $body");
      }
      echo json_decode($body, true)["state"], PHP_EOL;
      ```

      ```csharp C# theme={null}
      using System.Net.Http.Headers;

      var documentId = Environment.GetEnvironmentVariable("DOCUMENT_ID"); // the "id" from the create response

      using var client = new HttpClient { BaseAddress = new Uri("https://api.e-invoice.be") };
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
          "Bearer", Environment.GetEnvironmentVariable("E_INVOICE_API_KEY"));

      var query = "sender_peppol_scheme=0208&sender_peppol_id=1018265814&receiver_peppol_scheme=0208&receiver_peppol_id=0848934496";

      var response = await client.PostAsync($"/api/documents/{documentId}/send?{query}", null);

      var body = await response.Content.ReadAsStringAsync();
      if (!response.IsSuccessStatusCode)
      {
          throw new HttpRequestException($"HTTP {(int)response.StatusCode}: {body}");
      }
      Console.WriteLine(body);
      ```
    </CodeGroup>

    The API returns `200` and the document. The state is no longer `DRAFT`.

    ```json Response (200) theme={null}
    {
      "id": "doc-1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
      "created_at": "2026-10-15T09:30:00Z",
      "document_type": "CREDIT_NOTE",
      "state": "TRANSIT",
      "direction": "OUTBOUND",
      "invoice_id": "CN-2026-001",
      "invoice_total": "242.00"
    }
    ```
  </Step>

  <Step title="Monitor the delivery">
    The document goes to `SENT` or to `FAILED`. Use [webhooks](/essentials/webhooks) (`document.sent` and `document.sent.failed`) or read the timeline of the document. See [Document lifecycle and delivery tracking](/guides/document-lifecycle).
  </Step>
</Steps>

## Document states

A credit note has the same states as an invoice.

| State | Meaning |
| - | - |
| `DRAFT` | The document exists but is not sent. `POST /api/documents/` always creates a document in this state. |
| `TRANSIT` | The send request is accepted and the transmission is in progress. |
| `SENT` | The transmission is complete. |
| `FAILED` | The transmission failed. You can send the document again. |
| `RECEIVED` | The document came in from another Peppol participant. |

You can send a document only when it is in the `DRAFT` or `FAILED` state. For the transitions, the retry behaviour and the webhook events of each state, see [Document lifecycle and delivery tracking](/guides/document-lifecycle).

## Variants of the example

Each block below shows only the fields that are different from the [example credit note](#example-credit-note). All other fields stay the same. Give each credit note its own `invoice_id`.

### Full credit

To cancel the invoice fully, include each line of the original invoice with the same quantity and the same price.

```json theme={null}
{
  "note": "Credit note for invoice INV-2026-001: invoice issued in error",
  "items": [
    {
      "description": "Professional services (credit)",
      "quantity": 10,
      "unit": "C62",
      "unit_price": 100.00,
      "amount": 1000.00,
      "tax_rate": "21.00"
    }
  ],
  "subtotal": 1000.00,
  "total_tax": 210.00,
  "invoice_total": 1210.00,
  "amount_due": 1210.00
}
```

### Price correction

To correct a price, credit the difference. In this example the invoice price was €10.00 too high for each unit. The credit is €121.00 (10 × €10.00 plus 21% VAT).

```json theme={null}
{
  "note": "Credit note for invoice INV-2026-001: price correction of 10.00 EUR for each unit",
  "items": [
    {
      "description": "Professional services (price adjustment)",
      "quantity": 10,
      "unit": "C62",
      "unit_price": 10.00,
      "amount": 100.00,
      "tax_rate": "21.00"
    }
  ],
  "subtotal": 100.00,
  "total_tax": 21.00,
  "invoice_total": 121.00,
  "amount_due": 121.00
}
```

### More than one line

In this example the customer returns 5 units of the first product and 3 units of the second product. The credit is €786.50.

```json theme={null}
{
  "note": "Credit note for invoice INV-2026-001: return of two products",
  "items": [
    {
      "description": "Product A (returned)",
      "quantity": 5,
      "unit": "C62",
      "unit_price": 100.00,
      "amount": 500.00,
      "tax_rate": "21.00"
    },
    {
      "description": "Product B (damaged)",
      "quantity": 3,
      "unit": "C62",
      "unit_price": 50.00,
      "amount": 150.00,
      "tax_rate": "21.00"
    }
  ],
  "subtotal": 650.00,
  "total_tax": 136.50,
  "invoice_total": 786.50,
  "amount_due": 786.50
}
```

### Service cancellation

In this example you credit one day of a service that the customer did not use.

```json theme={null}
{
  "note": "Credit note for invoice INV-2026-001: one consulting day not used",
  "items": [
    {
      "description": "Consulting services (day not used)",
      "quantity": 1,
      "unit": "DAY",
      "unit_price": 500.00,
      "amount": 500.00,
      "tax_rate": "21.00"
    }
  ],
  "subtotal": 500.00,
  "total_tax": 105.00,
  "invoice_total": 605.00,
  "amount_due": 605.00
}
```

### Refund details

To tell the customer how you pay the refund, add `payment_term` and `payment_details`.

```json theme={null}
{
  "payment_term": "Refund within 14 days",
  "payment_details": [
    {
      "iban": "BE68539007547034",
      "swift": "GEBABEBB",
      "payment_reference": "CN-2026-001"
    }
  ]
}
```

### Allowances and charges

A credit note accepts the same `allowances` and `charges` as an invoice, at document level and at line level. See [Advanced invoicing](/guides/advanced-invoicing) for the fields and [Invoice totals and calculations](/guides/invoice-totals) for the calculation of the totals.

## Good practice

<AccordionGroup>
  <Accordion title="Name the original invoice">
    Write the number of the original invoice and the reason for the credit in `note`. The customer can then match the credit note with the invoice.

    ```json theme={null}
    {
      "note": "Credit note for invoice INV-2026-001: goods returned damaged"
    }
    ```
  </Accordion>

  <Accordion title="Use the descriptions of the original invoice">
    If you credit specific lines of the original invoice, use the same descriptions and unit prices. Add the reason to the description.

    ```json theme={null}
    {
      "description": "Professional services (returned)",
      "quantity": 2,
      "unit": "C62",
      "unit_price": 100.00,
      "amount": 200.00,
      "tax_rate": "21.00"
    }
    ```
  </Accordion>

  <Accordion title="Use the tax rates of the original invoice">
    Use the tax rates and tax categories of the original invoice, also if the rates changed after the invoice date.
  </Accordion>

  <Accordion title="Use positive amounts">
    Give the credited quantities and amounts as positive values. The document type `CREDIT_NOTE` tells the receiver that the document decreases the amount due.

    ```json theme={null}
    {
      "quantity": 2,
      "unit_price": 100.00,
      "amount": 200.00
    }
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

### The API rejects the credit note

`POST /api/documents/` returns `406` if the payload does not pass the validation rules or if the Peppol ID of the vendor is not a Peppol ID of your company. It returns `422` if a field has a wrong type or format. No document is created. Send the body to `POST /api/validate/json` to see the rule failures, and see [Create document errors](/guides/errors#create-document-errors-406).

### The total of the credit note is more than the total of the invoice

The API does not compare a credit note with the original invoice. A higher total can be correct, for example when you also credit return shipping costs. Make sure that your accounting system and that of the customer accept this.

### The customer did not receive the credit note

1. Make sure that the Peppol ID of the customer is correct. See [Look up Peppol participants](/guides/lookup-participants).
2. Get the state of the document with `GET /api/documents/{document_id}`.
3. Get the delivery history with `GET /api/documents/{document_id}/timeline`. See [Document lifecycle and delivery tracking](/guides/document-lifecycle).
4. Examine the webhook events for the document.

For all status codes and error formats, see [Errors and troubleshooting](/guides/errors).

## Next Steps

<CardGroup cols={2}>
  <Card title="Document lifecycle and delivery tracking" icon="arrows-rotate" href="/guides/document-lifecycle">
    Follow the states and the delivery of a credit note
  </Card>

  <Card title="Self-billing and debit notes" icon="arrow-right-arrow-left" href="/guides/self-billing">
    Issue credit notes as the buyer, and debit notes
  </Card>

  <Card title="Advanced invoicing" icon="percent" href="/guides/advanced-invoicing">
    Add allowances and charges
  </Card>

  <Card title="Errors and troubleshooting" icon="triangle-exclamation" href="/guides/errors">
    Find the cause of a rejected or failed document
  </Card>
</CardGroup>


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