maesn
For developers

How to integrate with Procountor: Two authorisation worlds, and one of them has a ceiling

Procountor is quick to call and slower to plan around. Two authorisation flows lead into the same system, and they do not reach the same endpoints: the one that runs without a person cannot touch anything Procountor guards with a second factor. That boundary is described in prose and named once across 192 operations, so it is usually found at runtime.

Lennart Svensson, CTO and Co-Founder at Maesn
Lennart Svensson
CTO and Co-Founder ·
Illustration for How to Integrate with Procountor: Two Ways In, One Ceiling
The context

Two applications, and both take three to four days

The first thing to know about Procountor is not technical. You cannot start against it on the afternoon you decide to. Procountor issues credentials through a form, and the answer comes back by email and by text message after three to four days.

The form asks what your integration does, which objects it will move, in which direction and for which countries, plus the redirect address the flow will use. None of it is hard. All of it sits between you and your first call.

Production is a second application of the same kind, with its own wait, and the test account does not transfer into it. Our own engineer built against the interface while waiting for the first reply and could not run a single request until it arrived.

The one thing our team would tell you first

Asked what advice he would give someone starting tomorrow, the engineer who built this integration said one thing: “Request in advance the test environment, because it takes three to four days.” The wait runs whether your code is ready or not, so it is the one task that pays to start before everything else.

The request form, the three to four day turnaround and the split delivery by email and text message from Procountor’s testing environment request and getting started guide, checked 28 August 2026. The four day wait and the inability to test before it is our own engineer’s account of building it.

The mechanics

Two authorisation worlds, and only one runs unattended

Procountor offers an authorisation code flow for applications with a user in front of them, and a client credentials flow for everything that runs on its own. The second uses an API key as its credential, and that key is bound to one user, one company and one client application at the same time.

So far this is ordinary. The sentence that decides your architecture is the next one, and Procountor publishes it plainly: an access token from the client credentials flow cannot reach any endpoint that requires two-factor authentication, because those endpoints need a user who is actively present.

Two ways in, and they do not reach the same endpointsProcountor’s own wording
Authorisation code
A person is present

Your customer completes the login in a browser and picks the company.

Every endpoint, including the ones that ask for a second factor
Client credentials
Nobody is present

An API key bound to one user, one company and one client application.

Every endpoint except the ones that ask for a second factor
The example Procountor gives

An integration may modify a purchase invoice on its own. Approving the payment for it needs a person with Procountor Key, which the unattended flow cannot supply.

Counted in the specification: across 192 operations, two-factor authentication is named once. Which endpoints require it is described in prose, so the boundary is found at runtime.

Both flows lead into the same system and stop in different places. Procountor's own wording, checked 28 August 2026.

Procountor gives the example itself, and it is the one that matters commercially. An integration may modify a purchase invoice on its own. The payment for that invoice has to be approved by a person holding Procountor Key, which is issued to a natural person and cannot be handed to a service.

The expensive part is that the boundary is not machine readable. Across 192 operations in the published specification, two-factor authentication is named exactly once. Which endpoints sit behind it is described in prose, so a team that plans for full automation usually discovers the line at runtime.

Trading an API key for an access token, in Procountor's documented formHTTP
POST /api/oauth/token HTTP/1.1
Host: api.procountor.com
Content-Type: application/x-www-form-urlencoded
 
grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>&redirect_uri=<redirect_uri>&api_key=<api_key>
 
# The response carries the token and its lifetime:
# { "access_token": "...", "expires_in": 3600 }

The access token is valid for one hour, after which the same exchange runs again. Note the redirect_uri in a call that redirects nobody: Procountor reuses the same address for both flows, so an application offering both has to tell them apart with the state parameter.

The flow, the binding of the key to user, company and client, the one hour token and the shared redirect address from Procountor’s machine to machine authentication, the two-factor boundary and the purchase invoice example from its certification checkpoints, both checked 28 August 2026. The count of 192 operations is our own, taken from the published specification.

The mechanics

Every connection belongs to one company

A Procountor user can belong to several companies, which on most systems means an identifier you resolve after authenticating and then carry in every request. Procountor settles it earlier. During login it shows a selection page of its own, and the connection that comes back is bound to the company the user chose.

That has a pleasant consequence and one constraint. The pleasant part is that there is nothing to discover afterwards and nothing to thread through your calls. The constraint is that one connection is one company, so a customer running three of them is three connections, each created by a person in a browser.

It also explains something you will notice if you read our documentation: Procountor is not on either of the two flow lists there, because it needs neither a company lookup nor a selection step of ours. The vendor already does it.

