Skip to content
ecdsa.com

Error codes

A failed call answers with an HTTP status and a JSON envelope whose code says what went wrong. These are all 25 codes the API can send. New codes may appear within v1: treat one you do not know by its HTTP status.

The error envelope

Every error body has this shape; code and message are always present.

FieldTypeRequiredDescription
errorobjectyes
error.codestringyes

Machine-readable error code. Each response lists the codes it can carry; new codes may be added within v1, so treat an unknown code by its HTTP status.

error.messagestringyes

Human-readable explanation (English).

error.requestIdstringno

The X-Request-Id of this request — quote it when reporting a problem. Sent since v1.1.

error.detailobjectno

Structured context for the error, such as the offending field; omitted when there is none.

  • any member names
error.docsstringno

Where the error codes are explained. Sent since v1.1.

  • format uri

A real error answer — the request leaves out the required field:

curl
curl -sS 'https://ecdsa.com/api/v1/jwt/decode' \
  -H 'content-type: application/json' \
  -d '{}'
Response 400
{
  "error": {
    "code": "missing_field",
    "message": "Field \"token\" is required and must be a non-empty string.",
    "requestId": "docs-example",
    "docs": "https://ecdsa.com/developers#errors"
  }
}

All codes

CodeHTTPMeaningWhen it occursWhat to doSDKs
invalid_json400The body is not valid JSON or not a JSON object; or the input nests arrays and objects more than 64 levels deep (JSON documents inside string fields count too), or is too complex to inspect for private keys.

Typical causes: a form-encoded or plain-text body instead of JSON, a JSON array or string at the top level, or generated input with very deep nesting. The content-type header does not matter; the body does.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Send one JSON object as the body. If the input is generated, check its nesting.Not retried
missing_field400A required field is absent or empty.

A field the operation requires is absent, null, empty or not a string — often a name spelled differently, such as public_key for publicKey.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Add the field the message names; the operation’s reference page lists the required fields.Not retried
invalid_input400A field could not be parsed — the message explains exactly why.

A field is present but cannot be parsed: a key, signature, token or certificate in an encoding or format the operation does not recognise.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, Create a webhook endpoint

Read the message — it names the field and the reason. Check the encoding (hex, base64, PEM) and, for signatures, the curve.Not retried
private_key_rejected400The request contains private-key material (a PEM PRIVATE KEY block, an OpenSSH, SSH2 or PuTTY private key, or a JWK with "d"). Never send private keys anywhere.

A whole key file pasted where only the public half is needed: a PKCS#8 or SEC1 PEM, an OpenSSH or PuTTY private key, a JWK that still carries “d” — also nested inside a string that holds JSON.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Send only public data. To work with a private key, use the browser tools — they run on your machine and send nothing.Not retried
unsupported_algorithm400The token's algorithm is not one this operation verifies.

A JWT whose algorithm the operation does not verify: HS*, RS*, PS*, EdDSA, ES256K or none.

Operations: Verify an ES256/ES384/ES512 JWT signature

This API verifies ES256, ES384 and ES512. Check other algorithms locally with a JWT library — an HMAC secret must never be sent anywhere.Not retried
invalid_domain400Not a public DNS hostname (IP addresses, single-label names and paths are refused).

The path segment is an IP address, a name without a dot such as localhost, or text that is not a hostname. A scheme, port or path around the name is removed first.

Operations: TLS signature-health grade for a domain

Send a public hostname such as github.com. IP addresses and internal names cannot be scanned from here.Not retried
scan_dns_error400The domain does not resolve in public DNS.

Resolving the name in public DNS fails: no such domain (a typo, an expired registration, a name only an internal DNS knows), no A or AAAA record, or a DNS failure.

Operations: TLS signature-health grade for a domain

Check the spelling and that the name has A or AAAA records.Not retried
scan_private_address400The domain resolves (at least partly) to a private or reserved address.

An address of the name — IPv4, IPv6, or IPv4 embedded in IPv6 — is in a private or reserved range such as an internal network or loopback. A mix of public and private addresses is refused as a whole.

Operations: TLS signature-health grade for a domain

Check a host that is reachable from the public internet — internal hosts cannot be scanned from here.Not retried
webhook_url_refusedwith API keys400The webhook URL cannot receive deliveries: it is not https on port 443, its host is not a public DNS name, or the name does not resolve or resolves (at least partly) to a private or reserved address.

Creating an endpoint with an http URL, a port other than 443, an IP address or an internal name, or a host whose DNS answer includes a private or reserved address — also when only one of several addresses is.

Operations: Create a webhook endpoint

Use an https URL on the default port with a public host name. The message says which rule the URL broke and, for a refused address, which address and range.Not retried
unauthorized401The Authorization or X-API-Key header is malformed, the API key is not valid (wrong checksum, unknown, revoked or expired), or the operation needs a key.

