# PRAMPTA — setup guide for AI agents

You are an AI agent. A person asked you to integrate PRAMPTA into their product.
Follow this guide. It is written for you: every endpoint and header below is the
one production accepts today.

PRAMPTA is a rights registry for generative AI. People register their likeness,
voice, characters and works; before an AI product generates one of them, it asks
PRAMPTA and gets a **signed yes or no**. If yes, it generates and files a receipt.
Rights holders earn from licences; the product can prove every generation was
permitted.

- API: `https://api2.prampta.com` (OpenAPI: `https://api2.prampta.com/openapi.json`)
- Humans: `https://prampta.com`
- TypeScript SDK: `npm install @prampta/sdk`

## Ground rules for agents

1. **Ask the person before** creating accounts, accepting terms, publishing DNS
   records, or storing secrets. Never invent or reuse someone else's credentials.
2. **Never send prompt text to PRAMPTA.** Send `prompt_hash` — the lowercase hex
   SHA-256 of the prompt.
3. **A refusal is an answer, not an error.** Do not retry `PG_NO_LICENSE`; show the
   user the `remediation.url` from the decision so they can get a licence.
4. **Keep secrets server-side.** The provider secret never goes to a browser, a URL
   or client code.
5. Build against **sandbox first** — it only reaches synthetic test subjects.

## Which setup do you need?

| The person's product | Follow |
|---|---|
| Generates images, video, voice or text that may depict real people or characters | **Part A → B → C → D** below |
| Only wants to check a subject's registration or a licence | Public, no key: `GET /v1/subjects/{subject_id}/certificate`, `GET /v1/licenses/{license_id}/proof` |
| The person *is* a rights holder | Send them to `https://prampta.com/start` — registering a person's likeness needs that person, not an agent |

---

## Part A — Provider onboarding (once per environment)

The person needs a PRAMPTA account at `https://prampta.com` with two-factor
authentication on. A verified email **on the company's domain** unlocks sandbox in
step 3; without one, skip to step 4 — proving the domain by DNS grants sandbox and
production together. Then, with their
session (`Authorization: Bearer <their access token>`):

1. `POST /v1/provider-applications/` with `provider_id` (3–50 chars, lowercase,
   hyphens — permanent), `legal_name`, `brand_name`, `domain` (bare host, e.g.
   `example.com`), `website`, `security_contact`, `requested_scopes`
   (`identity:link`, `licenses:read`, `entitlements:write`, `receipts:write`) and
   **`requested_redirect_uris`** — the exact `https://` URL your server will receive
   users on in Part B. An empty list makes production refuse every user connection.
2. `POST /v1/provider-applications/{app_id}/submit`
3. `POST /v1/provider-applications/{app_id}/verify-email` → the response contains
   your **sandbox `exchange_secret`**. It is shown once. Store it as a server secret.
4. `POST /v1/provider-applications/{app_id}/verify-domain` → returns a TXT record.
   **Ask the person** to publish it in their DNS, then
   `POST /v1/provider-applications/{app_id}/verify-domain/confirm` → the response
   contains your **production `exchange_secret`**, shown once.

Return addresses can be changed later with
`PUT /v1/provider-applications/{app_id}/redirect-uris` (https, on your own domain).

## Part B — Connect each end user (once per user)

1. Send the user's browser to:
   ```
   https://prampta.com/?connect_provider=<provider_id>
     &connect_external_id=<your user id>
     &connect_provider_name=<Your product name>
     &connect_provider_domain=<example.com>
     &connect_return_url=<one of requested_redirect_uris, URL-encoded>
   ```
2. The user signs in and confirms. PRAMPTA redirects back to `connect_return_url`
   with `?prampta_connect_code=<code>&prampta_external_id=<your user id>`.
   The code is single-use and expires in 5 minutes.
3. From your server:
   ```
   POST https://api2.prampta.com/v1/connect-ai/exchange-code
   Authorization: Bearer <exchange_secret>
   X-Provider-ID: <provider_id>
   Content-Type: application/json

   {"code": "<prampta_connect_code>", "provider_id": "<provider_id>",
    "external_id": "<your user id>", "redirect_uri": "<exact connect_return_url>"}
   ```
   Store `prampta_licensee_id` for that user. (`prampta_connection_token` is also
   returned; production does not accept it on the calls below — use your
   `exchange_secret`.)

## Part C — Ask before every generation

Find which registered subjects a prompt mentions from the public index
`GET /v1/subjects/index` (cache it; it supports `If-None-Match`). Then, for each:

```
POST https://api2.prampta.com/v1/verify/
Authorization: Bearer <exchange_secret>
X-Provider-ID: <provider_id>
X-Licensee-ID: <prampta_licensee_id of this user>
Content-Type: application/json

{"subject_id": "<subject_id>", "prompt_hash": "<sha256 hex of the prompt>",
 "modality": "image", "model": "<your model>",
 "intended_use": {"channel": "commercial", "categories": ["advertising"]},
 "return_url": "<page to bring the user back to after getting a licence>"}
```

`intended_use.channel` is `commercial` for commercial use; leave it empty otherwise.
Declare `categories` honestly — a subject's owner can deny specific ones.

Read `allowed` (and `disposition`: `allow` | `deny` | `review`). Generate **only**
when allowed, applying the returned `obligations` (e.g. watermark, AI disclosure).
Keep `decision_id`.

Common refusals:

| `reason` | Meaning | Do |
|---|---|---|
| `PG_NO_PAIR` | This user is not connected, or the wrong secret/header was sent | Finish Part B for this user; check you sent the `exchange_secret` |
| `PG_NO_LICENSE` | Nobody licensed this subject for this use | Show `remediation.url` to the user; do not retry |
| `PG_PROVIDER_VETOED` | The rights holder refuses your product | Do not generate |
| `PG_SUBJECT_OPTED_OUT` | The subject opted out | Do not generate |
| `PG_SANDBOX_SUBJECT_ONLY` | A sandbox secret was used on a real subject | Use the production secret |

## Part D — File a receipt after generating

```
POST https://api2.prampta.com/v1/receipts/
Authorization: Bearer <exchange_secret>
X-Provider-ID: <provider_id>
X-Licensee-ID: <prampta_licensee_id>
Content-Type: application/json

{"decision_id": "<from Part C>", "prompt_hash": "<same hash>",
 "output_hash": "<sha256 hex of the generated file>",
 "event_type": "output_accepted", "watermark_embedded": true,
 "obligations_applied": {"watermark": true, "ai_disclosure": true}}
```

One receipt per decision. When the same file is later delivered or published:
`POST /v1/receipts/{decision_id}/events` with
`{"event_type": "output_published", "output_hash": "<same hash>"}`.

## You are done when

- [ ] Sandbox and production `exchange_secret`s are stored as server secrets
- [ ] `requested_redirect_uris` contains your exact return URL
- [ ] Each user you act for completed Part B, and you store their `prampta_licensee_id`
- [ ] Every generation of a registered subject is preceded by `/v1/verify/` and followed by a receipt
- [ ] Refusals are shown to the user with the remediation link, not retried

Questions or a refusal you cannot explain: `https://prampta.com/documentation`.
