OSS / IOSS return

OSS return validator (lines only; dispatch-country breakdown not implemented): the output is the set of return lines per member state of consumption, supply type and rate, checked against the rates table, not a filable return. Implementing Regulation (EU) 2020/194 Annex III also requires goods to be split by member state of dispatch or fixed establishment; the row model carries no dispatch country, so a seller shipping from stock in several member states cannot file from this output (assessment 2026-10-28). Send the quarter's (OSS) or month's (IOSS) B2C sales as JSON rows or as a CSV export (Content-Type: text/csv, header row in English, French or German; or JSON {period, scheme, csv}). Each row names the member state of consumption, the rate (or a rates-table category), the net amount, optionally the VAT amount, the supply date and the supply type. The service aggregates per member state, supply type and rate; validates every row against the dated rates table (the rate must be one the member state applies; a rate changed inside the table's window is accepted with a warning when the supply predates the change), reconciles VAT with net × rate, checks the dates against the period, and nets credit notes; rows marked correctionOfPeriod become the corrections section. Returns the per-country summary and the upload file. On 2026-10-24 no national portal format could be fetched (the BZSt publishes its CSV record layout only inside the logged-in form; the DGFiP publishes none), so the file is a clearly labelled generic CSV and portals[] says so per member state. Up to 50000 rows or 4.5 MB. Add ?output=csv to receive the file itself instead of JSON. Send an Idempotency-Key header (1–128 characters, unique per request) and a retry after a dropped response replays the stored answer for 24 hours without a second charge (Idempotent-Replayed: true); the same key with a different body or query is refused with 409 idempotency_conflict.

About the return file

The lines follow the content of the OSS return set by Implementing Regulation (EU) 2020/194: per member state of consumption, rate type and rate, the taxable amount and the VAT, plus corrections of earlier periods per member state. Rates are checked against the dated table (verified 2026-10-24). No national portal publishes a fetchable import specification for the first two member states of identification (France, Germany) as of 2026-10-24, so the file is a labelled generic CSV; the walkthrough is on the "OSS return: one file per quarter" page. 25 calls per accepted return; a 422 costs nothing; send an Idempotency-Key header and a retry replays the stored answer for 24 hours without being charged again. The endpoint validates lines; the dispatch-country breakdown is not implemented.

POST/vat/oss/return

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

OSS return validator (lines only; dispatch-country breakdown not implemented): the output is the set of return lines per member state of consumption, supply type and rate, checked against the rates table, not a filable return. Implementing Regulation (EU) 2020/194 Annex III also requires goods to be split by member state of dispatch or fixed establishment; the row model carries no dispatch country, so a seller shipping from stock in several member states cannot file from this output (assessment 2026-10-28). Send the quarter's (OSS) or month's (IOSS) B2C sales as JSON rows or as a CSV export (Content-Type: text/csv, header row in English, French or German; or JSON {period, scheme, csv}). Each row names the member state of consumption, the rate (or a rates-table category), the net amount, optionally the VAT amount, the supply date and the supply type. The service aggregates per member state, supply type and rate; validates every row against the dated rates table (the rate must be one the member state applies; a rate changed inside the table's window is accepted with a warning when the supply predates the change), reconciles VAT with net × rate, checks the dates against the period, and nets credit notes; rows marked correctionOfPeriod become the corrections section. Returns the per-country summary and the upload file. On 2026-10-24 no national portal format could be fetched (the BZSt publishes its CSV record layout only inside the logged-in form; the DGFiP publishes none), so the file is a clearly labelled generic CSV and portals[] says so per member state. Up to 50000 rows or 4.5 MB. Add ?output=csv to receive the file itself instead of JSON. Send an Idempotency-Key header (1–128 characters, unique per request) and a retry after a dropped response replays the stored answer for 24 hours without a second charge (Idempotent-Replayed: true); the same key with a different body or query is refused with 409 idempotency_conflict.

Tiers
freecreditsplan
Cost
25 calls per accepted return (0 when the rows are refused with 422; 0 on an Idempotency-Key replay)

Parameters

NameInTypeDescription
outputquery"json" | "csv"json (default): summary, files and portal notes. csv: the generic CSV file alone, with Content-Disposition.Example: json
Idempotency-KeyheaderstringUnique per request (a UUID will do; ^[A-Za-z0-9_.:-]{1,128}$). A retry with the same key, query and body replays the stored answer for 24 hours (Idempotent-Replayed: true) instead of building and charging a second return; another body under the same key is 409.

Request body

Media types: application/json.

FieldTypeDescription
period*string2026-Q3 for OSS (quarterly), 2026-09 for IOSS (monthly).
scheme"union" | "non_union" | "import"Default union.
rows*OssSaleRow[]
csvstringAlternative to rows: the CSV text of the export.
application/json
{
  "period": "2026-Q3",
  "scheme": "union",
  "rows": [
    {
      "country": "DE",
      "rate": 19,
      "net": 1250,
      "vat": 237.5,
      "date": "2026-07-14",
      "supplyType": "goods"
    },
    {
      "country": "DE",
      "rate": 7,
      "net": 310,
      "vat": 21.7,
      "date": "2026-08-02",
      "supplyType": "goods"
    },
    {
      "country": "FR",
      "category": "digital_services",
      "net": 980,
      "date": "2026-09-21"
    },
    {
      "country": "IT",
      "rate": 22,
      "net": -45,
      "vat": -9.9,
      "date": "2026-05-30",
      "correctionOfPeriod": "2026-Q2"
    }
  ]
}

Request

curl
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":"DE","rate":7,"net":310,"vat":21.7,"date":"2026-08-02","supplyType":"goods"},{"country":"FR","category":"digital_services","net":980,"date":"2026-09-21"},{"country":"IT","rate":22,"net":-45,"vat":-9.9,"date":"2026-05-30","correctionOfPeriod":"2026-Q2"}]}' \
  "https://veriport.io/api/v1/vat/oss/return"

Response 200

The return: lines, corrections, totals, the file, and what each portal accepts.

Media types: application/json, text/csv.

FieldTypeDescription
scheme*"union" | "non_union" | "import"
period*object
period.labelstring
period.kind"quarter" | "month"
period.startstring (date)
period.endstring (date)
period.dueDatestring (date)Last day of the month following the period.
currency*"EUR"
lines*object[]
corrections*object[]
totals*object
totals.rowsinteger
totals.countriesinteger
totals.netnumber
totals.vatnumber
totals.correctionsVatnumber
totals.vatPayablenumber
byCountryobject[]
ratesobject
rates.verifiedOnstring (date)
warningsobject[]
files*object[]
portals*object[]
200 OK · application/json
{
  "scheme": "union",
  "period": {
    "label": "2026-Q3",
    "kind": "quarter",
    "start": "2026-07-01",
    "end": "2026-09-30",
    "dueDate": "2026-10-31"
  },
  "currency": "EUR",
  "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
  },
  "byCountry": [
    {
      "country": "DE",
      "countryName": "Germany",
      "net": 1560,
      "vat": 259.2
    },
    {
      "country": "FR",
      "countryName": "France",
      "net": 980,
      "vat": 196
    }
  ],
  "rates": {
    "verifiedOn": "2026-10-24"
  },
  "warnings": [],
  "files": [
    {
      "id": "generic_csv",
      "filename": "oss-return-union-2026-Q3-generic.csv",
      "contentType": "text/csv; charset=utf-8",
      "portal": null,
      "content": "period,scheme,member_state,member_state_name,supply_type,rate_kind,rate_percent,taxable_amount_eur,vat_amount_eur,rows,correction_of_period\r\n2026-Q3,union,DE,Germany,goods,standard,19,1250.00,237.50,1,\r\n…"
    }
  ],
  "portals": [
    {
      "memberState": "FR",
      "portal": "impots.gouv.fr — guichet unique TVA (espace professionnel)",
      "status": "generic",
      "note": "No public file-import specification was found; key the lines in."
    },
    {
      "memberState": "DE",
      "portal": "BZStOnline-Portal (Mein BOP)",
      "status": "generic",
      "note": "CSV import exists; its record layout is published only inside the logged-in form."
    }
  ]
}

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 400invalid_parameter — A parameter is missing or malformed.
  • 401unauthorized — The API key is missing, unknown or revoked.
  • 402quota_exceeded — Monthly allowance and credits are used up.
  • 409idempotency_conflict — The Idempotency-Key is in use.
  • 413payload_too_large — Too many rows or too many bytes.
  • 422unprocessable_file — The uploaded rows cannot be turned into a return.
  • 429rate_limited — Too many requests per second.

Sources