The mechanics

Six months on a refresh token, and five ways to lose it

The authorisation code flow returns an access token valid for one hour and a refresh token valid for six months. The refresh token does not rotate, so the value you store on day one is the value you still hold in month five.

What matters is the list of things that end it early, because four of the five are actions by somebody who has never heard of your integration.

The five documented cases in which a Procountor refresh token stops working
What happensWho does it
The six months run outNobody, it is the clock
The user changes their passwordYour customer
The user logs out through the logout endpointYour customer or your code
The user is removed from the companyYour customer's administrator
A hundred tokens exist for the same client, company and userUsually your own code

The last row is the one that catches teams out, and it is self-inflicted instead of a limit anyone reaches by growing. Requesting a fresh token on every connection attempt instead of reusing the stored one walks a tenant towards a hundred quietly.

In all five cases the consequence is the same, and it belongs in your design. The stored refresh token is invalid, and because Procountor keeps a person in the authorisation step, nothing can quietly renew it. Your customer authenticates once more. What that costs you is a path in your product for a connection that has gone cold, and a message that says so.

The six month validity and all five invalidation cases from Procountor’s certification checkpoints, section 3.2, checked 28 August 2026. That the token does not rotate is confirmed by our own engineer against the running integration.

The data model

One object carries seven kinds of document

Procountor does not model a sales invoice, a purchase invoice and an order as separate things. It models one invoice object with a type on it, and the type takes seven values. A sales invoice, a purchase invoice, both kinds of order, a travel invoice, a bill of charges and a periodic tax return are the same shape with a different label.

The ledger receipt does the same on a larger scale, with sixteen values including salary, employer contributions and a bank statement used as a receipt. Getting the type wrong produces a valid document of the wrong kind.

Two objects, two type lists, counted in the published specification on 28 August 2026
ObjectValues on its typeExamples
Invoice7Sales invoice, purchase order, periodic tax return
Ledger receipt16Journal, salary, employer contribution, VAT form

Two smaller things belong in the same section because they reach the same schema. First, an id is unique inside one company and nowhere else, so two companies can hold invoices with identical ids. Procountor names the company and the resource id together as the pair that is unique across the system.

Second, updating an invoice requires an invoiceVersion, which is a timestamp carried as a string. You send back the value you received, unchanged, or the write is rejected. It is optimistic concurrency wearing a date.

Through the common data model none of that reaches your product: the seven document kinds arrive as the objects they actually are, and the identifier question is answered before you see the record.

Both type lists counted in the published specification, version 26.08. The id rule and the company plus resource pairing from Procountor’s request and response conventions, checked 28 August 2026. The invoiceVersion requirement is stated on the field itself in the specification.

The data model

The rate and its code arrive in separate lists

This one is not in any documentation, and it is the reason this section exists. Asking Procountor for tax rates returns a response containing two arrays. One holds the percentages. The other holds the tax codes. Nothing in the response says which code belongs to which percentage.

Most accounting systems hand you a tax rate and its code as one object, and most data models are built that way, ours included. Against Procountor that model cannot be filled from a single response, so the pairing has to be established another way before any of it is usable.

One response, two lists, no key between themFrom the team that built it
First array
  • A percentage
  • A percentage
  • A percentage
Second array
  • A code
  • A code
  • A code
What the response does not carry

Nothing says which code belongs to which percentage. A model that pairs them cannot be filled from this response alone, which is the part that costs time.

Through Maesn it arrives as one list in the shared shape, with each entry carrying the rate or the code it came with. The relation stays unpublished, so nobody invents one.

The shape of the tax response as our own engineers found it. The labels stand for the form, because the values differ per company.

The cost of this one does not show up in any estimate, because nothing announces it. You call an endpoint, you get a valid response, and only when you try to map it does the gap appear.

Connecting through the Procountor API with Maesn changes the shape but not the fact. Tax data arrives as one list instead of two, in the same form every other connected system uses, and each entry carries the rate or the code it came with. The relation is not published by Procountor, so nobody downstream invents one, and a use case that needs the pairing establishes it deliberately.

This section rests on our own implementation, not on published documentation. Procountor documents neither the split nor a key between the two lists, and we could not find one in the specification either. Reported here because it is cheaper to read than to rediscover.

Change detection

Three events, and none of them on a document

Procountor publishes webhooks, and the list is short. Three event types exist: a payment was updated, a payment was deleted, a user was updated. Subscriptions are authenticated with HMAC over SHA512, and one webhook is allowed per event type.

For an accounting integration that reads accounts, contacts and tax rates, none of those three helps. Change detection is a read you schedule, and the interval is yours to choose.

