Guide 5 af 9
På denne side
Fejl og rate limits
Alle fejl er JSON og har mindst et message. Nogle har mere.
{ "message": "Unauthenticated." }Statuskoderne
| Kode | Betyder | Hvad du gør |
|---|---|---|
200 |
OK | |
401 |
Nøglen mangler, er ukendt, spærret eller udløbet | Stop. Genforsøg hjælper ikke |
403 |
Nøglen mangler et scope, eller abonnementet er udløbet | Stop. Se nedenfor |
404 |
Ressourcen findes ikke i din organisation, eller modulet er slået fra | Stop. Se nedenfor |
409 |
Kaldet strider mod en tilstand, ikke mod et felt | Stop. Ret tilstanden først |
422 |
Ugyldige parametre | Ret input |
429 |
For mange kald | Vent, og genforsøg efter Retry-After |
5xx |
Fejl hos os | Genforsøg med eksponentiel backoff |
Kun 429 og 5xx er værd at genforsøge automatisk. Alt andet er en fejl i kaldet, og et blindt genforsøg gør det bare til den samme fejl igen, hurtigere.
403 fortæller hvilket scope der mangler
{
"message": "Insufficient scope.",
"required_scope": "invoices:read"
}required_scope er der så din log kan sige "nøglen mangler invoices:read" i stedet for "adgang nægtet". Værdien er altid et navn fra scope-kataloget, aldrig fri tekst.
Den anden 403 er et udløbet abonnement. Den har intet required_scope, men et code:
{
"message": "The organisation has no active subscription.",
"code": "subscription_inactive"
}Den rammer kun skrivninger. GET bliver ved med at virke, så en virksomhed altid kan hente sine egne data ud. Se Autentificering og scopes.
404 er også svaret på "findes i en anden organisation"
Det her overrasker de fleste, og det er med vilje.
Slår du et id op der findes, men hører til en anden organisation, får du 404, ikke 403. Der er intet i svaret der skelner de to tilfælde fra hinanden.
Grunden er at 403 ville være en oplysning. "Du må ikke se den her" bekræfter at rækken eksisterer, og med et endpoint der svarer forskelligt på "findes ikke" og "findes, men ikke hos dig" kan man afprøve id'er indtil man har kortlagt en anden organisations sager. Det hedder et enumeration-hul, og den eneste sikre rettelse er at de to tilfælde ser ens ud.
Så i din fejlhåndtering: 404 betyder "ikke her". Læs det ikke som "slettet", og skriv ikke en oprydning der sletter lokale rækker på et enkelt 404.
409 betyder at noget skal gøres først
409 er ikke et ugyldigt felt. Det er et kald der er rigtigt skrevet, men forkert placeret i rækkefølgen, og de svar bærer et stabilt code du kan forgrene på.
{
"message": "A flow that is out for signature cannot be deleted. Cancel it first, which revokes the signers' links, then delete it.",
"code": "flow_must_be_cancelled_first"
}To steder giver det i dag:
| Kode | Sker når | Gør |
|---|---|---|
flow_must_be_cancelled_first |
DELETE på et underskriftsflow der er ude til underskrift |
Annullér flowet først. Det er annulleringen der spærrer underskrivernes links |
flow_must_be_draft |
Underskriverlisten ændres efter at flowet er sendt | Send en påmindelse eller byt en e-mail i stedet, eller annullér og start forfra |
Se Underskrifter. En Idempotency-Key genbrugt med en anden body giver også 409, og det er den samme slags fejl: kaldet strider mod noget der allerede er sket.
Et blindt genforsøg hjælper ingen af delene. Ret tilstanden, og kald så igen.
422 samler feltfejlene
{
"message": "The given data was invalid.",
"errors": {
"per_page": ["The per page must be an integer."]
}
}errors er et objekt med et feltnavn per nøgle og en liste af beskeder. Feltnavnene er dem fra forespørgslen, så du kan sætte dem direkte på din egen formular.
Nogle 422-svar bærer også et code ved siden af errors, når det der er galt er en tilstand frem for et felt. Det gælder hele underskriftsfladen, hvor flow_incomplete, flow_invalid_state og deres søskende fortæller præcis hvad der stod i vejen. Underskrifter har hele listen.
Rate limits
Grænsen tælles pr. nøgle, ikke pr. IP. Standard er 120 kald i minuttet. Flere servere bag samme nøgle deler altså puljen, og to nøgler fra samme maskine gør ikke.
Hvert autentificeret svar bærer status med:
| Header | Indhold |
|---|---|
X-RateLimit-Limit |
Kald tilladt i vinduet |
X-RateLimit-Remaining |
Kald tilbage i det nuværende vindue |
X-RateLimit-Reset |
Unix-tidsstempel for hvornår vinduet nulstilles |
Rammer du loftet, får du 429 og en Retry-After i sekunder.
import time, requests
def call(url, headers, attempt=1):
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 429 and attempt <= 5:
time.sleep(int(response.headers.get("Retry-After", 5)))
return call(url, headers, attempt + 1)
response.raise_for_status()
return response.json()Læs Retry-After frem for at gætte. Et fast sleep(1) i en løkke er den sikreste måde at holde sig selv i 429 resten af minuttet.
Vil du ikke ramme loftet i første omgang: hent større sider frem for flere. per_page=100 henter det samme som fire kald med per_page=25, for ét kald af budgettet.
Det uautentificerede endpoint /api/v1/openapi.json har sin egen, lavere grænse, fordi den ikke kan tælles pr. nøgle.
Hvad du ikke får i en fejl
Fejl indeholder ikke stack traces, interne id'er eller besked om hvilken organisation en ressource ellers ligger i. Kan du ikke se hvad der gik galt af message alene, så skriv til os med tidspunkt, endpoint og navnet på nøglen. Vi kan slå kaldet op i vores egne logs. Nøglens hemmelighed skal du ikke sende med.