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

# API Authentication

> Authenticate Didit identity verification requests with scoped API keys. Pass your secret key via HTTP header. Missing or invalid keys return 401.

export const AgentPromptAccordion = ({prompt, title = "AI Agent Integration Prompt"}) => {
  const [copied, setCopied] = React.useState(false);
  const handleCopy = e => {
    e.stopPropagation();
    if (!prompt) return;
    navigator.clipboard.writeText(prompt.trim()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };
  const agents = ["Claude Code", "Codex", "Cursor", "Devin", "Windsurf", "GitHub Copilot"];
  return <div className="didit-agent-card">
      {}
      <div className="didit-agent-titlebar">
        <div className="didit-agent-dots" aria-hidden="true">
          <span className="didit-agent-dot didit-agent-dot-red"></span>
          <span className="didit-agent-dot didit-agent-dot-yellow"></span>
          <span className="didit-agent-dot didit-agent-dot-green"></span>
        </div>
        <span className="didit-agent-filename">{title}</span>
        <button type="button" className={`didit-agent-copy ${copied ? "didit-agent-copy-copied" : ""}`} onClick={handleCopy} title="Copy prompt to clipboard" aria-label={copied ? "Copied!" : "Copy prompt to clipboard"}>
          {copied ? <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Copied</span>
            </> : <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <rect x="5" y="5" width="9" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.5" />
                <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              <span>Copy</span>
            </>}
        </button>
      </div>

      {}
      <pre className="didit-agent-body"><code>{prompt.trim()}</code></pre>

      {}
      <div className="didit-agent-footer">
        <span className="didit-agent-footer-label">Paste into</span>
        <div className="didit-agent-chips">
          {agents.map(name => <span key={name} className="didit-agent-chip">{name}</span>)}
        </div>
      </div>
    </div>;
};

<AgentPromptAccordion
  title="API Authentication Prompt"
  prompt={`# Goal — authenticate against Didit's REST API

Two hosts, two auth schemes. Never mix them up.

## Host map

| Host | Surface | Auth header |
|---|---|---|
| \`https://verification.didit.me\` | Verification API — sessions, workflows, entities, transactions, standalone APIs, lists, webhooks, billing (every \`/v3/...\` route) | \`x-api-key: <DIDIT_API_KEY>\` |
| \`https://apx.didit.me\` | Account / organization / application management (\`/auth/v2/programmatic/...\`, \`/auth/v2/organizations/...\`) | \`Authorization: Bearer <JWT access_token>\` |

The verification API does **not** use OAuth Bearer tokens. It uses a long-lived API key on the \`x-api-key\` header. Treat the key as a server-side secret — never ship it to a browser or mobile bundle.

## How to obtain the api_key (no console UI needed)

<Warning>
Substitute \`you@yourdomain.com\` below with a real inbox. The register endpoint sends the verification code synchronously, so reserved test domains (\`@example.com\`, \`@example.org\`, \`@*.test\`, \`@*.example\`, \`@*.invalid\`) get refused by mail delivery and the call returns a \`500\`.
</Warning>

\`\`\`bash
# 1) Register — emails a 6-char code (15 min TTL).
#    Password rules: ≥8 chars, 1 uppercase, 1 lowercase, 1 digit, 1 special.
curl -X POST https://apx.didit.me/auth/v2/programmatic/register/ \\
-H "Content-Type: application/json" \\
-d '{"email": "you@yourdomain.com", "password": "StrongP@ss1"}'

# 2) Verify email — returns api_key inline.
curl -X POST https://apx.didit.me/auth/v2/programmatic/verify-email/ \\
-H "Content-Type: application/json" \\
-d '{"email": "you@yourdomain.com", "code": "A3K9F2"}'
# 200 -> { access_token, refresh_token, organization, application: { api_key, client_id, uuid } }
\`\`\`

Persist \`response.application.api_key\` as the env var \`DIDIT_API_KEY\`.

## Recover the key (lost it)

\`\`\`bash
# Log back in to get a fresh JWT
TOK=$(curl -s -X POST https://apx.didit.me/auth/v2/programmatic/login/ \\
-H "Content-Type: application/json" \\
-d '{"email":"you@yourdomain.com","password":"StrongP@ss1"}' | jq -r .access_token)

# Find your org and app
curl https://apx.didit.me/auth/v2/organizations/me/ -H "Authorization: Bearer $TOK"
curl https://apx.didit.me/auth/v2/organizations/me/$ORG_ID/applications/$APP_ID/ \\
-H "Authorization: Bearer $TOK"
# Response.api_key is your key.
\`\`\`

## Calling the verification API

\`\`\`bash
curl -X POST https://verification.didit.me/v3/session/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"workflow_id":"<WORKFLOW_ID>","vendor_data":"user-42","callback":"https://myapp.com/return"}'
\`\`\`

## Failure modes

| Status | Meaning | Fix |
|---|---|---|
| \`401\` on verification.didit.me | \`x-api-key\` header missing, malformed, or revoked | Re-fetch via the recover-key flow above |
| \`403\` on apx.didit.me | JWT \`Authorization\` header missing or expired | Call \`POST /auth/v2/programmatic/login/\` again |
| \`429\` | Rate limit; response includes a \`wait\` field (seconds) | Back off, then retry |

## Sources of truth
- /openapi-auth.json — every account / org / app endpoint
- /openapi-25.json — every verification endpoint
- /integration/integration-prompt — end-to-end integration recipe
`}
/>

## Finding Your API Key

In Didit, API keys are scoped to a specific **Application** within your account. An Application is a workspace where you can configure workflows and manage verifications for a particular project or environment.

An API key is generated automatically for each Application you create. To find your key:

<Steps>
  <Step title="Log in to the Business Console">
    Go to the [**Didit Business Console**](https://business.didit.me) and sign in.
  </Step>

  <Step title="Select your Application">
    Choose the **Application** you want to work with from the dropdown menu at the top.
  </Step>

  <Step title="Open API & Webhooks">
    Navigate to **API & Webhooks** in the left-hand sidebar.
  </Step>

  <Step title="Copy your keys">
    Your **API Key** and **Webhook Secret Key** will be displayed here. Copy them as needed.
  </Step>
</Steps>

<Warning>
  **Your API Key is a Secret — treat it like a password.**

  It provides full access to the API on behalf of your Application. Never expose it in frontend code, public repositories, or client-side bundles. Always keep it server-side only.
</Warning>

***

## Making Authenticated Requests

To authenticate an API request, include your secret API key in the `x-api-key` HTTP header.

Here is an example of an authenticated request to the `Create Session` endpoint:

```shell cURL theme={null}
curl --request POST \
     --url https://verification.didit.me/v3/session/ \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: YOUR_API_KEY' \
     --data '
{
  "workflow_id": "WORKFLOW_ID",
  "vendor_data": "USER_ID",
  "callback": "CALLBACK_URL"
}
'
```

***

## Error Handling

If your API key is missing or invalid, the API returns a `401 Unauthorized` response:

```json theme={null}
{
  "detail": "Invalid or missing API key"
}
```

| Status Code | Meaning                                                |
| ----------- | ------------------------------------------------------ |
| **401**     | API key is missing, invalid, or revoked                |
| **403**     | API key does not have access to the requested resource |

<Tip>
  If you receive a `401` error, double-check that you are using the correct API key for the right Application and that it has not been regenerated.
</Tip>
