Daichodo

Errors

Every error has the same shape. Five fields, always.

{
  "type": "https://daichodo.com/errors/not_found",
  "code": "not_found",
  "message": "No invoice issuer with registration number T8000000000001",
  "doc_url": "https://daichodo.com/docs/errors/#not_found",
  "request_id": "req_01J8XZ9Q7M4KDR"
}

code is the machine-readable identifier — branch on that, not on the status code. Two different errors share 429, and they need opposite handling.

message is a human-readable explanation and may change without notice. Do not parse it. type is a stable URI naming the error class. doc_url points at the section of this page for that exact code. Quote request_id when you contact us; it identifies the request in our logs.

A sixth field, details, appears on the codes that have one. It is absent entirely rather than null when there is nothing to put in it, so test for its presence rather than for a value.

Codes

HTTPcodeRetry?What it means
400invalid_numberNoThe number is malformed
401unauthorizedNoKey missing, wrong, or revoked
403plan_requiredNoThe capability needs a higher plan
404not_foundNoWell-formed, but not in the register
422invalid_requestNoThe request itself is malformed
429rate_limitedYesToo many calls this minute
429quota_exceededNoThe month's allowance is gone
5xxinternal_errorYesOurs

invalid_number — 400

The number is not a well-formed 法人番号 or 登録番号. message says which check failed, usually the check digit. Validate before you call and you will not see this — see validation, which is free and uncounted.

Distinct from not_found; see 400 versus 404.

unauthorized — 401

No key, a key that does not exist, or one that has been revoked. Retrying with the same key returns the same answer. Keys are at app.daichodo.com.

plan_required — 403

The key is valid and its plan does not include this capability. Terminal — retrying burns quota to reach the same answer. Carries details:

{
  "code": "plan_required",
  "message": "point_in_time requires the standard plan; this key is on the free plan.",
  "details": {
    "capability": "point_in_time",
    "required_plan": "standard",
    "current_plan": "free",
    "upgrade_url": "https://daichodo.com/pricing"
  }
}

Branch on required_plan rather than parsing the sentence. This is what lets an agent tell its user what to buy instead of retrying.

not_found — 404

The number is well-formed and no such record exists. This is a business answer, not a failure: that party is not a qualified invoice issuer.

A sole trader's record with name: null is not this. That is a found record — identity fields are stripped at source for individuals, and the dates are authoritative. See lookup.

invalid_request — 422

The request itself is malformed — a missing or unparseable parameter, a bad request body, a date that is not a date. message names the field. Unlike invalid_number, this is about the shape of the call rather than the value of the number.

rate_limited — 429

Too many calls this minute. Retryable once the window rolls. Carries details:

{
  "code": "rate_limited",
  "message": "Rate limit of 60 requests per minute exceeded. Retry in 12s.",
  "details": { "limit_per_minute": 60, "retry_after": 12 }
}

Honour retry_after rather than guessing a backoff. A Retry-After header carries the same number for anything that reads headers only.

quota_exceeded — 429

The month's allowance is spent. Not retryable, despite the 429 it shares with rate_limited — the answer is identical until the month rolls over or the plan changes. This is the reason to branch on code and not on status.

Only register lookups count. Validation is free and unmetered, checking your own quota does not count, and a lookup that finds nothing does not count either.

internal_error — 5xx

Ours. Retry with exponential backoff. message is deliberately generic; quote request_id and we can find the request.

400 versus 404

400 means "that is not a number". 404 means "that is a number, and it is not registered".

They are distinct because your response differs. The first is a bad input. The second is a business answer: that party is not a qualified invoice issuer.

Retrying

Retry 5xx and rate_limited, with exponential backoff, honouring retry_after where it is given.

Do not retry quota_exceeded, even though it is also a 429. Do not retry any other 4xx; they return the same thing.