API Error Codes
A complete reference for all error codes returned by the Yuki API. Use this guide to understand what went wrong and how to resolve it quickly.
A complete reference for all error codes returned by the Yuki API. Use this guide to understand what went wrong and how to resolve it quickly.
All errors returned by the Yuki API follow RFC 7807 – Problem Details for HTTP APIs. Understanding this structure helps you handle errors programmatically.
{
"type": "https://httpstatuses.com/400",
"title": "Validation Error",
"status": 400,
"detail": "Portal id cannot be empty.",
"instance": "/api/v1/portals/00000000-0000-0000-0000-000000000000",
"errors": {
"validation:invalid_input": [
"Portal id cannot be empty."
]
},
"traceId": "ad89db24d04645ed383f4b90c1913602",
"errorCode": "validation:invalid_input"
}
When a request is rejected field by field, the keys of errors are the names of the rejected fields instead of the error code. The errorCode stays the same, so read the keys rather than assuming they match it:
{
"type": "https://httpstatuses.com/400",
"title": "Validation Error",
"status": 400,
"detail": "One or more fields are invalid.",
"instance": "/api/v1/domains/3fa85f64-5717-4562-b3fc-2c963f66afa6/users",
"errors": {
"email": [
"The email field is not a valid email address."
],
"language": [
"The language klingon is not supported."
]
},
"traceId": "ad89db24d04645ed383f4b90c1913602",
"errorCode": "validation:invalid_input"
}
| Field | Type | Description |
|---|---|---|
type | string | A URI that identifies the error type. Points to the relevant HTTP status documentation. |
title | string | A short, human-readable summary of the error type. |
status | integer | The HTTP status code for this error. |
detail | string | A human-readable explanation of this specific occurrence. Sent on every error. |
instance | string | The request path the API received. Sent on every error. The gateway fronts the API, so this may differ from the URL you called. |
errors | object | A map of arrays of descriptive messages. The keys are the names of the rejected fields when the request failed field-level validation, and the errorCode otherwise. Present on errors raised while the request is being handled; absent from the 401 and the 403 produced before the operation runs. |
traceId | string | The 32-character trace id taken from the W3C Trace Context traceparent header — the id alone, not the whole header. Always include this when contacting support. |
errorCode | string | The stable feature:error_type identifier to branch on. Read it together with the HTTP status: a few codes are emitted with more than one status, listed below. |
The Yuki API uses standard HTTP status codes to indicate the outcome of each request.
| HTTP Status | Meaning | When it occurs |
|---|---|---|
200 OK | Success | The request was processed successfully and a response body is returned. |
201 Created | Resource created | A new resource was successfully created. |
204 No Content | Success, no body | The request succeeded but there is no response body (e.g. DELETE). |
400 Bad Request | Invalid request | The request is malformed, missing required fields, or contains invalid values. This is also the status of every validation failure, including the *:validation_failed codes below. |
401 Unauthorized | Authentication failure | The access token is missing, expired, or invalid. |
403 Forbidden | Authorization failure | The authenticated user does not have permission to perform this action. |
404 Not Found | Resource not found | The requested resource does not exist. |
409 Conflict | State conflict | The request conflicts with the current state of the resource. |
422 Unprocessable Entity | Not eligible | The request is understood, but the target is not eligible for the operation. Used only by the PEPPOL eligibility checks. |
429 Too Many Requests | Rate limit exceeded | The client has sent too many requests in a given time window. |
500 Internal Server Error | Server error | An unexpected condition occurred on the server side. |
502 Bad Gateway | Service down | The API is temporarily unavailable due to an upstream error (e.g., a dependency is down). Retry after a short delay. |
503 Service Unavailable | Service overloaded or maintenance | The API itself is overloaded or down for maintenance. Retry after a short delay. |
The following tables list all error codes grouped by category.
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
authentication:unauthorized | 401, sometimes 400 | The request is missing a valid access token, or the token is invalid or expired. | Include a valid Authorization: Bearer <token> header. Re-authenticate via Visma Connect to obtain a fresh token. The 400 variant carries the same meaning and the same remedy. |
authentication:forbidden | 403 | The authenticated user does not have permission to perform this action. | Verify that your application and user have been granted access to the requested resource in Yuki. |
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
validation:invalid_input | 400, sometimes 403 or 500 | The request contains one or more values the API cannot accept. | Check the errors map for the messages that describe what is wrong with each value. The 403 is returned when the tenant identifier in your token is not a valid identifier; the 500 means the invalid value was detected too late to be reported as a request error — report that one with its traceId. |
validation:missing_required_field | 400 | A required field is absent from the request body. | Ensure all required fields are included in your request payload. |
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
companies:not_found | 404 | The specified company (administration) does not exist. | Verify the administration ID and that it is accessible by your application. |
companies:validation_failed | 400 | The request to create or modify a company failed validation. | Check the errors map for details on which fields are invalid. |
peppol:already_registered | 409 | The PEPPOL identifier is already registered. | Verify the PEPPOL identifier and ensure it is unique before retrying. |
peppol:network_unavailable | 502 | The PEPPOL network is temporarily unavailable. | Retry the operation after a short delay. |
peppol:validation_failed | 400 | The PEPPOL request failed validation. | Check the errors map for details on which fields are invalid. |
peppol:domain_not_eligible | 422 | The domain is not eligible for PEPPOL, so its companies cannot be registered on the network. | Check that the domain is licensed for PEPPOL, then retry the request. |
peppol:sending_not_eligible | 422 | PEPPOL sending is not available for this domain, so the company cannot send documents over the network. | Sending requires a Small bundle or higher. Upgrade the bundle, then retry the request. |
peppol:portal_not_enabled | 422 | PEPPOL is not enabled for the accounting portal, so none of its companies can be registered on the PEPPOL network. | Contact Yuki to have PEPPOL enabled for the portal, then retry the request. |
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
domains:not_found | 404 | The specified domain does not exist. | Verify the domain identifier and that it belongs to the correct administration. |
domains:validation_failed | 400 | The domain request failed one or more validation rules. | Check the errors map for field-level validation messages. |
domains:creation_failed | 400, sometimes 500 | The domain could not be created. | Review the request payload and ensure it meets all domain creation requirements. A 500 means the domain was accepted but a later step of creating it failed on our side; report that one with its traceId rather than retrying. |
domains:update_failed | 500 | The domain was accepted for update but the update did not complete. | This is not a conflict you can resolve by changing the request. Retry after a short delay, and if it persists report it with its traceId. |
domains:already_exists | 409 | A domain with the requested name already exists, or the name is reserved. | Choose a different domain name and retry. |
domains:user_not_found | 404 | The specified user does not exist in this domain. | Verify the e-mail address, and that the user has access to this domain. |
domains:user_already_exists | 409 | The e-mail address already has access to this domain. | Read the existing user instead of creating it, or use a different e-mail address. |
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
portals:not_found | 404 | The specified portal does not exist. | Verify the portal identifier and that it is accessible by your application. |
portals:validation_failed | 400 | The portal request failed one or more validation rules. | Check the errors map for details on which fields are invalid. |
portals:user_not_found | 404 | The specified portal user does not exist. | Verify the user identifier or e-mail address, and that the user belongs to this portal. |
portals:user_already_exists | 409 | The e-mail address is already a user of this portal. | Read or update the existing user instead of creating it, or use a different e-mail address. |
portals:user_update_failed | 500 | The portal user was accepted for update but the update did not complete. | Retry after a short delay. If it persists, report it with its traceId. |
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
contacts:not_found | 404 | The specified contact does not exist. | Verify the contact identifier and that it is accessible by your application. |
contacts:cannot_be_deleted | 409 | The contact cannot be deleted because it is referenced by other records or is required by the system. | Remove any dependencies or references to the contact before attempting deletion. |
contacts:creation_failed | 500 | The contact was accepted but creating it did not complete. | Retry after a short delay. If it persists, report it with its traceId. |
contacts:update_failed | 500 | The contact was accepted for update but the update did not complete. | Retry after a short delay. If it persists, report it with its traceId. |
Rate limiting is enforced at the API gateway level and returns HTTP 429 Too Many Requests. These responses do not include an application-level errorCode field. Check the Retry-After response header for the number of seconds to wait before retrying. If you are consistently hitting rate limits, contact Yuki Support to review your quota.
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
server:internal_error | 500 | A known internal error occurred on the server. | This is not related to your request. Retry after a short delay. If the issue persists, contact Yuki Support and provide the traceId from the error response. |
server:unexpected_error | 500 | An unhandled exception occurred that does not map to a known error type. | Retry after a short delay. If the issue persists, contact Yuki Support and provide the traceId. |
Follow these best practices to handle API errors gracefully in your integration.
Use the HTTP status code as the primary signal to branch your error handling logic before inspecting the errorCode field.
const response = await fetch('https://apirest.yukiworks.be/v1/administrations', {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!response.ok) {
const body = await response.json();
console.error(`[${body.errorCode}] ${body.title} (traceId: ${body.traceId})`);
switch (body.errorCode) {
case 'authentication:unauthorized':
// Token missing, invalid or expired — redirect to login and re-authenticate
break;
case 'authentication:forbidden':
// User lacks permission — show access denied message
break;
case 'validation:invalid_input':
case 'validation:missing_required_field':
// Surface the per-field messages to the user
console.error(body.errors);
break;
case 'companies:not_found':
case 'domains:not_found':
case 'portals:not_found':
// Resource does not exist — handle gracefully
break;
default:
// Generic fallback — log traceId for support
console.error('traceId:', body.traceId);
break;
}
}
For transient errors (429, 503, 502), retry the request with exponential back-off.
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429 && response.status !== 503) {
return response;
}
// Wait before retrying: 1s, 2s, 4s ...
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Max retries reached');
}
Always log the traceId from error responses. Should you need to contact support, providing this value allows Yuki's team to investigate the exact request in question.
If you encounter an error not listed here, or if you believe a server error is impacting your integration, reach out to the Yuki support team.
traceId, the endpoint called, the request payload (redacted of sensitive data), and the timestamp of the error.