Paging is thinner than the documentation suggests at first glance. Counted across the specification, 22 of 101 read operations carry paging parameters at all, in four different combinations, and the rest have none. Where paging exists there are two mechanisms, a cursor and a page number with a size that often defaults to fifty.

Our engineer added the practical half of that: some list endpoints return no total count, which he found on accounts. You can page through them, and you cannot tell in advance how far you have to go.

Filtering and ordering have to stay still

Procountor states that paging only works if the filtering and ordering stay constant between consecutive requests. A job that widens a filter halfway through a run does not return an error. It returns a page from a different result set.

The production request limit is 60 a second per client, and Procountor writes that exceeding it may result in suspending the service for that client. That is a firmer consequence than the usual rejected call, so it belongs in the design of the schedule instead of in the error handling.

Reading on a schedule across a catalogue of systems that each page differently is exactly the work that one way to filter and page removes. The loop you write once is the loop you point at the next system.

The three event types counted in the published specification, the HMAC and SHA512 rule, the paging mechanisms, the constant ordering requirement and the 60 requests a second from Procountor’s request and response conventions, checked 28 August 2026. The missing total count on accounts is our own engineer’s observation. What happens on exceeding the limit is not published, and we have not hit it.

Where our part ends

What Maesn covers, and what stays with you

Everything above is real work, and most of it is the same work for every customer you connect. That is the part to do once.

The division as it stands today
Handled hereStays with you
The authorisation flow and the company selectionWhich objects your use case needs
The one hour token and the six month refresh cycleTelling a customer their connection needs re-authorising
Tax data returned as one list in the shared shapePairing a rate with its code, where your use case needs it
Contacts joined from two endpoints into one shapeThe interval your schedule runs on
The document types resolved into real objectsYour own error handling and retries

The role question in that column is genuinely yours. Procountor sorts contacts into companies and people, and neither carries a field saying which side of an invoice they are on. A matching rule written against a system with separate customer and supplier objects needs adjusting here.

And the objects available today are a smaller set than the system as a whole. Accounts, contacts and tax rates have been readable since July, with posting for booking proposals and expenses added in August. The rest of Procountor, including a payroll surface larger than most of its accounting one, is not part of the connection today.

The live scope and its dates come from our own engineer and from our integration documentation, checked 28 August 2026. Procountor releases monthly and publishes discontinuation dates for older versions in its release notes, so the version you build against deserves a second look later.

FAQ

Frequently asked questions

Can a Procountor integration run without a person present?

Partly. An access token from the client credentials flow reaches most endpoints, and Procountor states that it reaches none of the ones requiring two-factor authentication, because those need a user who is actively present. Procountor's own example is that an integration may modify a purchase invoice while the payment for it needs a person to approve.

How long does a Procountor refresh token last?

Six months, and it does not rotate, so the value stays the same for that whole period. It ends early in four cases: the user changes their password, logs out through the logout endpoint, is removed from the company, or passes 100 logins. When that happens the stored token is invalid and the user has to authenticate again, because Procountor keeps a person in that step.

Why do two Procountor companies show the same record id?

Because an id is unique inside one company and not across the system. Procountor documents the company and the resource id together as the pair that is unique everywhere, so a store keyed on the resource id alone will collide as soon as a second company connects. Keep the company alongside it.

How do I page through a Procountor list endpoint?

Where paging exists there are two mechanisms, a previousId cursor and a page with a size, and size often defaults to 50. Counted in the specification, 22 of 101 read operations carry paging parameters at all, in four different combinations, so the endpoint decides. Filtering and ordering have to stay constant between calls.

What happens if I exceed Procountor's request limit?

Production allows 60 requests a second per client, and Procountor's documentation says exceeding it may result in suspending the service for that client. The exact response is not published and our own integration has not hit the ceiling, so treat the limit as a budget to stay inside instead of an error to handle.

Which Procountor version should I build against?

The latest one. Procountor releases monthly and keeps several versions available at once, with discontinuation dates published in its release notes. One change matters here: the person type on the business partners endpoint is marked for retirement, so contacts belong on the persons endpoint instead.

Do I need a partner status before I can build on Procountor?

No. You request a test environment with a form describing your integration, and production access is a second request of the same kind. Certification and the partner programme sit on top of that and are a commercial step, so they follow a working integration instead of gating one.

Build once on the Unified API.

Procountor splits its tax response in two, binds a connection to one company and stops the unattended flow at a second factor. The next system will draw every one of those lines somewhere else. Build against one interface and each difference turns into a field you read instead of a project you schedule.