Resource
Company
The companies (organisations) the instance works with. Full CRUD and a duplicate probe; an organisation number is unique per instance, and delete deactivates by default.
The endpoint reference below is kept in English in both language trees. It mirrors the API contract verbatim and there is no generator to rebuild it from, so a translated copy would drift from the API the first time an endpoint changes.
Endpoints
Nine endpoints, in the order they are documented below.
- POST
/company— Create a company - GET
/company/{companyId}— Get a company - GET
/company— List companies (offset-paginated) - GET
/company/cursor— List companies (cursor-paginated, insert-stable) - GET
/company/timeline— List companies (time-windowed, cursor-paginated) - GET
/company/duplicates— Search for potential duplicate companies - PUT
/company/{companyId}— Replace a company - PATCH
/company/{companyId}— Partially update a company (RFC 7396 JSON Merge Patch) - DELETE
/company/{companyId}— Delete or deactivate a company
Every endpoint on this page can additionally answer the shared errors — 401, 403, 404 (unknown instance) and 500. They are documented once, under Errors and troubleshooting.
Create a company
POST /{instanceName}/api/v1/{locale}/company
Creates a company and returns the full entity. 201 with a Location header.
Request body
application/json → CompanyCreateDto
Responses
| Status | Description |
|---|---|
| 201 | Company created. CompanyResponseDto · application/json |
| 400 | Request body failed validation. |
| 409 | The companyNumber or an organizational number is already used by another company. |
| 422 | A referenced entity (createdBy, modifiedBy, parent, ownerGroup, template, responsible, country, invoiceCompany, invoiceRecipient) does not exist. |
Example
curl -X POST "https://api.visena.example/acme/api/v1/en/company" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Logistics AS",
"countryCode": "NO",
"ownerGroupId": "gH8dF3",
"organizationalNumbers": [
{
"orgNumber": "923609016",
"countryCode": "NO"
}
]
}'
Get a company
GET /{instanceName}/api/v1/{locale}/company/{companyId}
Returns the full entity. 404 if unknown; 400 if the id cannot be unmasked.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
companyId required |
path | string |
Masked company id. |
Responses
| Status | Description |
|---|---|
| 200 | The company. CompanyResponseDto · application/json |
| 400 | The id is not a valid id. |
| 404 | No company with that id. |
Example
curl "https://api.visena.example/acme/api/v1/en/company/bQ4wR8" \
-H "Authorization: Bearer $TOKEN"
List companies (offset-paginated)
GET /{instanceName}/api/v1/{locale}/company
Offset/limit paging with a real total. Optional filters: query (name search), isActive, ownerGroupId, orgNumber (exact active org number), companyNumber (exact), externalReference (exact); and a created/modified/name sort. RFC 8288 navigation links are in the body. view selects the item projection: set view=full to receive, for every row, the same body the per-company read returns (createdBy/modifiedBy and the AML triad included) instead of the lean list item; allowed values are lean and full, the default is lean, and view=full caps limit at 100.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
offset |
query | integerdefault 0 |
Zero-based item offset. |
limit |
query | integer |
Maximum items to return per page. |
query |
query | string |
Free-text filter; the endpoint description lists the fields it matches. |
isActive |
query | boolean |
Filter on active state. |
ownerGroupId |
query | string |
Masked owner-group id. |
orgNumber |
query | string |
Exact organisation-number filter. |
companyNumber |
query | string |
Exact company-number filter. |
externalReference |
query | string |
Exact external-reference filter. |
sort |
query | string |
Sort key; the endpoint description lists the allowed values. |
view |
query | string, one of lean fulldefault lean |
Item projection: lean (default) for the compact list item, full for the same body the per-company read returns. full caps limit at 100. |
Responses
| Status | Description |
|---|---|
| 200 | A page of companies with totals and navigation links. CompanyOffsetListResponse · application/json |
| 400 | Invalid paging or sort parameter, or a filter id is not a valid id. |
| 404 | Under view=full, a company on this page no longer exists (permanently removed between the page query and the record read). Retry the request. |
Example
curl "https://api.visena.example/acme/api/v1/en/company?offset=0&limit=20" \
-H "Authorization: Bearer $TOKEN"
List companies (cursor-paginated, insert-stable)
GET /{instanceName}/api/v1/{locale}/company/cursor
Keyset paging over the monotonic entity id (insertion order). Pass the opaque cursor from a previous page's nextCursor/prevCursor; omit it for the first page. No total — keyset skips the count. Same filters as the offset list: query, isActive, ownerGroupId, orgNumber, companyNumber, externalReference. view selects the item projection: set view=full to receive, for every row, the same body the per-company read returns (createdBy/modifiedBy and the AML triad included) instead of the lean list item; allowed values are lean and full, the default is lean, and view=full caps limit at 100.
The offset, cursor and timeline lists are three different read modes. Which one to use for a one-off extract and which one to resume an ongoing synchronisation from, how to de-duplicate what you receive, and what a list response does not tell you about deletions, are documented once for the whole API under Lists, paging and sync. Read it before building a synchronisation on any of them.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
cursor |
query | string |
Opaque page cursor from the previous response's links.next; omit for the first page. |
limit |
query | integer |
Maximum items to return per page. |
query |
query | string |
Free-text filter; the endpoint description lists the fields it matches. |
isActive |
query | boolean |
Filter on active state. |
ownerGroupId |
query | string |
Masked owner-group id. |
orgNumber |
query | string |
Exact organisation-number filter. |
companyNumber |
query | string |
Exact company-number filter. |
externalReference |
query | string |
Exact external-reference filter. |
view |
query | string, one of lean fulldefault lean |
Item projection: lean (default) for the compact list item, full for the same body the per-company read returns. full caps limit at 100. |
Responses
| Status | Description |
|---|---|
| 200 | A page of companies with next/prev cursors and links. CompanyCursorListResponse · application/json |
| 400 | Invalid or expired cursor, or invalid limit. |
| 404 | Under view=full, a company on this page no longer exists (permanently removed between the page query and the record read). Retry the request. |
Example
curl "https://api.visena.example/acme/api/v1/en/company/cursor?limit=100" \
-H "Authorization: Bearer $TOKEN"
List companies (time-windowed, cursor-paginated)
GET /{instanceName}/api/v1/{locale}/company/timeline
Keyset paging from an optional since lower bound on a selectable key (created|modified). RFC 9557 Z timestamps. A cursor minted for a different key is rejected with 400. view selects the item projection: set view=full to receive, for every row, the same body the per-company read returns (createdBy/modifiedBy and the AML triad included) instead of the lean list item; allowed values are lean and full, the default is lean, and view=full caps limit at 100.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
since |
query | string (date-time) |
Inclusive lower bound — an RFC 3339 timestamp. |
key |
query | string |
Which timestamp to page on: created or modified. |
cursor |
query | string |
Opaque page cursor from the previous response's links.next; omit for the first page. |
limit |
query | integer |
Maximum items to return per page. |
view |
query | string, one of lean fulldefault lean |
Item projection: lean (default) for the compact list item, full for the same body the per-company read returns. full caps limit at 100. |
Responses
| Status | Description |
|---|---|
| 200 | A page of companies with next/prev cursors and links. CompanyCursorListResponse · application/json |
| 400 | Invalid timestamp, key, cursor, or limit. |
| 404 | Under view=full, a company on this page no longer exists (permanently removed between the page query and the record read). Retry the request. |
Example
curl "https://api.visena.example/acme/api/v1/en/company/timeline?since=2026-08-20T02:00:00Z" \
-H "Authorization: Bearer $TOKEN"
Search for potential duplicate companies
GET /{instanceName}/api/v1/{locale}/company/duplicates
Duplicate-detection probe for the create flow. Matches by exact organizational number (active numbers only) and/or exact companyNumber — the same identifiers the create/update 409 guard checks, so a hit here predicts that conflict and shows the holding company when the caller is allowed to see it. At least one of orgNumber or companyNumber is required. Org-number matches are listed first; results are capped by limit (default 20; values above 100 are clamped to 100).
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
orgNumber |
query | string |
Exact organisation-number filter. |
companyNumber |
query | string |
Exact company-number filter. |
limit |
query | integer |
Maximum items to return per page. |
Responses
| Status | Description |
|---|---|
| 200 | The potential duplicates (empty when none match). CompanyDuplicateListResponse · application/json |
| 400 | No search signal (orgNumber/companyNumber both absent) or a limit below 1. |
Example
curl "https://api.visena.example/acme/api/v1/en/company/duplicates?orgNumber=923609016" \
-H "Authorization: Bearer $TOKEN"
Replace a company
PUT /{instanceName}/api/v1/{locale}/company/{companyId}
Full replace (PUT): omitted optional fields are cleared.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
companyId required |
path | string |
Masked company id. |
Request body
application/json → CompanyUpdateDto
Responses
| Status | Description |
|---|---|
| 200 | The replaced company. CompanyResponseDto · application/json |
| 400 | Request body failed validation, or the id is not a valid id. |
| 404 | No company with that id. |
| 409 | The companyNumber or an organizational number is already used by another company. |
| 422 | A referenced entity (modifiedBy, parent, ownerGroup, template, responsible, country, invoiceCompany, invoiceRecipient) does not exist. |
Example
curl -X PUT "https://api.visena.example/acme/api/v1/en/company/bQ4wR8" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Logistics AS",
"countryCode": "NO",
"ownerGroupId": "gH8dF3",
"organizationalNumbers": [
{
"orgNumber": "923609016",
"countryCode": "NO"
}
]
}'
Partially update a company (RFC 7396 JSON Merge Patch)
PATCH /{instanceName}/api/v1/{locale}/company/{companyId}
Absent fields are unchanged, JSON null clears, a value sets. An empty body {} is a no-op. Wrong content type → 415.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
companyId required |
path | string |
Masked company id. |
Request body
application/merge-patch+json → object
Responses
| Status | Description |
|---|---|
| 200 | The updated company. CompanyResponseDto · application/json |
| 400 | A patched field had an invalid value, or the id is not a valid id. |
| 404 | No company with that id. |
| 409 | The companyNumber or an organizational number is already used by another company. |
| 415 | Content-Type was not application/merge-patch+json. |
| 422 | A referenced entity (modifiedBy, parent, ownerGroup, template, responsible, country, invoiceCompany, invoiceRecipient) does not exist. |
Example
curl -X PATCH "https://api.visena.example/acme/api/v1/en/company/bQ4wR8" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-d '{
"externalReference": "ERP-4711",
"riskValue": "LOW"
}'
Delete or deactivate a company
DELETE /{instanceName}/api/v1/{locale}/company/{companyId}
mode=deactivate (default) sets the company inactive; mode=delete hard-deletes it. 204 on success; a repeat hard-delete → 404.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
companyId required |
path | string |
Masked company id. |
mode |
query | stringdefault deactivate |
Delete mode; the endpoint description explains the options and the default. |
Responses
| Status | Description |
|---|---|
| 204 | Company deleted or deactivated; no body. |
| 400 | The id is not a valid id, or mode was not deactivate/delete. |
| 404 | No company with that id (or already deleted). |
Example
curl -X DELETE "https://api.visena.example/acme/api/v1/en/company/bQ4wR8?mode=deactivate" \
-H "Authorization: Bearer $TOKEN"
Object shapes
The request and response bodies used above, in the order they are first referenced.
CompanyCreateDto
| Field | Type | Description |
|---|---|---|
name required |
string |
Company display name. Required. |
companyNumber |
string |
Internal company number. |
externalReference |
string |
External reference / foreign system key. |
dunsNumber |
string |
D-U-N-S number. |
mainPhone |
string |
Main switchboard phone. Digits, spaces, +, -, ( ) only. |
mobilePhone |
string |
Mobile phone. Digits, spaces, +, -, ( ) only. |
fax |
string |
Fax. Digits, spaces, +, -, ( ) only. |
email |
string |
Company email address. |
homePage |
string |
Company home page URL. |
postAddress |
string |
Postal address line 1. |
postAddress2 |
string |
Postal address line 2. |
postZipCode |
string |
|
postPlace |
string |
|
postCity |
string |
|
visitAddress |
string |
Visiting address line 1. |
visitAddress2 |
string |
Visiting address line 2. |
visitZipCode |
string |
|
visitPlace |
string |
|
visitCity |
string |
|
isInvoiceAddressOverridden |
object |
Whether the invoice address overrides post/visit; when false the invoice address is derived. |
invoiceAddress |
string |
Invoice address line 1. |
invoiceAddress2 |
string |
Invoice address line 2. |
invoiceZipCode |
string |
|
invoicePlace |
string |
|
invoiceCity |
string |
|
countryCode required |
string, one of NO SE DK GB CH |
ISO 3166-1 alpha-2 country code (see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). Required. Resolved server-side; unknown → 422. |
parentId |
string (masked id) |
|
ownerGroupId required |
string (masked id) |
|
templateId |
string (masked id) |
|
responsiblePersonId |
string (masked id) |
|
invoiceCompanyId |
string (masked id) |
|
invoiceRecipientId |
string (masked id) |
|
invoiceCountryCode |
string, one of NO SE DK GB CH |
ISO 3166-1 alpha-2 invoice country code. Resolved server-side; unknown → 422. |
isActive |
object |
|
isPrivate |
object |
|
isPublicAccess |
object |
Whether the company is visible across the tenant (public access). |
newProjectsDefaultAccessControlled |
object |
Whether new projects on this company default to access-controlled. |
riskValue |
string, one of NOT_ASSESSED LOW MEDIUM HIGH NOT_APPLICABLE |
|
pepValue |
string, one of NOT_ASSESSED YES YES_EXPIRED NO DONT_KNOW NOT_APPLICABLE |
|
sanctionValue |
string, one of NOT_ASSESSED YES NO NOT_APPLICABLE |
|
organizationalNumbers |
array of OrgNumberWriteDto | Organizational (registration) number — at most one (Visena keeps a single active number per company); >1 entry is rejected with 400. Empty or omitted sets none. |
created |
string (date-time) |
override: creation timestamp to attribute. Defaults to server-now (UTC) when absent. |
createdBy |
string (masked id) |
|
modified |
string (date-time) |
override: modification timestamp (set alongside creation when provided). |
modifiedBy |
string (masked id) |
OrgNumberWriteDto
Organizational (registration) number — at most one (Visena keeps a single active number per company); >1 entry is rejected with 400. Full replace: omitted or empty clears it.
| Field | Type | Description |
|---|---|---|
orgNumber required |
string |
The organizational (registration) number. Validated per country (Norway: 9 digits, mod-11 checksum); an invalid number is rejected 400. |
countryCode required |
string |
ISO 3166-1 alpha-2 country code the number is registered in, e.g. "NO". Resolved server-side; unknown → 422. |
CompanyResponseDto
| Field | Type | Description |
|---|---|---|
id |
string (masked id) |
|
name |
string |
|
companyNumber |
string |
|
externalReference |
string |
|
dunsNumber |
string |
|
organizationalNumbers |
array of OrgNumberDto | Active organizational (registration) numbers; at most one per company. |
mainPhone |
string |
|
mobilePhone |
string |
|
fax |
string |
|
email |
string |
|
homePage |
string |
|
postAddress |
string |
|
postAddress2 |
string |
|
postZipCode |
string |
|
postPlace |
string |
|
postCity |
string |
|
visitAddress |
string |
|
visitAddress2 |
string |
|
visitZipCode |
string |
|
visitPlace |
string |
|
visitCity |
string |
|
isInvoiceAddressOverridden |
boolean |
|
invoiceAddress |
string |
|
invoiceAddress2 |
string |
|
invoiceZipCode |
string |
|
invoicePlace |
string |
|
invoiceCity |
string |
|
country |
CountryRefDto | |
invoiceCountry |
CountryRefDto | |
parent |
CompanyRefDto | |
invoiceCompany |
CompanyRefDto | |
ownerGroup |
GroupRefDto | |
responsible |
string (masked id) |
|
invoiceRecipientId |
string (masked id) |
|
templateId |
string (masked id) |
|
isActive |
boolean |
|
isPrivate |
boolean |
|
isPublicAccess |
boolean |
|
newProjectsDefaultAccessControlled |
boolean |
|
riskValue |
string, one of NOT_ASSESSED LOW MEDIUM HIGH NOT_APPLICABLE |
|
pepValue |
string, one of NOT_ASSESSED YES YES_EXPIRED NO DONT_KNOW NOT_APPLICABLE |
|
sanctionValue |
string, one of NOT_ASSESSED YES NO NOT_APPLICABLE |
|
created |
string (date-time) |
Creation timestamp (UTC). |
createdBy |
string (masked id) |
|
modified |
string (date-time) |
Last-modification timestamp (UTC); null until first modified. |
modifiedBy |
string (masked id) |
|
actedBy |
string (masked id) |
OrgNumberDto
Active organizational (registration) numbers; at most one per company.
| Field | Type | Description |
|---|---|---|
orgNumber |
string |
The organizational (registration) number. |
country |
CountryRefDto |
CountryRefDto
Country this organizational number is registered in.
| Field | Type | Description |
|---|---|---|
id |
string (masked id) |
|
name |
string |
Country display name. |
code |
string |
ISO 3166-1 alpha-2 country code, e.g. "NO". |
CompanyRefDto
The company the owning project belongs to, if any.
| Field | Type | Description |
|---|---|---|
id |
string (masked id) |
|
name |
string |
Company display name. |
organizationalNumbers |
array of OrgNumberDto | Active organizational (registration) numbers; at most one per company. |
GroupRefDto
Owning group / department.
| Field | Type | Description |
|---|---|---|
id |
string (masked id) |
|
name |
string |
Group display name. |
CompanyOffsetListResponse
| Field | Type | Description |
|---|---|---|
totalItems |
integer |
Total number of matching companies. |
totalPages |
integer |
Total number of pages at the current page size. |
page |
integer |
Zero-based index of the current page. |
size |
object |
Page size actually applied. |
items |
array of CompanyListItem | The companies on this page, in the projection selected by view. |
links |
CompanyListLinks |
CompanyListItem
A company as returned by a list operation. Which of the two shapes is returned is chosen by the view query parameter: lean (the default) yields the compact list item, full yields the same body the per-company read returns.
No fields of its own: the shape is either CompanyListItemDto (view=lean) or CompanyResponseDto (view=full).
CompanyListItemDto
| Field | Type | Description |
|---|---|---|
id |
string (masked id) |
|
name |
string |
Company display name. |
organizationalNumbers |
array of OrgNumberDto | Organizational (registration) numbers. The list endpoint carries the company's single active number. |
companyNumber |
string |
Internal company number, if any. |
mainPhone |
string |
Main switchboard phone. |
email |
string |
Company email address. |
country |
CountryRefDto | |
ownerGroup |
GroupRefDto | |
isActive |
boolean |
Whether the company is active. |
isPrivate |
boolean |
Whether the company is private. |
riskValue |
string, one of NOT_ASSESSED LOW MEDIUM HIGH NOT_APPLICABLE |
|
pepValue |
string, one of NOT_ASSESSED YES YES_EXPIRED NO DONT_KNOW NOT_APPLICABLE |
|
sanctionValue |
string, one of NOT_ASSESSED YES NO NOT_APPLICABLE |
|
created |
string (date-time) |
Creation timestamp (UTC). |
modified |
string (date-time) |
Last-modification timestamp (UTC); null until first modified. |
CompanyListLinks
RFC 8288 navigation links.
| Field | Type | Description |
|---|---|---|
self |
string |
URL of the current page. |
first |
string |
URL of the first page (offset endpoint). |
prev |
string |
URL of the previous page, if any. |
next |
string |
URL of the next page, if any. |
last |
string |
URL of the last page (offset endpoint). |
CompanyCursorListResponse
| Field | Type | Description |
|---|---|---|
items |
array of CompanyListItem | The companies on this page, in ascending key order, in the projection selected by view. |
nextCursor |
string |
Opaque cursor for the next page; absent on the last page. |
prevCursor |
string |
Opaque cursor for the previous page; absent on the first page. |
links |
CompanyListLinks |
CompanyDuplicateListResponse
| Field | Type | Description |
|---|---|---|
items |
array of CompanyListItemDto | Potential duplicate companies, org-number matches before companyNumber matches. |
CompanyUpdateDto
| Field | Type | Description |
|---|---|---|
name required |
string |
Company display name. Required. |
companyNumber |
string |
Internal company number. |
externalReference |
string |
External reference / foreign system key. |
dunsNumber |
string |
D-U-N-S number. |
mainPhone |
string |
Main switchboard phone. Digits, spaces, +, -, ( ) only. |
mobilePhone |
string |
Mobile phone. Digits, spaces, +, -, ( ) only. |
fax |
string |
Fax. Digits, spaces, +, -, ( ) only. |
email |
string |
Company email address. |
homePage |
string |
Company home page URL. |
postAddress |
string |
Postal address line 1. |
postAddress2 |
string |
Postal address line 2. |
postZipCode |
string |
|
postPlace |
string |
|
postCity |
string |
|
visitAddress |
string |
Visiting address line 1. |
visitAddress2 |
string |
Visiting address line 2. |
visitZipCode |
string |
|
visitPlace |
string |
|
visitCity |
string |
|
isInvoiceAddressOverridden |
object |
Whether the invoice address overrides post/visit; when false the invoice address is derived. |
invoiceAddress |
string |
Invoice address line 1. |
invoiceAddress2 |
string |
Invoice address line 2. |
invoiceZipCode |
string |
|
invoicePlace |
string |
|
invoiceCity |
string |
|
countryCode required |
string, one of NO SE DK GB CH |
ISO 3166-1 alpha-2 country code (see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). Required. Resolved server-side; unknown → 422. |
parentId |
string (masked id) |
|
ownerGroupId required |
string (masked id) |
|
templateId |
string (masked id) |
|
responsiblePersonId |
string (masked id) |
|
invoiceCompanyId |
string (masked id) |
|
invoiceRecipientId |
string (masked id) |
|
invoiceCountryCode |
string, one of NO SE DK GB CH |
ISO 3166-1 alpha-2 invoice country code. Resolved server-side; unknown → 422. |
isActive |
object |
|
isPrivate |
object |
|
isPublicAccess |
object |
Whether the company is visible across the tenant (public access). |
newProjectsDefaultAccessControlled |
object |
Whether new projects on this company default to access-controlled. |
riskValue |
string, one of NOT_ASSESSED LOW MEDIUM HIGH NOT_APPLICABLE |
|
pepValue |
string, one of NOT_ASSESSED YES YES_EXPIRED NO DONT_KNOW NOT_APPLICABLE |
|
sanctionValue |
string, one of NOT_ASSESSED YES NO NOT_APPLICABLE |
|
organizationalNumbers |
array of OrgNumberWriteDto | Organizational (registration) number — at most one (Visena keeps a single active number per company); >1 entry is rejected with 400. Full replace: omitted or empty clears it. |
created |
string (date-time) |
Audit override: creation timestamp. Immutable on update — ignored. |
createdBy |
string (masked id) |
|
modified |
string (date-time) |
Audit override: modification timestamp to attribute. Defaults to server-now (UTC) when absent. |
modifiedBy |
string (masked id) |