# Winstwaker v1 API - LLM Context Use this as the canonical integration context for AI-generated code. ## 1) Base URL and auth - Base URL: `https://api.winstwaker.nl/v1` - Health endpoint (`GET /health`) is public. - All other endpoints require: - `Authorization: Bearer ` - Live keys: `ww_live_...` - Test keys: `ww_test_...` ## 2) Response envelope (important) Most authenticated endpoints return a standard envelope: ```json { "ok": true, "request_id": "uuid", "mode": "live|test", "status": "SUBMITTED|ACCEPTED|...", "message": "Human-readable status", "data": {}, "breakdown": {}, "errors": null } ``` Error envelope: ```json { "ok": false, "request_id": "uuid", "mode": "live|test|null", "status": "ERROR", "message": "Error text", "data": null, "breakdown": null, "errors": { "code": "ERROR_CODE", "details": {} } } ``` ## 3) Rate limits - Per API key, per minute. - Respect headers: - `X-RateLimit-Limit` - `X-RateLimit-Remaining` - `X-RateLimit-Reset` - On `429`, honor `Retry-After`. ## 4) Idempotency rules - Required on create POST routes: - `POST /omzetbelasting/returns` - `POST /icp/returns` - `POST /oss/returns` - `POST /dividendbelasting/returns` - `POST /vennootschapsbelasting/returns` - `POST /inkomstenbelasting/uitstelverzoeken` - Must include `Idempotency-Key`. - Reusing the key with identical payload may return replay (`200`). - Reusing key with different payload returns `409 CONFLICT_IDEMPOTENCY`. ## 5) Endpoints ### Public - `GET /health` ### Credits and usage - `GET /credits/balance?mode=live|test` (mode optional) - `GET /credits/events?mode=live|test&limit=25&cursor=` - `GET /usage/summary?period=day|month` ### Omzetbelasting - `POST /omzetbelasting/returns` - `GET /omzetbelasting/returns/{requestId}?refresh=true|false` ### ICP - `POST /icp/returns` - `GET /icp/returns/{requestId}?refresh=true|false` ### OSS - `POST /oss/returns` - `GET /oss/returns/{requestId}?refresh=true|false` ### Dividendbelasting - `POST /dividendbelasting/returns` - `GET /dividendbelasting/returns/{requestId}?refresh=true|false` ### Vennootschapsbelasting - `POST /vennootschapsbelasting/returns` - `GET /vennootschapsbelasting/returns/{requestId}?refresh=true|false` ### Inkomstenbelasting uitstel - `POST /inkomstenbelasting/uitstelverzoeken` - `GET /inkomstenbelasting/uitstelverzoeken/{requestId}?refresh=true|false` ## 6) OpenAPI contract - Public export: `https://winstwaker.nl/api/developers/openapi` - Use this for exact schemas, examples, headers and status codes. ## 7) Omzetbelasting create payload rules Accepted variants: - `ob_nummer` or `obNummer` (format: `NL#########B##`) - Either: - `periode` as `YYYY-Q[1-4]` - or `year` + `quarter` (1-4) - Input style: - full `vatData` / `vat_data` - or quick path with `omzet` + `btw_hoog` Note: AI should prefer `ob_nummer`, `periode`, `omzet`, `btw_hoog` for concise code unless detailed VAT boxes are needed. ## 8) ICP create payload rules Required minimum: - `ob_nummer` or `obNummer` - `periode` or `year` + `quarter` - `entries` with at least 1 item Per entry use preferably: - `country_code` - `vat_number` - `type` = `L`, `D` or `B` - A positive amount field such as `services_amount`, `supplies_amount` or `total_amount` ## 9) OSS create payload rules Current supported scope: - `scheme: "OBU"` Required minimum: - `ob_nummer` - `periode` - `scheme` - `lines` with at least 1 item Per line use: - `member_state_of_consumption` - `supply_type` - `member_state_type` - `eu_member_state` - `rate_type` - `rate` - `taxable_amount` ## 10) Dividendbelasting create payload rules Required fields: - `distributionDate` (YYYY-MM-DD) - `grossDividend`, `dividendTax`, `netDividend` - `withholdingEntityName` - `withholdingEntityRsin` (9 digits) - `beneficiaries` (array, min 1 item) Beneficiary should include at least: - `name` - `bsnOrRsin` ## 11) Inkomstenbelasting uitstel create payload rules Required minimum: - `fiscalYear` or `fiscal_year` = `2024` or `2025` - `consultant.identificationNumber` or `consultant.identification_number` (9 digits RSIN/finummer) - `consultant.beconNumber` or `consultant.becon_number` (6 digits) - `consultant.surname` - In live mode mag `consultant` leeg blijven als Winstwaker een globale admin-config heeft ingesteld - `requests` with at least 1 taxpayer Per taxpayer entry use preferably: - `taxpayerIdentificationNumber` or `taxpayer_identification_number` (9 digits) - optional `taxpayerInitials`, `taxpayerPrefix`, `taxpayerSurname` - optional `requestType`: `1`, `4`, `6`, `9` or readable aliases like `aanvullend_uitstel` - `specialMotivation` is required for aanvullend uitstel (`requestType = 6`) Important: - Transport goes through Digipoort, but the substantive Belastingdienst decision comes back via SBU. - `data.business_status.grant_status = "PENDING_SBU"` after a successful create response does not mean approved yet. ## 12) Vennootschapsbelasting create payload rules Required minimum: - `fiscalYear` or `fiscal_year` - `rsin` or `company_rsin` (9 digits) - `taxableProfit` or `taxable_profit` Alternative minimum for officiële nul-aangifte auto-generation: - `fiscalYear` or `fiscal_year` - `rsin` or `company_rsin` (9 digits) - `zeroReturn` or `zero_return` = `true` - `companyName` or `company_name` - `bookYearStart` / `bookYearEnd` or snake_case varianten - `taxpayerType` or `taxpayer_type` = `domestic` or `foreign` Optional: - `lossCarryForward` or `loss_carry_forward` - `innovationBoxProfit` or `innovation_box_profit` - `innovationBoxRate` or `innovation_box_rate` - `filingReference` or `filing_reference` - `xbrlContent` or `xbrl_content` - `softwareSupplierCode` or `software_supplier_code` (override; defaults to the configured Digipoort softwareleverancierscode) - `softwarePackageName` or `software_package_name` - `softwarePackageVersion` or `software_package_version` - `softwareVendorAccountNumber` or `software_vendor_account_number` Important: - In `live` mode vereist Winstwaker een officiële VPB XBRL-instance via `xbrlContent`, inclusief een `schemaRef` naar de actuele VPB taxonomy van het fiscale jaar, of een expliciete `zeroReturn` payload waarmee Winstwaker zelf een officiële nul-aangifte opbouwt. - Bij aangeleverde officiële VPB XBRL controleert Winstwaker minimaal identifier/RSIN, boekjaar, officiële `schemaRef`, `PartyDimension[Declarant]` en een `TaxpayerDimension` context voor het belastingjaar. - Voor `zeroReturn` hergebruikt Winstwaker standaard dezelfde Digipoort software metadata als de andere belastingstromen; de `software*` velden zijn alleen overrides. - Live support is momenteel geconfigureerd voor `2024` en `2025`. - Als voor een jaar nog geen officiële VPB taxonomy is vrijgegeven of geconfigureerd, blokkeert Winstwaker de live submit expliciet. - In de publieke v1 API bestaat geen `dryRun`-schakelaar; live of test wordt bepaald door het API key prefix (`ww_live_...` of `ww_test_...`). - In `test` mode kan Winstwaker een generated smoke/test payload gebruiken om Digipoort-transport en requeststatus te verifiëren. ## 13) Async processing and polling guidance - Create endpoints return quickly with request IDs. - Use status endpoints with `refresh=true` to update state. - Polling cadence: follow a backoff schedule instead of tight loops. Logius guidance is 15 seconds, then 1 minute, then 15 minutes, then 1 hour, then every 4 hours. - Stop polling once a terminal status is reached. - Store both `data.request_id` and, when present, `data.digipoort.winstwaker_kenmerk`. - A status endpoint may return cached data with `200` if a refresh attempt fails. Inspect `data.digipoort.refresh` to see whether the latest refresh actually succeeded. - For `/inkomstenbelasting/uitstelverzoeken`, Digipoort status is transport only; use `data.business_status` for the SBU handoff state. ## 14) Common error codes (non-exhaustive) - `AUTH_MISSING_BEARER` - `AUTH_INVALID_KEY` - `AUTH_IP_NOT_ALLOWED` - `AUTH_SCOPE_MISSING` - `RATE_LIMIT_EXCEEDED` - `VALIDATION_MISSING_IDEMPOTENCY_KEY` - `VALIDATION_BLOCKED` - `CONFLICT_IDEMPOTENCY` - `REQUEST_NOT_FOUND` - `CREDITS_INSUFFICIENT` - `DIGIPOORT_SUBMIT_FAILED` ## 15) Code generation preference - Prefer raw HTTP examples using `fetch`, `requests` or `curl`. - Treat the OpenAPI export as the source of truth for exact request and response shapes.