Prepare a filing period's report
The filing_periods.prepare operation: POST /api/v1/filing_periods/{id}/prepare in the REST API and the filing_periods_prepare tool in the MCP server.
/api/v1/filing_periods/{id}/prepareGenerates the period's report (spec §21.2) from the entity's invoices and credit notes and its ledger, never
from processor data, for every brand of the entity, and stores it on the period with its CSV and XLSX files.
The period becomes prepared. The report follows the regime (reportKind):
eu_oss: taxable amount and VAT per member state of consumption and rate in EUR (ECB rate of the period's last day, or of the next publication day), corrections of earlier periods by original period, and the balance per member state;eu_domestic: domestic supplies by rate, corrections, the return values by rate, and the EC Sales List (reverse-charged services to businesses in other member states, per customer VAT ID);uk_vat: the nine boxes of the UK VAT return, with sales by rate;ch_mwst: turnover and tax by rate in CHF;us_state: gross, taxable and exempt sales and the tax by state;generic: sales and tax by jurisdiction and rate in the regime's currency.
Except for eu_oss, other currencies are converted per the filing spec's exchange-rate rule: the ECB rate of
the period's last day when it names it, else of each document's tax-point date. Credit notes for sales
reported in an earlier period are corrections of that period. Sales made during a grace period are reported
in the first return after the registration's effective date.
Every report includes a reconciliation: its tax per jurisdiction and currency must equal the movement of the
regime's tax payable accounts in the ledger for the period. If they differ, nothing is stored and the call
fails with filing_reconciliation_failed, listing the documents that differ.
Works on a locked period, and again on a prepared one until it is submitted. Write tier: tax managers,
finance, owners and admins. Dry-run it to see the report without storing anything.
At a glance
- REST:
POST /api/v1/filing_periods/{id}/prepare - MCP tool:
filing_periods_prepare - Operation ID:
filing_periods.prepare - Scope: Legal entity
- Permission:
filings:write - Risk tier:
write - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyrequired - Modes: Test and live
- Authentication: API key with the
filings:writescope - Since: M8
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | fp_… ID | The filing period (fp_…). |
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
note | string | No | A note for the period's history, e.g. who checked the figures. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | fp_… ID | |
object | "filing_period" | |
entityId | ent_… ID | |
livemode | boolean | |
regimeId | string | |
registrationId | regn_… ID | |
reportKind | one of eu_oss, eu_domestic, uk_vat, ch_mwst, generic, us_state | |
reportAvailable | boolean | |
frequency | one of monthly, quarterly, annual | |
periodKey | string | The period: "2026-Q3", "2026-07" or "2026". |
periodStart | date-time | |
periodEnd | date-time | The end (exclusive): the next period's first local midnight. |
firstDay | string | |
lastDay | string | |
timeZone | string | |
currency | string | |
dueDate | string | |
dueAt | date-time | 23:59:59 local time on the due date. |
lockableAt | date-time | |
status | one of open, locked, prepared, submitted, paid | |
statusChangedAt | date-time | |
lockedAt | date-time or null | |
preparedAt | date-time or null | |
submittedAt | date-time or null | |
reference | string or null | |
paidAt | date-time or null | |
paymentRef | string or null | |
totals | object or null | |
createdAt | date-time | |
updatedAt | date-time | |
registration | object or null | |
endsBeforeRegistration | boolean | |
report | object or null | |
files | array of object | |
files[].format | one of csv, xlsx, xml | |
files[].fileId | file_… ID | |
files[].filename | string | |
files[].contentType | string | |
files[].size | integer | |
files[].sha256 | string | |
receipts | array of object | |
receipts[].kind | one of file, reference | |
receipts[].reference | string | |
receipts[].label | string or null | |
receipts[].addedAt | date-time | |
receipts[].addedBy | string | |
paymentLedgerTxnIds | array of txn_… ID | |
reminders | array of object | |
reminders[].code | string | |
reminders[].at | date-time | |
reminders[].skipped | boolean | |
history | array of object | |
history[].from | one of open, locked, prepared, submitted, paid or null | |
history[].to | one of open, locked, prepared, submitted, paid | |
history[].at | date-time | |
history[].by | string | |
history[].note | string or null | |
actions | object | |
actions.lock | object | |
actions.lock.allowed | boolean | |
actions.lock.code | string or null | |
actions.lock.message | string or null | |
actions.prepare | object | |
actions.prepare.allowed | boolean | |
actions.prepare.code | string or null | |
actions.prepare.message | string or null | |
actions.submit | object | |
actions.submit.allowed | boolean | |
actions.submit.code | string or null | |
actions.submit.message | string or null | |
actions.markPaid | object | |
actions.markPaid.allowed | boolean | |
actions.markPaid.code | string or null | |
actions.markPaid.message | string or null |
Examples
Generate the Q3 OSS return
POST /api/v1/filing_periods/fp_01m4tx5nj8emwbyf7y9vcf47y0/prepare
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Response (200):
{
"id": "fp_01m4tx5nj8emwbyf7y9vcf47y0",
"object": "filing_period",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
"livemode": true,
"regimeId": "EU_OSS_UNION",
"registrationId": "regn_01m4tx5nj8emwbyf7y9vcf47xk",
"reportKind": "eu_oss",
"reportAvailable": true,
"frequency": "quarterly",
"periodKey": "2026-Q3",
"periodStart": "2026-06-30T22:00:00.000Z",
"periodEnd": "2026-09-30T22:00:00.000Z",
"firstDay": "2026-07-01",
"lastDay": "2026-09-30",
"timeZone": "Europe/Zagreb",
"currency": "EUR",
"dueDate": "2026-10-31",
"dueAt": "2026-10-31T22:59:59.000Z",
"lockableAt": "2026-09-30T22:00:00.000Z",
"status": "prepared",
"statusChangedAt": "2026-10-02T08:05:00.000Z",
"lockedAt": "2026-10-02T08:00:00.000Z",
"preparedAt": "2026-10-02T08:05:00.000Z",
"submittedAt": null,
"reference": null,
"paidAt": null,
"paymentRef": null,
"totals": {
"currency": "EUR",
"taxable": "1500000000",
"tax": "290000000",
"corrections": "-19000000",
"due": "271000000",
"refundable": "0"
},
"createdAt": "2026-07-01T03:00:00.000Z",
"updatedAt": "2026-10-02T08:05:00.000Z",
"registration": {
"id": "regn_01m4tx5nj8emwbyf7y9vcf47xk",
"state": "registered",
"registrationNumber": "HR12345678901",
"effectiveFrom": "2026-03-31T22:00:00.000Z"
},
"endsBeforeRegistration": false,
"report": {
"kind": "eu_oss",
"currency": "EUR",
"rounding": "half_up",
"fxRule": null,
"generatedAt": "2026-10-02T08:05:00.000Z",
"fx": [],
"sections": [
{
"id": "supplies",
"title": "Supplies by member state of consumption and rate",
"columns": [
{
"key": "memberState",
"label": "Member state",
"type": "text"
},
{
"key": "rate",
"label": "VAT rate",
"type": "rate"
},
{
"key": "rateKind",
"label": "Rate type",
"type": "text"
},
{
"key": "taxable",
"label": "Taxable amount",
"type": "money"
},
{
"key": "vat",
"label": "VAT",
"type": "money"
},
{
"key": "lines",
"label": "Lines",
"type": "count"
}
],
"rows": [
{
"memberState": "DE",
"rate": "190000",
"rateKind": "standard",
"taxable": "1000000000",
"vat": "190000000",
"lines": 8
},
{
"memberState": "FR",
"rate": "200000",
"rateKind": "standard",
"taxable": "500000000",
"vat": "100000000",
"lines": 3
}
]
},
{
"id": "corrections",
"title": "Corrections of earlier periods",
"columns": [
{
"key": "originalPeriod",
"label": "Period corrected",
"type": "text"
},
{
"key": "memberState",
"label": "Member state",
"type": "text"
},
{
"key": "taxable",
"label": "Taxable amount",
"type": "money"
},
{
"key": "vat",
"label": "VAT",
"type": "money"
},
{
"key": "lines",
"label": "Lines",
"type": "count"
}
],
"rows": [
{
"originalPeriod": "2026-Q2",
"memberState": "DE",
"taxable": "-100000000",
"vat": "-19000000",
"lines": 1
}
]
},
{
"id": "balances",
"title": "VAT due per member state",
"columns": [
{
"key": "memberState",
"label": "Member state",
"type": "text"
},
{
"key": "supplies",
"label": "VAT on supplies",
"type": "money"
},
{
"key": "corrections",
"label": "Corrections",
"type": "money"
},
{
"key": "balance",
"label": "Balance",
"type": "money"
}
],
"rows": [
{
"memberState": "DE",
"supplies": "190000000",
"corrections": "-19000000",
"balance": "171000000"
},
{
"memberState": "FR",
"supplies": "100000000",
"corrections": "0",
"balance": "100000000"
}
]
},
{
"id": "reconciliation",
"title": "Reconciliation with the ledger",
"columns": [
{
"key": "jurisdiction",
"label": "Jurisdiction",
"type": "text"
},
{
"key": "currency",
"label": "Currency",
"type": "text"
},
{
"key": "reportTax",
"label": "Report tax",
"type": "money"
},
{
"key": "ledgerTax",
"label": "Ledger tax payable",
"type": "money"
},
{
"key": "difference",
"label": "Difference",
"type": "money"
}
],
"rows": [
{
"jurisdiction": "DE",
"currency": "EUR",
"reportTax": "171000000",
"ledgerTax": "171000000",
"difference": "0"
},
{
"jurisdiction": "FR",
"currency": "EUR",
"reportTax": "100000000",
"ledgerTax": "100000000",
"difference": "0"
}
]
}
],
"reconciliation": {
"matches": true,
"rows": [
{
"jurisdictionId": "DE",
"currency": "EUR",
"reportTax": "171000000",
"ledgerTax": "171000000",
"difference": "0"
},
{
"jurisdictionId": "FR",
"currency": "EUR",
"reportTax": "100000000",
"ledgerTax": "100000000",
"difference": "0"
}
]
},
"counts": {
"lines": 12,
"corrections": 1,
"notReported": 0,
"documents": 12
}
},
"files": [
{
"format": "csv",
"fileId": "file_01m4tx5nj8emwbyf7y9vcf47y2",
"filename": "EU_OSS_UNION-2026-Q3.csv",
"contentType": "text/csv; charset=utf-8",
"size": 2381,
"sha256": "5d1c9d6b7f3e0a4c8b2f1e6d9a7c3b5e0f4d8a2c6b1e9f7d3a5c0b8e2f6d4a1c"
},
{
"format": "xlsx",
"fileId": "file_01m4tx5nj8emwbyf7y9vcf47y3",
"filename": "EU_OSS_UNION-2026-Q3.xlsx",
"contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"size": 9184,
"sha256": "8a3f6c1e9d4b7a2f5c0e8d3b6a1f4c9e7d2b5a0f3c8e6d1b4a9f7c2e5d0b3a6f"
}
],
"receipts": [],
"paymentLedgerTxnIds": [],
"reminders": [],
"history": [
{
"from": null,
"to": "open",
"at": "2026-07-01T03:00:00.000Z",
"by": "system",
"note": null
},
{
"from": "open",
"to": "locked",
"at": "2026-10-02T08:00:00.000Z",
"by": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
"note": null
},
{
"from": "locked",
"to": "prepared",
"at": "2026-10-02T08:05:00.000Z",
"by": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
"note": null
}
],
"actions": {
"lock": {
"allowed": false,
"code": "filing_period_status_invalid",
"message": "This period is prepared: \"lock\" needs open."
},
"prepare": {
"allowed": true,
"code": null,
"message": null
},
"submit": {
"allowed": true,
"code": null,
"message": null
},
"markPaid": {
"allowed": false,
"code": "filing_period_status_invalid",
"message": "This period is prepared: \"mark_paid\" needs submitted."
}
}
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | A field is malformed (param names it). | Fix the fields listed in details.issues and send the request again. |
resource_not_found | 404 | No filing period with this ID exists for this legal entity and mode. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
scope_required | 400 | The request names no legal entity (an org key without Ownrecord-Entity). | Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (details.required_scope). |
filing_period_status_invalid | 409 | The period isn't locked or prepared (details.status). | Reload the period and check its status: details.allowed_from lists the statuses the action needs. Periods go open → locked → prepared → submitted → paid. |
filing_report_kind_unsupported | 409 | Ownrecord can't generate this regime's report yet (details.report_kind). | Prepare the return outside Ownrecord for now; the report for this kind of regime comes in a later release. |
filing_registration_not_effective | 409 | The registration is still pending: grace sales have no return until it has an effective date. | Mark the registration registered with its number and effective date first: sales made during the grace period are reported in the first return after it. |
fx_rate_unavailable | 404 | The ECB rates the report converts with (of the period's last day or the next publication day, or of a document's tax-point date) aren't loaded yet. Retry after the next publication. | Check the currency (the ECB publishes about 30) and the date. Rates are fetched every day after 16:00 CET; for a date with no rate yet, try again after the next publication. |
filing_reconciliation_failed | 409 | The report's tax differs from the ledger's tax payable (details.rows, details.documents). | Check the documents in details.documents: each shows the report's and the ledger's tax. Correct the ledger or the documents (for example with a manual ledger adjustment or a credit note), then prepare the period again. |
upstream_timeout | 502 | The file store didn't answer in time; nothing was stored. Retry. | Retry the request with the same Idempotency-Key after a short wait. |
version_conflict | 409 | The period changed at the same moment. Reload it and try again. | Fetch the object again and retry the change. |
permission_denied | 403 | You can't work on this entity's filings (tax managers, finance, owners and admins can). | Ask an organization owner or admin for a role or scope that allows this action. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.