# OSS return validator (lines only; dispatch-country breakdown not implemented)

Source: https://veriport.io/docs/oss-return-file (published 2026-10-24)

Every quarter, a seller registered in the Union OSS declares, per member state of consumption and per rate, the taxable amount and the VAT, plus corrections of earlier quarters. The data is already in your shop or billing export; the work is grouping it, checking each rate against the right country, and catching the rows that would make the portal or an auditor stop. `POST /vat/oss/return` does that in one call and returns the lines, the totals and a file. It does not file the return: you key or import it on your member state of identification’s portal.

- Input: your export as CSV (any column order, headers in English, French or German, comma or semicolon, decimal comma or point) or JSON rows. One row per invoice line or per order.
- Checks per row: member state code, rate one the country applies according to the dated table (or a table category), VAT = net × rate within rounding, supply date inside the quarter, euro amounts, supply type allowed by the scheme. Every refusal names the row and the rule.
- Output: lines per member state × supply type × rate; corrections per earlier period and member state; totals and VAT payable; due date (last day of the following month); the generic CSV.
- Cost: 25 calls per accepted return, nothing when rows are refused. The free tier (100 calls a month) covers 4 returns a month; the 2,000-call pack covers 80.
- Send an Idempotency-Key header; a retry replays the stored answer for 24 hours and is not charged again.

## 1. Export the quarter

Export the quarter’s B2C sales to other member states from your shop, billing tool or payment provider. The columns that matter are the country of consumption, the rate (or a category), the net amount, the VAT amount, the supply date; optional: the supply type (`services` or `goods`), the currency (must be EUR) and, for credit notes of an earlier quarter, the period they correct. Headers are matched by name, so most exports work as they are.

```text
country;vat_rate;net;vat;invoice_date;supply_type;correction_of_period
DE;19;1 250,00;237,50;14/07/2026;goods;
DE;7;310,00;21,70;02/08/2026;goods;
FR;20;980,00;196,00;2026-09-21;services;
IT;22;-45,00;-9,90;2026-05-30;services;2026-Q2
```

## 2. Send it

As the raw CSV with `Content-Type: text/csv` and the period in the query string, or as JSON rows. `scheme` is `union` (default: EU sellers, and non-EU sellers of goods), `non_union` (services by sellers established outside the EU) or `import` (IOSS, monthly, period `2026-09`). Add `output=csv` to receive the file alone.

```bash
curl -X POST -H "Authorization: Bearer vp_live_YOUR_KEY" -H "Content-Type: text/csv" \
  --data-binary @sales-2026-Q3.csv -o oss-return-2026-Q3.csv \
  "https://veriport.io/api/v1/vat/oss/return?period=2026-Q3&scheme=union&output=csv"
```

```bash
curl -X POST -H "Authorization: Bearer vp_live_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"period":"2026-Q3","scheme":"union","rows":[{"country":"DE","rate":19,"net":1250,"vat":237.5,"date":"2026-07-14","supplyType":"goods"},{"country":"FR","category":"digital_services","net":980,"date":"2026-09-21"}]}' \
  "https://veriport.io/api/v1/vat/oss/return"
```

## 3. Read the answer

`lines[]` are the return’s rows: one per member state of consumption, supply type and rate, with the number of source rows, the net, the VAT you charged and `vatComputed` (net × rate) for the reconciliation. `corrections[]` group the rows marked `correctionOfPeriod` per earlier period and member state: the return carries them in their own section. `totals.vatPayable` is the quarter’s VAT plus corrections. `warnings[]` flag what passed but deserves a look (a former rate before a recorded change, a line whose rounding drifts more than per-row rounding).

```json
{
  "period": {
    "label": "2026-Q3",
    "kind": "quarter",
    "start": "2026-07-01",
    "end": "2026-09-30",
    "dueDate": "2026-10-31"
  },
  "lines": [
    {
      "country": "DE",
      "countryName": "Germany",
      "supplyType": "goods",
      "rateKind": "standard",
      "rate": 19,
      "rows": 1,
      "net": 1250,
      "vat": 237.5,
      "vatComputed": 237.5
    },
    {
      "country": "DE",
      "countryName": "Germany",
      "supplyType": "goods",
      "rateKind": "reduced",
      "rate": 7,
      "rows": 1,
      "net": 310,
      "vat": 21.7,
      "vatComputed": 21.7
    },
    {
      "country": "FR",
      "countryName": "France",
      "supplyType": "services",
      "rateKind": "standard",
      "rate": 20,
      "rows": 1,
      "net": 980,
      "vat": 196,
      "vatComputed": 196
    }
  ],
  "corrections": [
    {
      "period": "2026-Q2",
      "country": "IT",
      "countryName": "Italy",
      "rows": 1,
      "vat": -9.9,
      "net": -45
    }
  ],
  "totals": {
    "rows": 4,
    "countries": 2,
    "net": 2540,
    "vat": 455.2,
    "correctionsVat": -9.9,
    "vatPayable": 445.3
  }
}
```

## 4. Put it on the portal — what file you get, honestly

The return is filed on the portal of your member state of identification. Where that portal publishes a file-import specification we can fetch, the endpoint will return that portal’s file; on 2026-10-24 none of the first two could be produced, so you get a **clearly labelled generic CSV** (`files[0].portal: null`, filename ending `-generic.csv`) that doubles as the keying sheet: one line per member state, supply type and rate, corrections after. `portals[]` in every answer repeats what follows.

