Skip to content

Create connected practice API key

POST/v1/practices/{practiceId}/api-keys

Creates a practice API key for a connected practice. Requires a platform key with service_keys:write and every requested scope. The practice key uses the platform key's Test or Live mode and cannot outlive it. Requires Idempotency-Key for safe retries; the secret is returned in the encrypted replay response for 24 hours.

Request example

Replace example values with your Test data. Check the field rules below before you send a request.

{
  "allowedIps": [
    "<string>"
  ],
  "expiresAt": "<string>",
  "name": "<string>",
  "scopes": [
    "catalog:read"
  ]
}
curl -X POST 'https://api.affinityrx.com/v1/practices/{practiceId}/api-keys' \
  -H "Authorization: Bearer $AFFINITY_API_KEY" \
  -H 'Affinity-Version: 2026-09-28' \
  -H 'Idempotency-Key: <Idempotency-Key>' \
  -H 'Content-Type: application/json' \
  --data @request.json

Response example

These examples show the body structure. Values can differ. Select a status code to see its response.

{
  "apiKey": {
    "allowedIps": [
      "<string>"
    ],
    "createdAt": "<string>",
    "expiresAt": "<string>",
    "id": "<string>",
    "keyPrefix": "<string>",
    "lastUsedAt": "<string>",
    "mode": "live",
    "name": "<string>",
    "revokedAt": "<string>",
    "scopes": [
      "catalog:read"
    ],
    "status": "active"
  },
  "secret": "<string>",
  "serviceAccount": {
    "apiVersion": "2026-09-28",
    "displayName": "<string>",
    "id": "<string>",
    "maxScopes": [
      "catalog:read"
    ],
    "organizationId": "<string>",
    "status": "active",
    "subjectId": "<string>",
    "subjectType": "practice"
  }
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 400,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 401,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 403,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 404,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 409,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 429,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}

Implementation specification

Use these field types and limits to build your integration. Download the OpenAPI document for the complete contract.

Path parameters

practiceIdstringrequired

Pattern: ^prac_[0-9a-hjkmnp-tv-z]{26}$

Headers

Affinity-Versionstring

Selects the HTTP API contract for this request only. When omitted, API-key requests use their service account’s stored version. Does not change the stored default.

Pin requests to 2026-09-28.

Idempotency-Keystringrequired

Request body specification application/json

allowedIpsstring[] | null
Show allowedIps fields
Any of · 1: string[]

Array items · string

Any of · 1: string

string

Pattern: ^(?:(?:\d{1,3}\.){3}\d{1,3}|(?:[a-f\d]{0,4}:){2,7}[a-f\d]{0,4})$

Any of · 2: string

string

Pattern: ^(?:(?:\d{1,3}\.){3}\d{1,3}|(?:[a-f\d]{0,4}:){2,7}[a-f\d]{0,4})$

Any of · 2: null

null

expiresAtstring | null | null
Show expiresAt fields
Any of · 1: string | null
Any of · 1: string

string

Any of · 2: null

null

Any of · 2: null

null

namestringrequired
scopesstring[] | null
Show scopes fields
Any of · 1: string[]

Array items · string

string

Allowed: "catalog:read", "selling_prices:read", "selling_prices:write", "catalog_pricing:read", "catalog_pricing:write", "formulation_defaults:read", "formulation_defaults:write", "practices:read", "practices:write", "service_keys:write", "locations:read", "locations:write", "orders:read", "orders:write", "orders:sign", "patients:read", "patients:write", "team:read", "team:write", "hosted_sessions:write", "webhooks:read", "webhooks:write"

Any of · 2: null

null

Response specifications

200Successful response

application/json

apiKeyobjectrequired

No additional properties

Show apiKey fields
allowedIpsstring[]required
Show allowedIps fields

Array items · string

string

createdAtstringrequired
expiresAtstring | nullrequired
Show expiresAt fields
Any of · 1: string

string

Any of · 2: null

null

idstringrequired
keyPrefixstringrequired
lastUsedAtstring | nullrequired
Show lastUsedAt fields
Any of · 1: string

string

Any of · 2: null

null

modestringrequired

Allowed: "live", "test"

namestringrequired
revokedAtstring | nullrequired
Show revokedAt fields
Any of · 1: string

string

Any of · 2: null

null

scopesstring[]required
Show scopes fields

Array items · string

string

Allowed: "catalog:read", "selling_prices:read", "selling_prices:write", "catalog_pricing:read", "catalog_pricing:write", "formulation_defaults:read", "formulation_defaults:write", "practices:read", "practices:write", "service_keys:write", "locations:read", "locations:write", "orders:read", "orders:write", "orders:sign", "patients:read", "patients:write", "team:read", "team:write", "hosted_sessions:write", "webhooks:read", "webhooks:write"

statusstringrequired

Allowed: "active", "expired", "revoked"

secretstringrequired
serviceAccountobjectrequired

No additional properties

Show serviceAccount fields
apiVersionstringrequired
Show apiVersion fields
Any of · 1: string

string

Allowed: "2026-09-28"

displayNamestringrequired
idstringrequired
maxScopesstring[]required
Show maxScopes fields

Array items · string

string

Allowed: "catalog:read", "selling_prices:read", "selling_prices:write", "catalog_pricing:read", "catalog_pricing:write", "formulation_defaults:read", "formulation_defaults:write", "practices:read", "practices:write", "service_keys:write", "locations:read", "locations:write", "orders:read", "orders:write", "orders:sign", "patients:read", "patients:write", "team:read", "team:write", "hosted_sessions:write", "webhooks:read", "webhooks:write"

organizationIdstringrequired
statusstringrequired

Allowed: "active", "disabled"

subjectIdstringrequired
subjectTypestringrequired

Allowed: "practice", "internal_service", "pharmacy", "platform", "user"

400HTTP 400

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

401Unauthorized

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

403Forbidden

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

404Not found

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

409Conflict

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

429Too many requests

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

Type to search…

↑↓ navigate↵ selectEsc close