Visena Documentation
Partner API

Guide

Getting started

Three moves take you from nothing to a real record in your own terminal: get a credential, exchange it for an access token, call the API. This page ends with you having made that call.

Everything is plain HTTPS and JSON over standard OAuth 2.0, so any language with an HTTP client works — and the examples below need nothing but curl and a shell. Read this page once end to end and you will have the shape of every request you ever send to the Partner API; the guides after it fill in the details.

The whole flow in three moves

There is no handshake to negotiate, no SDK to install and no session to keep alive. A credential identifies your integration, a token proves it for a while, and the token authorises each call. The three moves differ mainly in how long what they give you lasts, which is what decides where you keep it.

The three moves — credential, token, call — and what you keep from each one. Move 1 Get a credential in the Visena instance clientId + secret Move 2 Exchange for a token a standard OAuth 2.0 grant /auth/api/v1/token Move 3 Call the API read or write a record /api/v1/{locale}/person clientId clientSecret access_token as Bearer The secret in a secret manager lives until revoked The token in memory, reused expires_in 86399 s The data in your own system application/json All three moves run on your backend the secret and the token never reach a browser, a phone or any code you ship to end users
The three moves, and what each one leaves you holding: a credential that lasts until someone revokes it, a token that expires by itself, and data that belongs in your own system. The dashed lines are not calls — they are where the result of each move lives.
  1. Get a credential. A clientId and secret pair, created inside the customer's Visena instance by an administrator there. It identifies your integration and decides which user its calls act as — see Credentials and tokens.
  2. Exchange it for an access token. One standard OAuth 2.0 client_credentials request against /{instanceName}/auth/api/v1/token returns a short-lived bearer token with exactly the scopes you asked for. There is no refresh token: when it expires, ask again.
  3. Call the API. Send the token as Authorization: Bearer on every request. Create, read, update, delete, list and sync — the conventions are the same for all nine resources, and Making requests covers them.
i

Prefer screenshots? Credentials and tokens walks the same loop through the Visena interface, screen by screen, and Read-only access shows what a read-scoped token cannot do — with the 403 to prove it.

What you need before you start

Four values, and you have them all before you write a line of code. Every example on this page uses the placeholders in the right-hand column, so you can substitute yours once and copy the rest verbatim.

ValueWhat it isThe examples use
Base URL The host you were given during onboarding. Everything else hangs off it. https://api.visena.example
Instance name The short name of the customer's Visena instance, and the first segment of every URL you call. acme
Client id Identifies the API credential. Labelled Klient-ID (client id) in the Visena interface. acme-partner-3f9a
Client secret The credential's password — a vco_… value, shown once and stored only as a one-way hash. Labelled Klienthemmelighet (client secret). $CLIENT_SECRET

The credential itself is created by an administrator in the customer's own instance, under Admin → Tilgangskontroll (access control) → Administrer API-tilganger (manage API credentials). If someone has already handed you a client id and a secret, you have everything this page needs; if not, Credentials and tokens is the page to send them.

i

Was your credential created «på vegne av en annen»? An on-behalf credential (created for a named user rather than for the administrator themselves) holds the act-as-user:read and act-as-user:write scopes instead of plain read and write. Ask for those below, or the token request answers 400 invalid_scope. And if the credential was also created as read only, act-as-user:read alone is what it can mint. Concepts explains the difference between the two kinds.

Server-to-server only. Credentials and tokens belong on your backend. Never embed them in a mobile app, a browser page or any code you ship to end users — anyone holding the secret can act as your integration, with the permissions of the user it authenticates as.

A 60-second taste

Four commands in a terminal: set your values, exchange the credential for a token, then read the first page of people in the instance. Nothing is created or changed, and the token asks for read only, so this is safe to run against a live instance.

Set your values

Substitute the three values from the table above. The secret is read from a prompt rather than typed into the command, so it never lands in your shell history.

Terminal — your values
# The values from the table above — substitute your own.
export VISENA_BASE_URL="https://api.visena.example"
export VISENA_INSTANCE="acme"
export CLIENT_ID="acme-partner-3f9a"

# Prompt for the secret, so it stays out of your shell history.
read -rs -p "Client secret: " CLIENT_SECRET && echo
export CLIENT_SECRET

Get an access token

The token endpoint takes the credential over HTTP Basic — the form that belongs in production — and the standard client_credentials grant. scope is mandatory and has no default: state exactly what the token may do.

Terminal — 1. credential → token
curl -sS -X POST "$VISENA_BASE_URL/$VISENA_INSTANCE/auth/api/v1/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  -d "scope=read"
Response — 200 OK
{
  "access_token": "dcrEUVpMEpYqbdsDKawBb1yTqIAELMgqIO4KrN…",
  "scope": "read",
  "token_type": "Bearer",
  "expires_in": 86399
}

The token is opaque — do not parse it — and lives for expires_in seconds. Note that the response echoes the scope it actually granted; that is the value worth asserting in a test. A production integration mints one token, caches it and re-mints shortly before expiry, which Credentials and tokens shows with a cache you can copy.

Make the call

Paste the access_token from the response and send it as a bearer token. The path carries the instance name, the API version and a locale, then the resource — person, singular, like every resource in the API.

Terminal — 2. token → first call
# Paste the access_token from the response above.
export ACCESS_TOKEN="dcrEUVpMEpYqbdsDKawBb1yTqIAELMgqIO4KrN…"

# The first page of people in this instance.
curl -sS "$VISENA_BASE_URL/$VISENA_INSTANCE/api/v1/en/person?offset=0&limit=20" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response — 200 OK
{
  "totalItems": 428,
  "totalPages": 22,
  "page": 0,
  "size": 20,
  "items": [
    { "id": "xK9mQ2",
      "firstName": "Kari",
      "lastName": "Nordmann",
      "primaryEmail": "kari.nordmann@example.com",
      "isActive": true },
    …19 more…
  ],
  "links": { "self": "…", "next": "…/person?offset=20&limit=20" }
}

That is the entire model: credential → token → call. The ids are opaque strings like xK9mQ2 — store them exactly as received and echo them back verbatim rather than parsing or constructing them.

If the first call does not work

Failures are machine-readable, and the five below cover almost every first attempt. The token endpoint answers with the standard OAuth 2.0 error body; the API itself answers with an RFC 9457 problem document.

What you seeUsual cause
401 invalid_client from the token endpoint The client id and secret do not match, or the credential has been revoked. Check the pair; if it was rotated, deploy the new one.
400 invalid_scope No scope parameter, or a scope this credential does not hold — including asking an on-behalf credential for plain read.
404 from the token endpoint The instance name in the first path segment is unknown. Check that segment before anything else.
401 on the API call The token is missing, expired or revoked. Verify the Authorization: Bearer header, then mint a fresh token.
403 on the API call The token lacks the scope the method needs, or it was minted for a different instance than the one in the URL.

Every other status, the problem-document fields to log, and a retry policy that will not make things worse are in Errors and troubleshooting.

With that call answered, the rest is detail. Three pages, in the order most teams want them: