An integration lets your customers connect their Numina company to your product, so you can read their books or create invoices, contacts and journal entries on their behalf. Each customer approves the connection once with OAuth, and from then on you hold a token for that one company.
For a script against your own company, an API key is enough. This guide is for a product that many Numina companies connect to.
How it fits together
- You register an app in Numina and get a client ID and secret.
- Your customer clicks a “Connect Numina” button in your product, signs in to Numina, picks a company and approves your scopes.
- You store the tokens for that customer and call the API as the user who approved.
- The customer can disconnect at any time under Settings → API & apps in Numina.
Build it
Get a company to test against
Use your own Numina company, or write to support@numina.app for a sandbox company. A sandbox behaves like a real company, except that it cannot send invoices by email (Send invoice by email returns
403 forbidden) and it expires on a set date.Create a developer app
A company admin opens Settings → API & apps in that company and creates a new OAuth application. Give it the name your customers will see on the consent screen, your redirect URIs (
https, orhttp://localhostwhile you develop) and the scopes you need. The client secret is shown once.You can connect the app to the company that owns it and to a sandbox you are a member of, with any scope, booking included. That is all you need to build and test the whole flow.
Connect a company
Send the user through the authorization code flow with PKCE described in Authentication, then check the connection:
cURL curl https://api.numina.app/v1/me \ -H "Authorization: Bearer $ACCESS_TOKEN"Response { "user": { "id": "7d0c…", "email": "anna@example.dk", "first_name": "Anna", "last_name": "Holm" }, "company": { "id": "1b9a…", "name": "Fjordlys ApS", "slug": "fjordlys" }, "scopes": ["setup:read", "contacts:read", "contacts:write", "invoices:read", "invoices:write"], "auth_type": "oauth" }Store the access token, the refresh token and
company.idwith your customer’s account. Show the company name in your product, so the user can see which company is connected.Keep the connection alive
Access tokens last an hour and refresh tokens 30 days. Refresh tokens rotate, so save the new one every time you refresh, and make sure two of your workers never refresh the same token at once. A second refresh within 30 seconds gets the same new tokens, but after that a retired refresh token ends the connection.
A user can disconnect your app, and a refresh token can expire unused. Either way an API call returns
401 invalid_tokenand the refresh is refused. Mark the connection as broken in your product and ask the user to connect again; do not retry.Read the company's setup before you write
Account numbers, VAT codes and bank accounts differ from one company to the next. Read them from List accounts, List VAT codes and List bank accounts when a company connects, and let the user choose where your data goes rather than hard-coding numbers. The accounting model explains signs, VAT and drafts.
Write safely
- Send an
Idempotency-Keyon every create that supports one, and store Numina’sidnext to your own record. - Search before you create a contact: Create contact does not detect duplicates.
- Branch on the
errorcode, not the status or the description. See Errors. - There are no webhooks yet. To follow changes in Numina, poll the list endpoints and page through them.
- Send an
Go live
Make the app available to other companies in its settings, and your customers can connect it. An admin of the customer’s company approves, the consent screen says that Numina has not reviewed the app, and it works for up to 10 companies. It can hold booking scopes too: the consent screen then tells the admin that the app can book and that booking cannot be undone.
When more than 10 companies should connect it, write to support@numina.app with:
- the app’s name, website and a short description of what it does in Numina
- your production redirect URIs
- the scopes it needs, and why it needs each write or booking scope
We review the app and mark it as reviewed. It keeps its client ID, secret and the connections it has, so you change nothing. After that any number of Numina companies can connect it, any of their users can approve, and the consent screen shows you as a verified Numina partner instead of the note about review. Adding a redirect URI later sends the app back to unreviewed until we have looked at it again.
Good to know
- Limits are counted per connection, so each company connected to your app has its own 600 requests per minute, and your host’s shared IP addresses do not matter. See Rate limits.
- One connection is one company: a customer with several companies connects each one, and you hold a token per company.
- If the user who connected your app leaves the company, its requests return
404 not_found, and another member has to connect again. - Fuld Service customers cannot book through the API: booking calls return
403 booking_not_available, while drafts still work.