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

# Consent and Installs

> How customers connect their OpenTrain account to your platform: the consent deep link, scopes, PII consent, one-time ot_ptk_ tokens, reconnects, and revocation.

An **install** is one customer's grant of access to your platform app: which scopes they approved, whether they consented to Work Email sharing, and the tokens minted under that grant. Every Platform API token (`ot_ptk_…`) belongs to exactly one install.

## The Consent Deep Link

Send your customer (an OpenTrain employer — specifically the organization owner) to:

```text theme={null}
https://app.opentrain.ai/integrations/{partnerSlug}/connect?external_project_id=<id>&redirect_uri=<url>&state=<opaque>
```

| Query parameter       | Required | Purpose                                                                                                                                                                                                                               |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `external_project_id` | No       | Your project identifier. Echoed back on the return redirect so you know which of your projects initiated the connection.                                                                                                              |
| `redirect_uri`        | No       | Where to send the customer after consent. Must be `http(s)` and match a redirect URI registered for your app: same origin, and its path must start with the registered base path (so dynamic sub-paths under a registered base work). |
| `state`               | No       | Opaque value echoed back unchanged on the return redirect — use it to correlate the flow on your side.                                                                                                                                |

On the consent screen the customer sees your app's name, the scopes you requested, and — if you requested `participants:email` — a separate, explicit **PII consent checkbox** for Work Email sharing. They can approve or decline.

## The One-Time Token

When the customer approves, OpenTrain mints an install-scoped `ot_ptk_…` token and displays it **once, on the consent screen only**. The customer copies it into your platform's integration settings.

<Warning>
  The token never travels in the redirect back to your platform. The return redirect carries only `opentrain_install_id`, plus your echoed `state` and `external_project_id` — never credentials. If the token is lost, the customer must reconnect to mint a new one.
</Warning>

## Scopes

Your app requests a subset of these seven scopes when you [register it](/docs/developers/annotation-platforms/register-your-app); the customer sees each one described on the consent screen:

| Scope                 | Grants                                                                                                                                                                                                    |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `project-links:read`  | Read links between your projects and OpenTrain jobs                                                                                                                                                       |
| `project-links:write` | Create and remove project links (implies `project-links:read`)                                                                                                                                            |
| `contracts:read`      | Read contracts (status, dates, [budget](/docs/developers/annotation-platforms/api-reference/contracts/budget)) on linked jobs                                                                                  |
| `participants:read`   | Read hired participants on linked contracts: OpenTrain user ID, display name, profile URL, country                                                                                                        |
| `participants:email`  | Read the participant's `@opentrain.work` [Work Email](/docs/developers/concepts/privacy-and-work-email). Requires the explicit PII consent checkbox at install time; personal email addresses are never shared |
| `usage:write`         | [Report cumulative per-day work usage](/docs/developers/annotation-platforms/usage-sync) (time, tasks, labels) for contracts on linked jobs                                                                    |
| `webhooks:manage`     | Create, list, update, and delete webhook endpoints                                                                                                                                                        |

`participants:email` is double-gated: the scope must be granted **and** the install must have `piiConsent: true`. If the customer granted the scope but left the consent box unchecked, requests that would return Work Email are refused with `403` at request time — and webhook payloads simply omit the `workEmail` field.

## Inspecting Your Install

[`GET /installs/current`](/docs/developers/annotation-platforms/api-reference/installs/current) returns the install your token belongs to — useful as a connectivity check and to confirm which scopes and consent you actually have:

```bash theme={null}
curl -sS https://app.opentrain.ai/api/partner/v1/installs/current \
  -H "Authorization: Bearer $OT_PARTNER_TOKEN"
```

```json theme={null}
{
  "install": {
    "id": "<INSTALL_ID>",
    "status": "ACTIVE",
    "scopes": [
      "project-links:read",
      "project-links:write",
      "contracts:read",
      "participants:read",
      "participants:email",
      "webhooks:manage"
    ],
    "piiConsent": true,
    "organizationId": "<ORG_ID>",
    "createdAt": "2026-06-12T10:00:00.000Z",
    "partnerApp": { "id": "<APP_ID>", "slug": "your-app", "name": "Your App" },
    "token": { "id": "<TOKEN_ID>", "name": "Your App connection", "scopes": ["..."] }
  }
}
```

## What Every Request Requires

Beyond the right scope, every Platform API request checks four things. Any of them failing yields `401` or `403`:

1. A live token — not revoked or expired
2. An `ACTIVE` install
3. An `ACTIVE` platform app
4. The annotation-platform feature enabled for the granting employer's account

## Reconnecting

If a customer runs the consent flow again for an app they already installed, OpenTrain **revokes all previous tokens for that install before minting the fresh one**. A scope reduction on reconnect therefore cannot be bypassed by holding on to an older, broader token. Treat any `401` as a signal to ask the customer to reconnect.

## Revocation

Customers can disconnect your app at any time from their OpenTrain integrations page. Disconnecting immediately:

1. Flips the install to `REVOKED`
2. Revokes every access token — your next request returns `401`
3. Emits an [`install.revoked`](/docs/developers/annotation-platforms/lifecycle-events#install-revoked) event to webhook deliveries already queued
4. Stops all new event fan-out for that install

Handle `install.revoked` by ceasing work for that customer and marking the connection as disconnected in your UI.