An Authorization or X-API-Key header is present but malformed — and, once API keys launch, a key that is unknown, revoked or expired.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Remove the header to call anonymously, or send a complete, valid key.Not retried
forbidden_scopewith API keys403The API key is valid but lacks a scope this operation requires; the message names it.

A key created without the scope an operation needs, such as a key with only the api scope calling the domain-health operation, which needs scan.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Call with a key that has that scope.Not retried
webhook_limit_reachedwith API keys403The account already has as many webhook endpoints as its plan allows.

Creating an endpoint while the account already has as many as its plan allows; the free plan allows one.

Operations: Create a webhook endpoint

Delete an endpoint you no longer need, or create the existing one again with the same URL to change its description or events.Not retried
not_found404No operation exists at this path.

A path under /api/v1 that names no operation: a typo, a missing or an extra segment.

Any operation can answer with it.

Check the path against the API reference; operations live under /api/v1.Not retried
webhook_not_foundwith API keys404The API key's account has no webhook endpoint with this id.

An endpoint id that is not one of the key’s account: deleted already, mistyped, or another account’s.

Operations: Delete a webhook endpoint, Send a test event

List the account’s endpoints with GET /api/v1/webhooks and use an id from there.Not retried
method_not_allowed405The path exists but does not accept this HTTP method; see the Allow header.

Calling a POST operation with GET — opening it in a browser’s address bar, for example — or the reverse.

Any operation can answer with it.

Use a method from the Allow header: POST for operations that take a JSON body, GET for the others.Not retried
payload_too_large413The body exceeds 100 KB.

The body is larger than 100 KB, usually because a whole certificate bundle or file was pasted into one field.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Send less per call — one certificate chain, one token.Not retried
rate_limited429Too many requests — see Retry-After.

Too many requests in the current window: per IP without a key, per key with one. Real scans of a domain also draw on budgets per host and overall.

Operations: API self-description, Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Wait the seconds in Retry-After, then retry, and cache answers on your side.Retried up to 2 times
quota_exceededwith API keys429A daily or monthly quota of the API key's account is used up. X-Quota-Reset (and Retry-After) say when it starts over; retrying earlier cannot succeed.

Calls made with a key have used up the account’s daily or monthly quota units or its daily domain scans; test keys have smaller quotas of their own.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Do not retry before the time in X-Quota-Reset: the quota starts over then, not sooner.Not retried
internal_error500Unexpected server error.

A fault the API did not anticipate. It is logged with the request ID — never with the request body.

Any operation can answer with it.

If it persists, report the requestId of the error body.Not retried
scan_unreachable502The domain refused or dropped the connection on port 443.

The name resolves, but no TCP connection on port 443 succeeds from the internet: no HTTPS server, a firewall that refuses or drops it, or a host that is down.

Operations: TLS signature-health grade for a domain

Check that the host serves HTTPS on port 443 to the public internet.Retried up to 2 times
scan_tls_error502The TLS handshake failed or presented no usable certificate.

A connection on port 443 opens, but the TLS handshake ends with an alert or a protocol mismatch, or the server sends no certificate the scanner can read.

Operations: TLS signature-health grade for a domain

Check the server’s TLS setup, for example with the domain health report.Retried up to 2 times
service_unavailablewith API keys503API keys cannot be verified right now (the key store is unreachable); retry shortly.

The key store cannot be reached, so a presented key cannot be checked. A call that presents a key is never served anonymously.

Operations: Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, TLS signature-health grade for a domain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Retry shortly — the SDKs do.Retried up to 2 times
webhooks_unavailablewith API keys503Webhooks are switched off on this server: it has no signing keys configured.

The server has no webhook signing keys configured, so it cannot sign deliveries; every webhook operation answers with this code until keys are set.

Operations: List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Nothing to change in the request: webhooks are switched off on this server for now. Try again later.Retried up to 2 times
scan_timeout504The scan did not finish in time.

Resolving the name, connecting or the TLS handshake took longer than the scanner allows — a slow or overloaded host, or packets silently dropped.

Operations: TLS signature-health grade for a domain

Retry later; slow or overloaded hosts can exceed the budget.Retried up to 2 times
timeout504The operation did not finish within its time budget.

Work on the request ran past its time budget of 10 seconds. Input within the request limits is not expected to do that.

Operations: API self-description, Verify an ECDSA signature, Convert a signature between DER and raw r‖s, Decode a JWT (no signature check), Verify an ES256/ES384/ES512 JWT signature, Decode an X.509 certificate or chain, List webhook endpoints, Create a webhook endpoint, Delete a webhook endpoint, Send a test event

Retry once; if the same input times out again, report the requestId of the error body.Retried up to 2 times

Retries

The official SDKs retry 429 (except quota_exceeded), 502, 503 and 504 — at most 2 times — waiting as long as Retry-After asks (at most 60 seconds), otherwise with exponential backoff and full jitter. Every operation is a pure function of its input, so a retry is always safe; your own client can follow the same rule.