Create connected practice API key
/v1/practices/{practiceId}/api-keysCreates 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.jsonResponse 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
practiceIdstringrequiredPattern: ^prac_[0-9a-hjkmnp-tv-z]{26}$
Headers
Affinity-VersionstringSelects 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-KeystringrequiredRequest body specification application/json
allowedIpsstring[] | nullShow 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 | nullShow expiresAt fields
Any of · 1: string | null
Any of · 1: string
string
Any of · 2: null
null
Any of · 2: null
null
namestringrequiredscopesstring[] | nullShow 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
apiKeyobjectrequiredNo additional properties
Show apiKey fields
allowedIpsstring[]requiredShow allowedIps fields
Array items · string
string
createdAtstringrequiredexpiresAtstring | nullrequiredShow expiresAt fields
Any of · 1: string
string
Any of · 2: null
null
idstringrequiredkeyPrefixstringrequiredlastUsedAtstring | nullrequiredShow lastUsedAt fields
Any of · 1: string
string
Any of · 2: null
null
modestringrequiredAllowed: "live", "test"
namestringrequiredrevokedAtstring | nullrequiredShow revokedAt fields
Any of · 1: string
string
Any of · 2: null
null
scopesstring[]requiredShow 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"
statusstringrequiredAllowed: "active", "expired", "revoked"
secretstringrequiredserviceAccountobjectrequiredNo additional properties
Show serviceAccount fields
apiVersionstringrequiredShow apiVersion fields
Any of · 1: string
string
Allowed: "2026-09-28"
displayNamestringrequiredidstringrequiredmaxScopesstring[]requiredShow 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"
organizationIdstringrequiredstatusstringrequiredAllowed: "active", "disabled"
subjectIdstringrequiredsubjectTypestringrequiredAllowed: "practice", "internal_service", "pharmacy", "platform", "user"
400HTTP 400
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri
401Unauthorized
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri
403Forbidden
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri
404Not found
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri
409Conflict
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri
429Too many requests
application/json
codestringrequireddataobjectdetailstringrequiredinstancestringrequiredrequestIdstringrequiredstatusintegerrequiredMinimum: 400
Maximum: 599
titlestringrequiredtraceIdstringtypestringrequiredFormat: uri