Skip to content

Getting started

Sandbox is a full mirror of production with synthetic bureau data and instant, deterministic financing decisions. Nothing there touches a real company register or moves real money.

Authentication

Request a token with your client credentials, then send it as a bearer token. Tokens last one hour — request a new one when it expires rather than on every call.

Request a token
curl -X POST https://api.noja.fi/partner/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grantType": "client_credentials",
    "clientId": "noja_live_7f2a...",
    "clientSecret": "••••••••",
    "scope": "clients:write invoices:write decisions:read"
  }'
Response
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "scope": "clients:write invoices:write decisions:read"
}
Use it
curl https://api.noja.fi/partner/v1/clients/NL/68123456 \
  -H "Authorization: Bearer $TOKEN"

Scopes

Scope Grants
clients:write Create clients, push onboarding data, submit applications
clients:read Read client state, credit limits, pricing, history coverage
invoices:write Send and update invoices, request financing
decisions:read Read financing decisions and settlement state
webhooks:manage Register and remove webhook endpoints

Request only the scopes you need. A token missing a scope returns 403 forbidden naming the one it lacked.

Your first call

Create a client. Both this call and the invoice call below work before any onboarding has happened — the invoice simply waits.

curl -X POST https://api.noja.fi/partner/v1/clients \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9c1e-onboard-68123456" \
  -d '{
    "countryCode": "NL",
    "registrationNumber": "68123456",
    "companyName": "Van Dijk Installatietechniek",
    "contact": {
      "firstName": "Sanne",
      "lastName": "van Dijk",
      "email": "sanne@vandijk-installatie.nl",
      "phone": "+31612345678"
    },
    "consent": {
      "obtainedAt": "2026-09-14T09:31:04Z",
      "method": "in_product_checkbox",
      "evidenceRef": "ptr-consent-4471a9"
    }
  }'

Your second call

Send one of that client's invoices as history.

curl -X POST https://api.noja.fi/partner/v1/invoices \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv-68123456-2026-0388" \
  -d '{
    "client": { "countryCode": "NL", "registrationNumber": "68123456" },
    "invoiceNumber": "2026-0388",
    "direction": "receivable",
    "counterparty": {
      "name": "Bouwgroep Rotterdam B.V.",
      "registrationNumber": "24398871",
      "countryCode": "NL"
    },
    "amount": { "amount": 312000, "currency": "EUR" },
    "issueDate": "2026-06-02",
    "dueDate": "2026-07-02",
    "paymentStatus": "paid",
    "paymentDate": "2026-07-11"
  }'

That is the whole integration in miniature. Everything else is volume, onboarding, and reacting to webhooks.

Sandbox behaviour

Sandbox is deterministic so you can write tests against it.

Input Sandbox response
Registration number starting 9999 Client is auto-approved on creation, with a €25,000 limit
Invoice amount ending .00 Financing approved
Invoice amount ending .13 Financing declined, reason debtor_risk
Any other amount Decision after roughly 30 seconds, approved
Registration number 99990000 Onboarding always completes instantly, no signing required

Sandbox never sends email, never calls a credit bureau, and never creates a real signing document.