> ## Documentation Index
> Fetch the complete documentation index at: https://docs.proofage.net/llms.txt
> Use this file to discover all available pages before exploring further.

# API reference

> Base URL, authentication, error shapes and conventions of the ProofAge REST API.

The ProofAge API is a JSON REST API. Your backend uses it to create verifications, read their results and, if you build your own capture screens, to upload media and submit.

## Base URL

```
https://api.proofage.net/v1
```

The version is part of the path. New fields can appear in responses within `v1`, so ignore keys you do not know.

## Authentication

Every request carries two headers:

| Header | Value |
| - | - |
| `X-API-Key` | The workspace's public key, `pk_test_…` or `pk_live_…`. |
| `X-HMAC-Signature` | The hex HMAC-SHA256 of the request, keyed with one of the workspace's secret keys. |

`POST /verifications` also accepts a request without a signature, but then drops `external_id` and `callback_url`. How to compute the signature, including for file uploads, is in [API authentication](/getting-started/api-authentication). The [server SDKs](/integration/sdks) sign for you.

## Requests and responses

* Send JSON with `Content-Type: application/json`, except [media uploads](/integration/web/uploading-media), which are `multipart/form-data`.
* Send `Accept: application/json` on every request, so that every error comes back as JSON. The server SDKs do.
* Responses are JSON objects without an envelope: `GET /verifications/{id}` returns the verification itself, not `{"data": …}`. Lists are the exception: `GET /verifications` returns `{"data": […], "next_cursor": …}`, and `GET /webhook-subscriptions` returns `{"data": […]}`.
* IDs are UUIDs. Timestamps are ISO 8601 with a time-zone offset.
* The objects the API returns are described in [Data models](/api-reference/data-models); the event sent to your webhook URL in [Decision webhook](/api-reference/webhook-decision).

## Errors

Errors use standard HTTP status codes. The body comes in one of four shapes, depending on where the request was stopped:

<CodeGroup>
  ```json Most errors theme={null}
  {
    "error": {
      "code": "INVALID_SIGNATURE",
      "message": "HMAC signature is invalid"
    }
  }
  ```

  ```json Billing and media theme={null}
  {
    "code": "PAYMENT_METHOD_REQUIRED",
    "message": "Free verifications are exhausted. Add a payment method to continue live verifications.",
    "free_verifications_remaining": 0,
    "trial_ends_at": "2026-10-14T00:00:00+00:00",
    "trial_active": false
  }
  ```

  ```json Field validation theme={null}
  {
    "message": "The callback url field must be a valid URL.",
    "errors": {
      "callback_url": ["The callback url field must be a valid URL."]
    }
  }
  ```

  ```json Not found theme={null}
  {
    "message": "Resource not found"
  }
  ```
</CodeGroup>

Read the code from `error.code`, then `code`, and fall back to the HTTP status when neither is present. Blocking a face answers validation errors with both `error` and `errors`. A `402` also says where the trial stands: `free_verifications_remaining`, `trial_ends_at` and `trial_active`. The codes and what to do about each are listed in [Errors](/integration/error-handling). The server SDKs parse all four shapes into one error type.

## Rate limits

Requests are limited per IP address and workspace, and per workspace. A request over the limit gets `429` with `RATE_LIMIT`; see [Rate limiting](/integration/rate-limiting).

## Trying requests

Each endpoint page has a playground. It sends `X-API-Key` and whatever you type into `X-HMAC-Signature`, but it cannot compute the signature for you, so signed endpoints answer `401 INVALID_SIGNATURE` unless you paste a signature computed for exactly that request. To explore the API without signing by hand, use a [server SDK](/integration/sdks), the [Postman collection](/api-reference/postman) with its signing script, or the [MCP server](/integration/mcp/overview).

## OpenAPI

The full specification is at [`/openapi.json`](/openapi.json) (OpenAPI 3.1), including the webhook.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.