---
title: "How to Integrate with the Twinfield API"
description: "Developer guide to integrating with the Twinfield API. Covers OAuth, cluster routing, SOAP requests, rate limits, and the partner certification process."
author: "Kateryna Poryvay"
published: "2026-05-20"
updated: "2026-05-20T21:51:51.760Z"
url: "https://www.apideck.com/blog/how-to-integrate-with-the-twinfield-api"
category: "Accounting"
tags: ["Accounting", "Guides & Tutorials"]
---

# How to Integrate with the Twinfield API

Twinfield is the cloud accounting platform [Wolters Kluwer acquired in 2011](https://www.wolterskluwer.com/en/news/wolters-kluwer-tax-accounting-expands-european-online-software-solutions-with-acquisition-of-twinfield) to anchor its European tax and accounting suite. In the Netherlands it sits at the upper end of the SMB and mid-market segment, alongside Exact Online and AFAS, and it has meaningful presence in the UK through Wolters Kluwer's CCH ecosystem. If your product serves Dutch accounting firms, mid-sized businesses with multi-entity setups, or any customer that lives inside the WK financial suite, you will end up integrating with Twinfield.

This guide walks through the integration end to end: how OAuth works with the Wolters Kluwer identity platform, why you need to resolve a cluster URL before you can call anything useful, what SOAP services you will actually use, where rate limits hit a non-certified app first, and what the certification process costs in time and effort.

> Auth note: Twinfield uses OpenID Connect on top of OAuth 2.0 for authentication, but the API itself is primarily SOAP-based with XML payloads. You combine an OAuth access token with a SOAP header that includes a `CompanyCode`. Standard REST patterns do not apply.

## Prerequisites

Before you start:

- A Twinfield account with developer portal access. You can register at [developers.twinfield.com](https://developers.twinfield.com) and create an OAuth client.
- A backend service that can hold a client secret. The authorization code flow is the only sensible option for a production server-to-server integration.
- A working knowledge of SOAP and XML parsing. The API does not return JSON.
- A clear answer to whether you are building for a single organisation (one accountancy firm) or for many. The OAuth consent flow runs per organisation user.

## Step 1: Register an OAuth client in the developer portal

Log into the Twinfield developer portal and create a new application. You will get:

- A Client ID
- A client secret (only shown once; copy it now)
- A redirect URI you control on your side

Register the redirect URI exactly as your app will send it, including the trailing slash or absence of one. The token endpoint will reject a request where the redirect URI does not match byte-for-byte. This trips up almost every first integration.

Twinfield supports two OAuth flows: implicit and authorization code. Use the authorization code flow with the `offline_access` scope. Implicit flow exists for native and JavaScript-only clients, and the lack of a refresh token in that flow is a hard ceiling. Access tokens last 12 hours in implicit flow and 1 hour in code flow, and without `offline_access` you cannot extend them without sending the user back through the consent screen.

The full set of scopes you almost always want for a server-side accounting integration:

```
openid twf.user twf.organisation twf.organisationUser offline_access
```

The `twf.organisationUser` scope is mandatory for login. The `offline_access` scope is required for refresh tokens. Without it, you are stuck redoing the consent flow every hour.

## Step 2: Walk a user through the authorization flow

Redirect the user to the Twinfield authorize endpoint:

```
https://login.twinfield.com/auth/authentication/connect/authorize
  ?client_id=YOUR_CLIENT_ID
  &response_type=code
  &scope=openid+twf.user+twf.organisation+twf.organisationUser+offline_access
  &redirect_uri=YOUR_REDIRECT_URI
  &state=RANDOM_STATE
  &nonce=RANDOM_NONCE
```

After the user logs in and consents, Twinfield redirects to your callback with a `code` and the original `state`. Verify the state, then exchange the code at the token endpoint:

```http
POST https://login.twinfield.com/auth/authentication/connect/token
Authorization: Basic BASE64(CLIENT_ID:CLIENT_SECRET)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=THE_CODE_YOU_RECEIVED
&redirect_uri=YOUR_REDIRECT_URI
```

The response contains an access token, an ID token, an `expires_in` value (3600 seconds for the auth code flow), and a refresh token. Store all of these against the user record.

A note on refresh token lifetime: Twinfield documents refresh tokens as valid for [788,940,000 seconds, or roughly 25 years](https://developers.twinfield.com/documentation/api/authentication/openid-connect-auth). In practice, plan for them to fail earlier than that. If a user changes password, has their account disabled, gets deleted from their organisation, or the organisation itself is deactivated, the refresh token is invalidated immediately. Your only signal is an `invalid_request` error on the next refresh attempt.

## Step 3: Resolve the cluster URL

This is the step most teams miss in their first day.

Twinfield runs multiple data clusters. Your access token is issued by the central login service, but the actual web service endpoints live on whichever cluster your customer's organisation sits on. You do not know which cluster that is from the token alone.

Send the access token to the validation endpoint:

```http
GET https://login.twinfield.com/auth/authentication/connect/accesstokenvalidation?token=ACCESS_TOKEN
```

The response includes a `twf.clusterUrl` claim. That URL is the base for every subsequent SOAP call. If your customer is on `https://accounting.twinfield.com`, your calls go there. If they are on a different cluster, calls to the wrong one return what looks like an authentication error but is actually a routing problem. Cache the cluster URL alongside the customer's tokens.

## Step 4: Make your first authenticated SOAP request

Twinfield's API is organised around two patterns: Commands and Queries. Commands mutate data, Queries read it. Both wrap a payload in a SOAP envelope with an authentication header.

A simple ProcessXml query that reads the list of offices in an administration looks like:

```xml
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <Header xmlns="http://www.twinfield.com/">
      <AccessToken>YOUR_ACCESS_TOKEN</AccessToken>
      <CompanyCode>001</CompanyCode>
    </Header>
  </soap:Header>
  <soap:Body>
    <ProcessXmlString xmlns="http://www.twinfield.com/">
      <xmlRequest>
        <list>
          <type>offices</type>
        </list>
      </xmlRequest>
    </ProcessXmlString>
  </soap:Body>
</soap:Envelope>
```

POST that to `{clusterUrl}/webservices/processxml.asmx` with `Content-Type: text/xml; charset=utf-8` and a `SOAPAction` header set to `http://www.twinfield.com/ProcessXmlString`.

`CompanyCode` scopes every call to a single administration. If your customer manages 200 client books, you iterate by changing the company code in the header. You can pass `CompanyId` (a GUID) instead of `CompanyCode` for the same effect.

Twinfield maintains [official C# integration samples on GitHub](https://github.com/Twinfield/TwinfieldIntegrationSamples) if you want a working reference for the SOAP scaffolding.

## Key endpoints and data models

The Twinfield API exposes the core accounting object graph through a mix of typed SOAP services and a generic ProcessXml endpoint that handles XML documents directly.

Master data covers offices (administrations), users, periods, financial settings, VAT codes, currencies, and payment conditions. Dimensions cover customers, suppliers, general ledger accounts, projects, cost centers, and asset codes. Transaction data covers sales invoices, purchase invoices, bank statements, journal entries, cash entries, and memorial entries. Request data covers browse queries for financial reports and trial balance, hierarchy queries for the chart of accounts, and individual transaction reads by number.

The data model leans heavily on dimensions. In Twinfield, customers and suppliers are not first-class objects; they are dimensions of types `DEB` and `CRD` respectively. General ledger accounts are dimensions of type `BAS` or `PNL`. Once you understand that customers, suppliers, projects, cost centers, and accounts share a dimension data structure, the rest of the API gets easier to navigate. The [dimensions documentation](https://developers.twinfield.com/documentation/getting-started/dimensions) is worth reading before you write any code.

## Rate limits and concurrency

Twinfield enforces credit-based rate limiting as of December 2024. The credit system charges differently for reads and writes. Query requests (HTTP GET, OPTIONS, and SOAP actions starting with `Get`, `Query`, `Search`, or `Load`, plus ProcessXml requests with `list`, `read`, `columns`, `accountcode`, or `accountcodes` root elements) cost 1 credit. Everything else costs 3 credits.

The credit budget per minute:

- 1000 credits per IP address
- 1000 credits per Client ID
- 1000 credits per Organisation ID
- 500 credits per Client ID and Organisation ID combination

One wrinkle: those numbers apply to certified integrations. New and uncertified clients get 5% of those limits. That means a non-certified Client ID is capped at 50 credits per minute, and 25 credits per minute against a single organisation. You can hit that ceiling in a few seconds of synchronous backfill.

Twinfield also enforces concurrency: 20 simultaneous requests per Client ID, 10 per Client ID and Organisation combination. A 429 response with the `Retry-After` header is the signal to back off. The full rate limit rules are documented in the [fair use policy](https://developers.twinfield.com/documentation/getting-started/fair-use-policy).

Two practical implications:

- Build your client around exponential backoff and respect the `X-RateLimit-Remaining` header from day one. Adding it after you ship is harder than adding it before.
- Batch your writes. The XML format lets you submit up to 25 children per parent element and up to 500 lines per transaction (1000 is the hard ceiling). One batched call costs 3 credits; 25 individual calls cost 75.

## The certification process

Twinfield gates production access behind a partner program. Until you are certified, you live with the 5% rate limit, and you cannot publish your integration to the Twinfield marketplace, which is where most Twinfield-using accountants discover and install third-party apps.

The [certification process](https://wktaaeu.my.site.com/nlcommunity/articles/en_US/Knowledge/Wat-komt-er-aan-bod-tijdens-de-certificering) consists of a technical review against the [API best practices](https://wktaaeu.my.site.com/nlcommunity/s/article/API-Best-Practices-Introduction?language=en_US) document, a security review, and a recurring audit cadence. Wolters Kluwer charges a partner fee per active API link, and uncertified integrations are eventually phased out. Pricing is published in the partner price list and is worth confirming directly with WK before committing, since the numbers third-party blogs cite are not always current.

Plan for several weeks between submitting an integration for certification and getting marketplace approval. If your product launch depends on it, start the conversation with Wolters Kluwer's partner team before you finish the build, not after.

## Common gotchas

A few things that will cost you a day each if you do not know them upfront.

*Cluster URL caching.* If you skip the cluster resolution step or assume `accounting.twinfield.com` for every customer, you will hit silent authentication failures the first time a customer is on a different cluster. Cache the resolved URL against the customer's organisation ID.

*CompanyCode versus CompanyId.* Both work in the SOAP header, but they behave slightly differently across services. `CompanyCode` is the human-readable code (e.g. `001`); `CompanyId` is the GUID. Some downstream tooling and reporting flows expect one or the other. Pick a convention and stick with it.

*Refresh token revocation is silent.* When a user is disabled or password-rotated, your refresh token stops working with no upfront notice. Your only signal is an `invalid_request` error on the next refresh. Build for the case where you have to send the user back through consent without warning.

*XML size limits are unevenly documented.* The fair use policy says 25 children per parent and 500 lines per transaction recommended, 1000 hard. Some entities have their own internal limits that are not in the public docs. If a large payload fails with a generic error, split it and retry.

*The sandbox is a real Twinfield account.* Twinfield does not offer a separate sandbox API. Test environments are real Twinfield administrations that you request from your partner contact. Pollution between test data and live data is on you to manage.

*VAT handling does not match generic accounting models.* Twinfield's VAT logic is opinionated about Dutch and EU compliance rules. Submitting an invoice with an inconsistent VAT code and base amount returns errors that read as schema problems but are actually compliance validation failures. Read the [VAT calculation docs](https://developers.twinfield.com/documentation/getting-started/vat-calculation) before posting any invoices.

## Where this leaves you

A direct Twinfield integration is a meaningful build. You are looking at OAuth with cluster resolution, SOAP plumbing, XML payload construction, a credit-based rate limiter that throttles you to 5% until you certify, and a partner program with ongoing fees and a recertification cadence. None of it is unreasonable for a platform with Twinfield's market position, but it is a multi-week commitment for one connector.

If Twinfield is one of several accounting platforms on your roadmap, the math shifts. Your Dutch SMB customers also use [MoneyBird](https://www.apideck.com/blog/moneybird-api-integration) and [SnelStart](https://www.apideck.com/blog/how-to-integrate-with-the-snelstart-api). Your French ones use Pennylane. Your German ones use DATEV. Each has its own auth model, its own pagination behaviour, its own gotchas. Building and maintaining a portfolio of direct integrations is a real ongoing engineering investment.

Apideck does not yet have a Twinfield connector. Our [unified Accounting API](https://www.apideck.com/accounting-api) covers most of the rest of the Dutch and broader European SMB market, and custom connectors are part of the enterprise plan when a specific platform is missing. Twinfield is on the roadmap. If you would benefit from it being there sooner, you can [request Twinfield support](https://www.apideck.com/accounting-software/twinfield) or start building today against the 40+ accounting connectors already in the unified API with a [30-day free trial](https://www.apideck.com/signup).