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

# Personal API Keys

> Generate and manage personal API keys to authenticate scripts, CLI tools, and integrations against Pria — only available to Admin role.

Personal API keys let you authenticate non-interactive callers — scripts, SDKs, CI runners, notebooks — against Pria without baking a web-session JWT into your tooling. The key is your long-lived credential; you exchange it at runtime for a short-lived JWT and call the rest of the API with that JWT.

<Note>
  Personal API keys are an **Admin-only** capability. If you are demoted from Admin to User, any key you previously generated will stop working immediately — every sign-in attempt is re-checked against your current account type.
</Note>

## API key vs JWT — what's the difference

When you sign in through the web app, Pria gives your browser a JSON Web Token (JWT) that expires after 24 hours. Calling the API directly with that JWT works, but it means re-authenticating every day and storing a value that rotates frequently.

A personal API key is a stable, long-lived credential that identifies *you* to non-interactive callers. It is **not** itself a bearer token — it must be exchanged for a JWT via a single short request. Once exchanged, the JWT behaves exactly like the one your browser uses.

<Info>
  Personal API keys never leave the device they were generated on unless you move them yourself. Pria stores only a SHA-256 hash of the key — the raw value is shown to you exactly once at generation time.
</Info>

## Who can create a key

| Role  | Can generate a key | Can sign in with a key |
| ----- | ------------------ | ---------------------- |
| Admin | Yes                | Yes                    |
| User  | No                 | No                     |

If you need API access but are not an Admin, ask the Admin of your Digital Twin to promote you, or contact the Praxis AI team at [humans@praxis-ai.com](mailto:humans@praxis-ai.com) to request access.

## Generating a key

<Steps>
  <Step title="Open Your Profile">
    Click your profile icon in the top-right and select **Your Profile**.
  </Step>

  <Step title="Open the Developer tab">
    In Personal Settings, switch to the **Developer** tab. This tab is only visible to accounts with the Admin role.
  </Step>

  <Step title="Generate the key">
    Click **Generate API key**. Pria creates a fresh key and shows it to you in full, exactly once.
  </Step>

  <Step title="Copy and store it immediately">
    Use the copy button next to the displayed key and paste it into a password manager or secret store. Once you close or navigate away from this view, you cannot retrieve the key again — only its short prefix and creation date are stored.
  </Step>
</Steps>

<Warning>
  The raw key is shown **exactly once**. If you lose it, you must rotate to a new one — there is no recovery flow.
</Warning>

### Key format

Every key has the shape:

```
pria_<40 lowercase hex characters>
```

For example: `pria_d350d4156bf1ba9b14332240c30b7c7941195ba6`. The `pria_` prefix makes keys easy to identify in code review and secret-scanning tools.

## Using the key — the two-step exchange

Personal API keys are **not bearer tokens**. Calling a protected endpoint with the raw `pria_…` value in an `Authorization: Bearer` header returns:

```json theme={null}
{ "success": false, "message": "Invalid access token jwt malformed" }
```

Instead, you exchange the key for a JWT once per session via `POST /api/auth/api-key-signin`, sending the key in the **`x-api-key`** header. The response carries a JWT in `.token` that you then use for every subsequent call as `Authorization: Bearer <jwt>`.

### Example — curl

```bash theme={null}
APIKEY="pria_d350d4156bf1ba9b14332240c30b7c7941195ba6"

# Step 1 — exchange the API key for a short-lived JWT
JWT=$(curl -sS -X POST "https://pria.praxislxp.com/api/auth/api-key-signin" \
  -H "x-api-key: $APIKEY" \
  | python -c "import json,sys; print(json.load(sys.stdin)['token'])")

# Step 2 — call any protected endpoint with the JWT
curl -sS "https://pria.praxislxp.com/api/user/api-key" \
  -H "Authorization: Bearer $JWT"
```

<Tip>
  The `/api-key-signin` endpoint is rate-limited (100 requests per minute per IP). For batch jobs, exchange the key **once** at startup and reuse the JWT across all subsequent calls instead of re-exchanging on every request.
</Tip>

## Rotating and revoking keys

### Rotate

Generating a new key when one already exists **overwrites** the old one — the previous key stops working immediately. Use rotation when a key may have been exposed in a log, a screenshot, or a former teammate's machine.

When you rotate, Pria also wipes the **device usage history** tied to the old key. The new key starts with a clean device list, and any caller still holding the old value will be told the key is invalid the next time they try to exchange it.

### Revoke

Use **Revoke API key** to remove the key entirely without issuing a replacement. Revocation:

* Hard-deletes the key hash, prefix, and creation timestamp from your profile.
* Wipes all device usage rows for that key.
* Records an `apiKey.revoked` audit entry tied to your account.

You can generate a new one later — there is no cooldown.

<Note>
  JWTs that were already minted from the old key continue to work until they expire (up to 24 hours). Revocation prevents *new* exchanges, not the use of an outstanding JWT. If you need to invalidate in-flight JWTs immediately, contact the Praxis AI team at [humans@praxis-ai.com](mailto:humans@praxis-ai.com).
</Note>

## Device usage tracking

Every successful exchange records a row in your **Recent device usage** list. Pria identifies each device by a coarse **fingerprint** built from your `/24` IP subnet, browser family, and operating system — enough to group repeat sign-ins from the same network and device, but not enough to identify you across different networks or different machines.

For each device row you see:

* Source IP and `/24` subnet
* Browser family, version, and operating system
* Optional client name and hostname (if your tool advertises one via `User-Agent`)
* First seen, last seen, and total sign-in count

Rows are listed most-recently-seen first, capped at 50. Each row expires **180 days** after its last sign-in, so old, idle devices fall off automatically.

<Tip>
  Spot an unfamiliar entry? **Rotate your API key.** Deleting a single device row is cosmetic — it only hides the row from your list and does not invalidate the device's access. Real revocation always means rotating or revoking the key.
</Tip>

## Security best practices

<AccordionGroup>
  <Accordion title="Never commit keys to source control" icon="code-branch">
    Add `.env` files (or whatever you use to load secrets) to `.gitignore`. Use a secret-scanning tool like `gitleaks` or `trufflehog` to catch accidental commits — the `pria_` prefix makes keys easy to detect.
  </Accordion>

  <Accordion title="Use a secret manager in production" icon="vault">
    For CI runners and deployed services, store the key in a managed secret store (AWS Secrets Manager, HashiCorp Vault, GitHub Actions secrets, GitLab CI variables) rather than environment files on disk.
  </Accordion>

  <Accordion title="Rotate on schedule" icon="arrows-rotate">
    For service accounts, rotate every 90 days at minimum. For human Admin accounts, rotate any time you change machines, leave a team, or suspect exposure.
  </Accordion>

  <Accordion title="Exchange once, reuse the JWT" icon="recycle">
    Re-exchanging on every request will hit the rate limiter on busy workloads and unnecessarily expand the device-usage log. Cache the JWT in memory for the duration of the job.
  </Accordion>

  <Accordion title="Watch the device list" icon="eye">
    The Recent device usage list is your tripwire. Check it after any rotation, after onboarding a new tool, and any time you suspect a credential leak.
  </Accordion>
</AccordionGroup>

## Related

* [Edit Profile](/mdx/user-guide/profile-settings/edit-profile)
* [Two-Step Verification](/mdx/user-guide/profile-settings/two-step-verification)
* [Change Password](/mdx/user-guide/profile-settings/change-password)
* [API Reference (Runtime)](/mdx/api-reference/introduction)
* [API Reference (Admin)](/mdx/api-reference/introduction)
