API Reference
Error codes Every error.code the LearnCoin API can return, what it means, and how to recover.
Every non-2xx response shares this body shape:
{
"error" : {
"code" : "credential_not_found" ,
"message" : "Human-readable description of what went wrong." ,
"request_id" : "req_01HXYZABCDEF"
}
}
The request_id is also returned in the X-Request-Id response header. Include it when contacting support — it's the fastest way to pin down a specific call in our audit log.
error.codeCause Fix api_key_missingNo Authorization header on the request. Send Authorization: Bearer lrn_test_…. api_key_invalidMalformed key, wrong prefix, or unknown key. Re-check the key. New keys: [email protected] . api_key_revokedKey existed but was explicitly revoked. Rotate to a new key. ip_not_allowedKey has IP allowlisting; request source isn't allowlisted. Add the source IP to the key's allowlist in the admin console.
error.codeCause Fix environment_mismatchlrn_test_ key used on a mainnet-only endpoint.Use a lrn_live_ key or switch endpoint. tier_requiredFeature needs a higher plan (e.g. custom DID on Institution). Upgrade plan or remove the feature flag. credential_not_ownedTenant A trying to mutate Tenant B's credential. Use a key scoped to the owning tenant.
error.codeCause Fix invalid_jsonRequest body isn't valid JSON. Validate your JSON payload. missing_required_fieldA required field is absent. error.message names the missing field.invalid_field_formatA field is present but malformed (e.g. issuanceDate isn't ISO 8601). error.message names the field + expected format.recipient_id_invalidrecipient.id isn't a urn:uuid:… form.Use urn:uuid:<v4 UUID>. achievement_too_largeAchievement payload exceeds 64 KB. Trim or split into multiple credentials. batch_too_largeMore than 500 credentials in one batch. Split across multiple POST /v1/batches calls. alignment_framework_unknownalignment[].targetFramework isn't in the supported list.Use ESCO, O*NET, ISCED-F, or CUSTOM.
error.codeCause batch_not_foundNo batch with that ID exists for this tenant. credential_not_foundNo credential with that ID. webhook_not_foundNo webhook endpoint with that ID. tenant_not_foundTenant lookup by ID failed.
error.codeCause Fix idempotency_key_reusedSame Idempotency-Key used for a different request body. Change the key, or resend the original body. credential_already_revokedTrying to revoke a credential that's already revoked. Skip the call; the state is already what you want. credential_already_erasedTrying to erase a credential that's already erased. Skip the call.
error.codeCause rate_limitedToo many requests per minute. See Retry-After header for seconds until retry.
Default limit: 120 requests / minute / tenant across all endpoints. Institution and Industry tiers have higher limits. POSTs that spawn background work (e.g. /v1/batches) count as one request regardless of batch size.
Surface only from POST /v1/batches when the payload is syntactically valid but semantically can't be issued.
error.codeCause monthly_quota_exceededTenant's plan credential quota for the month is used up. signing_key_unavailableGCP KMS signing key is temporarily unreachable (rare, auto-retries). anchoring_chain_unavailableBase RPC is down (rare, batch queues for retry).
error.codeCause internal_errorSomething broke on our side. Every instance is paged. Retry with an idempotency key and contact support with the request_id.
Rule of thumb:
2xx — success, stop.
4xx (except 429) — don't retry, the body won't change. Fix the payload.
429 — back off by the Retry-After header. Exponential backoff after that.
5xx — retry with exponential backoff (start 1 s, cap 30 s, jitter). Use Idempotency-Key so the retry is safe.
Include the request_id from the response body or X-Request-Id header when you email [email protected] . We can look up the exact call in our audit log within seconds.