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

# Create and manage Ultiwrite API keys

> Request API approval, create a server key, check account usage, and rotate or revoke credentials without resetting your shared request allowance.

Use a dashboard API key to call the Ultiwrite Partner API from your server. It uses the same account, evidence workflow, saved reports and analysis credits as the website.

This page mirrors the [native API key guide](https://dwsoffshorepartners.com/docs/developers/api-keys). Both documentation sites describe the same account approval, key management and request allowances.

* API base: `https://dwsoffshorepartners.com/api/v1`
* Key management: [Dashboard → API access](https://dwsoffshorepartners.com/settings/api)
* Reference: [API documentation](https://dwsoffshorepartners.com/docs/api)
* Machine contract: [OpenAPI 3.1](https://dwsoffshorepartners.com/.well-known/openapi.json)
* Complete workflow, pagination and signed staging: [Developer guide](https://dwsoffshorepartners.com/docs/downloads/partner-api/GUIDE.md)

Availability depends on the deployed API configuration. A feature being documented here does not establish that a deployment has been activated.

## 1. Get approval and create a key

API access is visible in the dashboard and the **Enterprise & custom pricing** block. Access requires an explicit grant from an Ultiwrite administrator; signing up or buying an analysis does not grant it.

1. Sign in and open [Enterprise & custom pricing in your customer dashboard](https://dwsoffshorepartners.com/dashboard#custom-pricing). Use **Request API access** and submit the form there; this is the only customer API-access request intake. The documentation and access-status page remain available before approval.
2. After approval, open **API access** again. Your monthly request allowance, usage, remaining requests, reset date and requests per minute appear here.
3. Give the key a recognizable name such as “CRM production,” select an expiration and choose **Create key**.
4. Copy the key immediately into your application's server secret store. It is displayed only once.

Keys start with `ultiwrite_live_`. The default expiration is 90 days. The dashboard offers 30, 90 or 365 days; the server accepts 1–365 days. Up to five unexpired active keys or pending creations are permitted per account. These defaults do not imply API approval.

If creation reports an unknown outcome, refresh the list before trying again. A pending creation must be resolved or revoked before creating a replacement. A key created during a lost response cannot be displayed again; revoke it and issue a replacement. The list shows safe metadata, never the full credential.

All keys created through the dashboard receive `ultiwrite:read` and `ultiwrite:evidence`. Customers cannot choose another account, user, permission set or request limit when creating a key. The server derives those values from the signed-in account and its saved policy.

## 2. Make the first request

Store the key in `ULTIWRITE_API_KEY` on your own server. Send it only in the Authorization header. Do not put it in URLs, browser bundles, public repositories or request logs.

```bash theme={null}
# Set ULTIWRITE_API_KEY in your local/server secret environment first.
export ULTIWRITE_API_BASE=https://dwsoffshorepartners.com/api/v1

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/me" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/usage" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"
```

`GET /me` identifies the account the credential actually authorizes. `GET /usage` returns the existing analysis-credit fields and an additional `apiRequests` object:

```json theme={null}
{
  "enabled": true,
  "monthlyRequestLimit": 1000,
  "requestsPerMinute": 60,
  "usedThisMonth": 2,
  "remainingThisMonth": 998,
  "resetsAt": "2026-12-01T00:00:00.000Z",
  "maxKeys": 5
}
```

This is an illustrative `apiRequests` object, not a live account balance. The actual response determines your allowance and reset date. The usage request itself counts, so its reported balance includes that request.

### Two balances

| Balance | What it measures | What changes it |
| - | - | - |
| API requests | Admitted Partner API calls in the current UTC calendar month | Account reads, uploads, polling, continuations, findings and export requests; admitted validation or handler failures also count |
| Analysis credits | The existing account allowance for new evidence packages | The canonical analysis workflow reserves and consumes or releases the credit; content-identical retries, continuations and report reads do not use an additional analysis credit |

All keys **and Partner API OAuth grants** share the account's request allowance. Creating or rotating a key does not reset it. Requests rejected during authentication, approval, rate, concurrency or quota checks are not admitted and do not spend a request.

Limits default to 1,000 requests per UTC calendar month and 60 requests per minute. Your administrator can change both. A limit change preserves usage already recorded; lowering a limit below usage blocks further requests until the allowance increases or resets. A monthly allowance of zero blocks all Partner API calls, including `/usage`; use the dashboard to view the balance.

After admission, responses include:

| Header | Meaning |
| - | - |
| `X-Request-Id` | Correlation identifier to provide to support |
| `Ultiwrite-Api-Version` | API contract revision |
| `X-Api-Requests-Limit` | Saved monthly request allowance |
| `X-Api-Requests-Remaining` | Remaining allowance immediately after this request was admitted |
| `X-Api-Requests-Reset` | Next UTC calendar-month reset as an ISO timestamp |

Another concurrent request may reduce the remaining balance after the snapshot was taken. Rate, quota and concurrency refusals include `Retry-After`. Dashboard administration and signed staging transport are not additional Partner API requests; minting a signed upload link is one Partner API request, and the eventual analysis retains its normal analysis-credit checks.

## 3. Submit evidence and read the result

Use `multipart/form-data` with one to six `files` parts. Do not manually set its Content-Type boundary. The optional `documentForensics` form field accepts exactly `true` or `false`; omit it to let the engine infer relevance from supported contents.

```bash theme={null}
curl --fail-with-body -sS "$ULTIWRITE_API_BASE/cases" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY" \
  -F "files=@./company-profile.pdf" \
  -F "files=@./bank-statement.csv"
```

The response contains the case id, saved workflow state, links and next action. A `201` indicates a newly completed analysis; a `202` indicates saved processing. A repeated identical package may return `200` and `state: "already_persisted"`. Repeating the same files and frozen forensics choice recovers the same account-scoped case without another analysis credit; each admitted HTTP request still counts.

For larger evidence packages, obtain a signed upload link:

```bash theme={null}
curl --fail-with-body -sS -X POST "$ULTIWRITE_API_BASE/upload-links" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"documentForensics": false}'
```

Open the returned URL in the guided uploader, or follow the signed staging protocol in the developer guide. The production hosting platform limits a direct request body to approximately 4.5 MB, even where the engine accepts larger evidence files.

An upload link is single use and valid for up to 30 minutes, capped by the key's expiration. It is bound to the issuing credential and account. Key status and API approval are rechecked on use; possession of an old link does not override a removed grant. Treat the signed URL as a secret too.

Use the actual returned identifiers in these requests:

```bash theme={null}
# Replace these with ids returned by your own account's API responses.
ULTIWRITE_CASE_ID=case_id_from_response
ULTIWRITE_REPORT_ID=report_id_from_response

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/cases/$ULTIWRITE_CASE_ID" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"

# Call only when the saved case supplies a continuation.
curl --fail-with-body -sS -X POST "$ULTIWRITE_API_BASE/cases/$ULTIWRITE_CASE_ID/continue" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/cases/$ULTIWRITE_CASE_ID/findings" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/cases/$ULTIWRITE_CASE_ID/brief" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"

curl --fail-with-body -sS "$ULTIWRITE_API_BASE/reports/$ULTIWRITE_REPORT_ID/export" \
  -H "Authorization: Bearer $ULTIWRITE_API_KEY"
```

Status reads do not advance processing. Follow the returned continuation and next action, use bounded polling and honor `Retry-After`. Read paginated findings using the response's snapshot, page token and cursors; do not manufacture them. Export returns account-authenticated delivery links and entitled inline data. An API key does not authenticate the website's PDF, Excel or ZIP download routes; sign in to the same account for those downloads.

A complete workflow means a report was saved. It does not mean an opportunity was approved or that missing evidence was clear.

## 4. Rotate and revoke

For planned rotation, create a replacement, update your server secret, confirm `GET /me` with the new key, then revoke the previous key in the dashboard. Leave a key slot available for rotation.

Revocation blocks the local credential before the Unkey cleanup request is attempted. If provider cleanup is pending, the dashboard provides a retry action; the locally revoked key remains blocked. A revoked key cannot be reactivated.

Removing API approval blocks every key and Partner API OAuth grant without erasing the key list or request history. Customers can still revoke their own keys while approval is off. Reenabling approval restores eligibility for otherwise active, unexpired keys; revoke keys as well when permanent invalidation is intended. Password resets, deactivated users, closed or suspended organizations, and changed account bindings also invalidate the affected credential.

## 5. Handle errors

Responses use `{"error":{"code":"…","message":"…","requestId":"…"}}`.

| Status / code | Action |
| - | - |
| `401 unauthorized` | Send the Authorization bearer header |
| `401 invalid_token` | Replace an expired, revoked, mismatched or otherwise invalid key; check the intended API |
| `403 api_access_denied` | Request explicit administrator approval |
| `403 insufficient_scope` | Use a credential with the required permissions |
| `429 api_quota_exceeded` | Check dashboard usage; wait for the UTC monthly reset or request a larger allowance |
| `429 rate_limited` | Back off using `Retry-After`; reduce concurrency or polling |
| `404 not_found` | Check the identifier and deployment availability; records in another account are not disclosed |
| `400 invalid_input` | Correct the request; an admitted validation failure still uses a request |
| `503 service_unavailable` | Retry with bounded backoff; authentication, provider or database availability could not be established |

Do not retry invalid credentials indefinitely. For support, provide the request id and status/code, never the API key.

## 6. OAuth and existing integrations

OAuth 2.1 with PKCE remains available for integrations that need an interactive customer authorization flow. Use the exact Partner API resource `https://dwsoffshorepartners.com/api/v1`; an MCP token is bound to a different resource. OAuth Partner API requests require the same explicit approval and share the same account request limits.

The older provisioned `uw_live_` credentials apply to the legacy routes separately identified in OpenAPI. Dashboard `ultiwrite_live_` keys authorize the Partner API operations above. They do not grant staff, billing, admin or legacy compute access.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.