API
API self-description
https://ecdsa.com/api/v1Version, endpoint list, rate limits and documentation links.
- API key
- Not read: the answer is the same for everyone
- Rate limit
- 60 requests/min per IP
Request
This operation takes no input.
Responses
200Self-description of the API.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | |
| version | string | yes | Version of the v1 API. |
| description | string | yes | |
| documentation | string | yes |
|
| openapi | string | yes | This API's OpenAPI document.
|
| auth | string | yes | How callers authenticate. |
| rateLimit | object | yes | |
| rateLimit.requestsPerMinute | integer | yes |
|
| rateLimit.healthRequestsPerMinute | integer | yes |
|
| rateLimit.scope | string | yes | |
| rateLimit.headers | string[] | yes | |
| rateLimit.onExceeded | string | yes | |
| privacy | string | yes | |
| endpoints | ApiEndpoint[] | yes |
Headers: X-Request-Id · X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset
| Status | Meaning | Codes |
|---|---|---|
| 404 | Not found. | |
| 405 | Method not allowed. | |
| 429 | Too many requests. | |
| 500 | Internal server error. | |
| 504 | Gateway timeout. |
Every error answer carries the JSON envelope; the error table says what each code means and what to do.
Example
The API index
curl -sS 'https://ecdsa.com/api/v1'const response = await fetch("https://ecdsa.com/api/v1");
console.log(response.status, await response.json());import httpx
response = httpx.get("https://ecdsa.com/api/v1", timeout=30.0)
print(response.status_code, response.json()){
"name": "ecdsa.com Signature API",
"version": "1.1.0",
"description": "Free REST API for ECDSA signature verification, signature format conversion, JWT (ES256/ES384/ES512) decoding and verification, X.509 certificate decoding and TLS signature-health grades.",
"documentation": "https://ecdsa.com/developers",
"openapi": "https://ecdsa.com/api/v1/openapi.json",
"auth": "optional — every operation works without a key except managing webhooks, which needs a key with the webhooks scope. An API key (Authorization: Bearer <key> or X-API-Key) gets per-key rate limits and the quotas of its account's plan.",
"rateLimit": {
"requestsPerMinute": 60,
"healthRequestsPerMinute": 10,
"scope": "per IP address, per server instance",
"headers": [
"X-RateLimit-Limit",
"X-RateLimit-Remaining",
"X-RateLimit-Reset"
],
"onExceeded": "HTTP 429 with a Retry-After header"
},
"privacy": "Request bodies are processed in memory and never logged. Never send private keys — requests containing one are rejected. For anything secret, use the in-browser tools at https://ecdsa.com: they run entirely client-side.",
"endpoints": [
{
"method": "GET",
"path": "/api/v1",
"summary": "This self-description."
},
{
"method": "POST",
"path": "/api/v1/verify",
"summary": "Verify an ECDSA signature (P-256, P-384, P-521, secp256k1; DER or raw r‖s)."
},
{
"method": "POST",
"path": "/api/v1/convert",
"summary": "Convert an ECDSA signature between DER and raw r‖s, optionally normalizing to low-S."
},
{
"method": "POST",
"path": "/api/v1/jwt/decode",
"summary": "Decode a JWT (header, payload, time claims, algorithm info) without verifying the signature."
},
{
"method": "POST",
"path": "/api/v1/jwt/verify",
"summary": "Verify an ES256/ES384/ES512 JWT signature against a public key."
},
{
"method": "POST",
"path": "/api/v1/cert/decode",
"summary": "Decode an X.509 certificate or chain (PEM or base64/hex DER) with assessments."
},
{
"method": "GET",
"path": "/api/v1/health/{domain}",
"summary": "TLS signature-health grade for a public domain (1-hour cache)."
},
{
"method": "GET",
"path": "/api/v1/webhooks",
"summary": "List the webhook endpoints of the API key's account (needs a key with the webhooks scope)."
},
{
"method": "POST",
"path": "/api/v1/webhooks",
"summary": "Create or update a webhook endpoint of the API key's account (needs a key with the webhooks scope)."
},
{
"method": "POST",
"path": "/api/v1/webhooks/delete",
"summary": "Delete a webhook endpoint of the API key's account (needs a key with the webhooks scope)."
},
{
"method": "POST",
"path": "/api/v1/webhooks/test",
"summary": "Send a webhook.test event to an endpoint of the API key's account (needs a key with the webhooks scope)."
},
{
"method": "GET",
"path": "/api/v1/openapi.json",
"summary": "OpenAPI 3.1 specification of this API."
}
]
}The API’s answer to this example, produced for this page on October 20, 2026; relative times and day counts in it refer to that day.
Error codes
| Code | Status | Meaning |
|---|---|---|
| not_found | 404 | No operation exists at this path. |
| method_not_allowed | 405 | The path exists but does not accept this HTTP method; see the Allow header. |
| rate_limited | 429 | Too many requests — see Retry-After. |
| internal_error | 500 | Unexpected server error. |
| timeout | 504 | The operation did not finish within its time budget. |
Schemas
ApiEndpoint
| Field | Type | Required | Description |
|---|---|---|---|
| method | string | yes |
|
| path | string | yes | Path on https://ecdsa.com, e.g. "/api/v1/verify". |
| summary | string | yes |
Error
The error envelope of every non-2xx response.
| Field | Type | Required | Description |
|---|---|---|---|
| error | object | yes | |
| error.code | string | yes | 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.message | string | yes | Human-readable explanation (English). |
| error.requestId | string | no | The X-Request-Id of this request — quote it when reporting a problem. Sent since v1.1. |
| error.detail | object | no | Structured context for the error, such as the offending field; omitted when there is none.
|
| error.docs | string | no | Where the error codes are explained. Sent since v1.1.
|
All operations are listed in the API reference.