| Member state of identification | Portal | File returned | Why |
|---|---|---|---|
| FR | impots.gouv.fr — guichet unique TVA (espace professionnel) | Generic CSV | No public file-import specification for the French OSS return was found on 2026-10-24; the return is keyed in on the portal. Use the generic CSV as the keying sheet: one line per member state, supply type and rate. |
| DE | BZStOnline-Portal (Mein BOP) — Steuererklärung One-Stop-Shop, EU-Regelung, Import-Funktion | Generic CSV | The BZSt confirms a CSV import for the OSS return and publishes the general CSV rules (UTF-8, one separator, decimal point, a #v version line) openly, but the record layout (Datensatztabelle) only inside the import help of the logged-in form, which cannot be fetched without a BOP certificate. The generic CSV follows the public rules without the version line; map its columns once against the form’s Importhilfe. |

> The generic CSV is not a portal format. Germany: map its columns once to the form’s Importhilfe (visible after login) or key the lines in. France: key the lines in the guichet unique. The day a portal’s record layout becomes fetchable, a portal file is added next to the generic one and announced in the changelog.

## The checks, in the order a portal would stop

- **Country**: an EU member state code (Greece is `EL`; `GR` accepted). Non-EU destinations do not belong in an OSS return.
- **Rate**: one the member state applies according to the rates table (verified 2026-10-24, next review 2026-11-24): standard, reduced, super-reduced or parking. A category (`digital_services`, `ebooks`…) is turned into the country’s rate for it. A rate the country no longer applies is accepted with a warning only when the supply predates the last change the table records; otherwise refused.
- **VAT**: equals net × rate within half a cent plus 0.1 % (exports that round per line). Absent VAT is computed.
- **Date**: inside the quarter (or the month for IOSS); a correction’s date inside the period it corrects, which must be earlier.
- **Scheme and supply type**: IOSS is goods only; the non-Union scheme is services only; zero-rated or exempt supplies are refused (they are not declared through OSS).
- **Totals**: a member state whose quarter nets negative is refused: that is a correction of an earlier quarter and belongs in the corrections section.
- **Limits**: 50,000 rows or 4.5 MB per call; aggregate or split by month above that.

## What the endpoint does not do

It does not convert currencies (the regulation asks for the ECB rate of the last day of the period: convert before sending, and keep the rate you used), decide whether a supply is B2C or which rate category a product falls in, check the €10,000 threshold for you, or submit anything to a tax administration. It is arithmetic and validation on your data, not tax advice; the return remains yours.

## Questions

### Can I send a whole year?

No: one return is one quarter (OSS) or one month (IOSS), and rows dated outside it are refused unless they carry the period they correct. Send one call per period.

### Are my sales stored?

No. The rows are processed in memory to build the answer; neither the rows nor the file are stored or logged. Only the call count is recorded, as for any call.

### Why 25 calls?

A return is a quarter’s worth of grouping and checking, not a lookup. At 25 calls it costs $0.11 from the 2,000-call pack, and the free tier (100 calls a month) produces 4 a month. It validates lines; the dispatch-country breakdown some portals ask for is not implemented.

## Read next

- [Reference: OSS / IOSS return](https://veriport.io/docs/oss-return)
- [Which VAT rate for OSS: the consumption-country rule](https://veriport.io/guides/which-vat-rate-for-oss-consumption-country-rule)
- [Reference: EU VAT rates](https://veriport.io/docs/vat-rates)

## Sources

- Commission Implementing Regulation (EU) 2020/194 — the OSS/IOSS VAT return: content per member state of consumption, rate type, rate, taxable amount, VAT amount, corrections (Annex III) — https://eur-lex.europa.eu/eli/reg_impl/2020/194/oj (2026-10-24)
- One Stop Shop — guide to the VAT OSS: declare and pay, quarterly periods, corrections in a later return — https://vat-one-stop-shop.ec.europa.eu/one-stop-shop/declare-and-pay-oss_en (2026-10-24)
- VAT e-commerce rules: One Stop Shop (OSS) and Import One Stop Shop (IOSS) — https://vat-one-stop-shop.ec.europa.eu/ (2026-10-24)
- BZSt — One-Stop-Shop, EU-Regelung: elektronische Abgabe der Steuererklärung im BZStOnline-Portal, wahlweise mit Import-Funktion — https://www.bzst.de/DE/Unternehmen/Umsatzsteuer/One-Stop-Shop_EU/ElektronischeAbgabe/elektronischeabgabe_oss_node.html (2026-10-24)
- BZStOnline-Portal (Mein BOP) — Allgemeine Anleitung zur Erstellung von CSV-Dateien für die Importfunktion (UTF-8, one separator , or ;, decimal point, #v version line) — https://www.elster.de/bportal/helpGlobal?themaGlobal=allgemeine_csv-anleitung (2026-10-24)
- impots.gouv.fr — guichet unique TVA (OSS/IOSS): déclaration en ligne dans l’espace professionnel — https://www.impots.gouv.fr/professionnel/le-guichet-unique-tva-oss-ioss (2026-10-24)
- VAT rates applied in the Member States of the European Union (situation at 1 January 2025) and the Taxes in Europe Database (TEDB) — https://taxation-customs.ec.europa.eu/taxation/vat/vat-rates_en (2026-10-24)
