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

# Service accounts

> The non-human principal behind every integration API key — identity, acting attorney, lifecycle, and management surfaces.

An integration API key is more than a credential: it is a **service account** — a named, organization-scoped, non-human principal. Everything the key does is recorded against that identity.

## The model

| Concept | Behavior |
| - | - |
| Identity | The service account's id is the `actorId` recorded on every write it performs |
| Display name | The key's name appears as `actorName` in events and audit logs |
| Tenant boundary | The issuing organization; saved report execution can additionally use authorized HQ descendants |
| Credential | The API key secret (shown once at creation; stored as a SHA-256 digest with a display prefix) |
| Authorization | The key's [scopes](/docs/scopes), endpoint boundary, and applicable acting-attorney [RBAC](/docs/authorization) |
| Lifecycle | Validity window (`validFrom` / `validUntil`), active flag, revocation timestamp, last-used timestamp |
| Acting attorney | Optional (required for some scopes) — the human the account acts on behalf of |
| Webhook egress allowlist | HTTPS hosts the key's webhook subscriptions may target |

Writes made through the API are attributed as `actorType: "service"` with the key's id and name, plus `onBehalfOfAttorneyId` when an acting attorney is configured. This attribution flows into the event feed, audit logs, and API responses, so you can always trace a change back to the integration (and person) responsible — and filter out your own writes when consuming the [event feed](/docs/webhooks/overview) (echo suppression).

## Acting attorney

The **acting attorney** is an active member of the key's organization who provides human attribution for the account's writes:

* Required for scopes whose domains need a human owner — document ownership (`documents:write`), case/lead attribution (`cases:write`, `leads:write`), author/sender attribution (`notes:write`, `tasks:write`, `calendar:write`, `esign:write`), money movement (`funds:write`), and all elevated PHI/PII scopes. See the [full matrix](/docs/scopes#scope--acting-attorney-matrix).
* Required for default HQ report rollups and cross-organization saved report runs. Current report-view/export, hierarchy, and underlying data permissions are checked at execution; selecting an attorney does not grant those permissions.
* Validated at configuration time: the attorney must be an active organization member.
* If the acting attorney's membership is later deactivated, requests that rely on the attribution fail with `INTEGRATION_NOT_CONFIGURED` until the key is pointed at another active attorney.

## Lifecycle

* **Create** — self-serve in the attorney portal (**Settings → Integrations → API Credentials**), by a platform admin, or via the API (below). The secret is returned once.
* **Reconfigure** — name, standard scopes, acting attorney, report hierarchy preference, and webhook hosts can change without rotating the secret.
* **Rotate** — create a new key alongside the old (multiple active keys are supported), migrate, then revoke the old key. There is no in-place secret rotation.
* **Revoke** — immediate; revoked keys fail closed.
* **Expire** — `validUntil` is required at creation. Self-serve maximum is 2 years; keys holding elevated (PHI/PII) scopes are capped at 1 year.

## Management surfaces

### Attorney portal (self-serve)

**Settings → Integrations → API Credentials** lists your organization's keys (name, prefix, scopes, acting attorney, created/expires/last-used, status) and supports create, edit, and revoke. Portal management requires **Manage Integrations** (`integrations:manage`); a reporting-only integration usually needs `reports:read`, not `org:manage`. Elevated scopes (`medical:read`, `medical:write`, `pii:read`) are visible but disabled — they can only be granted by platform administrators after compliance (BAA) verification, and this restriction is enforced server-side, not just in the UI.

### API self-management

With the `org:manage` scope, keys can be managed programmatically — useful for platform partners automating rotation. Note that **creating** a key additionally requires the calling credential to have an **acting attorney** configured: API-minted keys are attributed to it, so an `org:manage` key without one is rejected on `POST`:

| Method | Path | Purpose |
| - | - | - |
| GET | `/api/v1/service-accounts` | List keys (metadata only — never secrets) |
| POST | `/api/v1/service-accounts` | Create a key (standard scopes only; the secret is in this response only) |
| PATCH | `/api/v1/service-accounts/{keyId}` | Update name / scopes / acting attorney / expiry / report scope / webhook hosts |
| DELETE | `/api/v1/service-accounts/{keyId}` | Revoke |

Elevated scopes are rejected on this surface too — the same server-side rule as self-serve.

```bash theme={null}
curl -X POST https://www.presolve.com/api/v1/service-accounts \
  -H "x-api-key: YOUR_ADMIN_KEY" \
  -H "X-Idempotency-Key: 5f1f9c1e-create-sync-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly document sync",
    "scopes": ["documents:read", "documents:write", "events:read"],
    "actingAttorneyId": "attorney-example-id",
    "expiresAt": "2027-08-01T00:00:00Z"
  }'
```

The response contains the new key's plaintext secret — store it immediately; it is never returned again (idempotent replays of the same request serve a sanitized copy without the secret).

> **Planned:** OAuth 2.0 client-credentials for service accounts — the same scope strings become OAuth scopes on short-lived bearer tokens. Not yet available.

## HQ report scope

The credential setting `reportIncludeChildOrganizations` defaults to `true`, including for existing keys. In the credential editor it is labeled **Current organization + child organizations**. Set it to `false` when creating or updating a service account to restrict saved report runs to the key's organization. Changing this setting does not rotate the secret.

Only HQ keys can reach descendants, and only through the acting attorney's current HQ reporting and data permissions. Configure an acting attorney for HQ rollups. The setting applies to saved report execution, not other endpoints. Explicit `organizationIds` on a report run must be a subset of the authorized scope. Saved report filters, including case status, remain in effect.

## Configure a reporting credential

1. Select the organization that should issue the key. Use HQ for an authorized multi-office report integration.
2. Create a named integration key with `reports:read`. Add other scopes only if the integration calls those endpoints.
3. Choose an existing active acting attorney in HQ and review the [HQ reporting permission checklist](/docs/authorization#hq-saved-report-permissions).
4. Leave **Current organization + child organizations** on for HQ rollups, or turn it off for own-organization runs.
5. Set an expiry, store the one-time secret in the integration's credential store, and test `GET /api/v1/me` followed by a known report run. The health check verifies the key; a successful report run verifies the report-specific access.
6. Review representative records, saved filters, and truncation before scheduling repeated pulls.

To restrict an existing key without rotating it:

```bash theme={null}
curl -X PATCH "https://www.presolve.com/api/v1/service-accounts/KEY_ID" \
  -H "x-api-key: KEY_WITH_ORG_MANAGE" \
  -H "X-Idempotency-Key: report-scope-change-001" \
  -H "Content-Type: application/json" \
  -d '{ "reportIncludeChildOrganizations": false }'
```

Set the property to `true` to restore the HQ report preference. The acting attorney still needs current authorization. Omitting the property in PATCH preserves its existing value. Setting it does not change the key's organization, report ownership, saved filters, or access to other API endpoint families.

## Rotate, revoke, and hand over ownership

Create a replacement key before the old one expires. Configure its scopes, acting attorney, report scope, and webhook hosts deliberately; do not assume a new key copies the old settings. Test it, update the integration's stored secret, confirm successful requests, then revoke the old credential. Revocation invalidates the old secret; changing a display name does not.

Review the acting-attorney assignment when someone changes roles or leaves the organization. Reassign to an appropriate active member and verify report access again. Reconfiguring an acting attorney preserves the secret but can change the permitted reporting data and the meaning of `$currentUser` report filters.

If a secret is lost, create a replacement. List and metadata endpoints cannot recover it. Use the prefix, name, expiry, and last-used time to identify a credential without sharing its secret.
