Guider
Fel
Alla fel från /api/v1 kommer som application/problem+json enligt RFC 9457. Formen är alltid densamma, så ett program kan hantera alla fel på ett ställe.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
X-Request-Id: 7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17
{
"type": "urn:nonox:problem:validation_failed",
"title": "Unprocessable Content",
"status": 422,
"code": "validation_failed",
"detail": "Uppgifterna kunde inte godtas. Se errors.",
"instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
"errors": {
"rows": ["Verifikationen balanserar inte: debet och kredit skiljer sig åt."],
"voucher_date": ["Det finns inget räkenskapsår som omfattar 2031-01-01."]
}
}Fälten
| Fält | Innehåll |
|---|---|
type |
urn:nonox:problem:<code>. |
title |
HTTP-statusens korta engelska namn. |
status |
HTTP-statusen. |
code |
Styr på den här. Stabil och maskinläsbar; ändras aldrig inom v1. |
detail |
En svensk förklaring för människor. Kan ändras; styr aldrig på den. |
instance |
urn:nonox:request:<uuid>, samma id som svarshuvudet X-Request-Id. Uppge det vid supportfrågor. |
errors |
Bara vid 422 validation_failed: felen per fält. |
required_scopes |
Bara vid 403 insufficient_scope: behörigheterna som behövs. |
Ett serverfel (500) avslöjar aldrig orsaken, bara instance.
Alla koder
Listan genereras från OpenAPI-filen, så den är alltid komplett.
| Status | Kod | Betyder |
|---|---|---|
| 400 | idempotency_key_invalid |
Idempotency-Key too long or not visible ASCII detail: ”Idempotency-Key ska vara 1–255 synliga ASCII-tecken.” |
| 400 | idempotency_key_required |
No Idempotency-Key on a POST detail: ”Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.” |
| 400 | invalid_json |
Malformed JSON detail: ”Kroppen är inte giltig JSON (ett objekt).” |
| 401 | unauthenticated |
No valid credential detail: ”Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.” |
| 403 | app_not_allowed |
The company no longer allows the app detail: ”Företaget tillåter inte längre den här appen.” |
| 403 | company_archived |
Write to an archived company detail: ”Företaget är arkiverat och kan bara läsas.” |
| 403 | forbidden |
The action refuses (for example changing a posted voucher) detail: ”Behörighet saknas för det här.” |
| 403 | insufficient_scope |
Scope missing or permission lost detail: ”Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.” |
| 403 | ip_not_allowed |
Outside the IP allowlist detail: ”Företaget tillåter inte anrop från den här adressen.” |
| 404 | not_found |
Unknown id, other company's id, or module off detail: ”Det du söker finns inte.” |
| 409 | idempotency_in_progress |
Same key, first request not finished detail: ”En begäran med samma Idempotency-Key pågår. Vänta och försök igen.” |
| 415 | unsupported_media_type |
Wrong Content-Type detail: ”Skicka JSON (application/json).” |
| 422 | idempotency_key_reused |
Same key, different body detail: ”Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.” |
| 422 | validation_failed |
Field errors detail: ”Uppgifterna kunde inte godtas. Se errors.” |
| 429 | rate_limited |
Over the limit detail: ”För många anrop. Försök igen om 23 sekunder.” |
Vad programmet ska göra
| Status | Gör så här |
|---|---|
400 |
Rätta anropet. Oftast saknas Idempotency-Key eller så är kroppen inte ett JSON-objekt. |
401 |
Förnya access token (OAuth) och försök en gång till. Ger det 401 igen, eller invalid_grant vid förnyelsen, har anslutningen återkallats: be personen ansluta igen. För en API-nyckel: nyckeln har gått ut eller återkallats. |
403 |
Försök inte igen. Läs code: en behörighet saknas, adressen är inte tillåten, företaget är arkiverat eller tillåter inte längre appen. |
404 |
Posten finns inte, tillhör ett annat företag, eller så är NONOX Connect avstängt för företaget. API:t skiljer medvetet inte på dem. |
409 |
Ett anrop med samma Idempotency-Key pågår. Vänta Retry-After sekunder och försök igen med samma nyckel. |
415 |
Skicka Content-Type: application/json (eller multipart/form-data för underlag). |
422 |
Rätta uppgifterna efter errors, eller använd en ny Idempotency-Key för en ny åtgärd. |
429 |
Vänta Retry-After sekunder. Se Gränser för anrop. |
5xx |
Försök igen med samma Idempotency-Key och ökande väntetid. |
Ett exempel på felhantering
use Illuminate\Http\Client\RequestException;
try {
$voucher = Http::withToken(config('services.nonox.token'))
->withHeaders(['Idempotency-Key' => $key])
->post('https://nonox.app/api/v1/vouchers/'.$id.'/post')
->throw()
->json('data');
} catch (RequestException $exception) {
$problem = $exception->response->json();
match ($problem['code'] ?? null) {
'validation_failed' => $this->showErrors($problem['errors']),
'insufficient_scope' => $this->askForScopes($problem['required_scopes']),
'company_archived' => $this->markReadOnly(),
default => report($exception),
};
}const response = await fetch(`https://nonox.app/api/v1/vouchers/${id}/post`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.NONOX_TOKEN}`, 'Idempotency-Key': key },
});
if (!response.ok) {
const problem = await response.json();
switch (problem.code) {
case 'validation_failed': showErrors(problem.errors); break;
case 'insufficient_scope': askForScopes(problem.required_scopes); break;
default: throw new Error(`${problem.code} (${problem.instance})`);
}
}response = requests.post(
f"https://nonox.app/api/v1/vouchers/{voucher_id}/post",
headers={"Authorization": f"Bearer {os.environ['NONOX_TOKEN']}", "Idempotency-Key": key},
timeout=30,
)
if not response.ok:
problem = response.json()
if problem["code"] == "validation_failed":
show_errors(problem["errors"])
elif problem["code"] == "insufficient_scope":
ask_for_scopes(problem["required_scopes"])
else:
raise RuntimeError(f"{problem['code']} ({problem['instance']})")Fel från OAuth
Tokenadressen (/oauth/token) svarar i OAuths eget format (error, error_description), inte med problem+json. Se Autentisering.