Skip to content

Register user

POST/v1/practices/{practiceId}/users

Requires team:write and Idempotency-Key. Registers a practice member without an invitation. Test requires synthetic .test emails and Affinity Test NPIs. Live requires approved integration and practice access. Identity attestation records the integration's assertion; it does not verify login email or clinical credentials. Existing memberships and verified provider records are preserved. Use the returned user ID for orders and signing.

Request example

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

{
  "externalId": "<string>",
  "email": "<string>",
  "name": "<string>",
  "role": "administrator",
  "roles": [
    "owner"
  ],
  "profileDetails": {
    "firstName": "<string>",
    "middleName": "<string>",
    "lastName": "<string>",
    "namePrefix": "<string>",
    "nameSuffix": "<string>",
    "fax": "<string>",
    "specialties": [
      {
        "code": "<string>",
        "description": "<string>",
        "primary": false
      }
    ],
    "addresses": [
      {
        "purpose": "<string>",
        "line1": "<string>",
        "line2": "<string>",
        "city": "<string>",
        "state": "<string>",
        "postalCode": "<string>",
        "country": "<string>",
        "phone": "<string>",
        "fax": "<string>"
      }
    ],
    "otherNames": [
      {
        "name": "<string>",
        "credentials": "<string>",
        "type": "<string>"
      }
    ],
    "identifiers": [
      {
        "identifier": "<string>",
        "issuer": "<string>",
        "state": "<string>",
        "description": "<string>"
      }
    ],
    "endpoints": [
      {
        "endpoint": "<string>",
        "type": "<string>",
        "description": "<string>",
        "use": "<string>",
        "affiliation": "<string>"
      }
    ],
    "certifications": [
      {
        "name": "<string>",
        "issuer": "<string>",
        "expiresAt": "<string>"
      }
    ]
  },
  "npi": "<string>",
  "licenses": [
    {
      "state": "<string>",
      "licenseNumber": "<string>",
      "expiresAt": "<string>"
    }
  ],
  "legalName": "<string>",
  "displayName": "<string>",
  "credentials": "<string>",
  "address": {
    "city": "<string>",
    "country": "<string>",
    "line1": "<string>",
    "line2": "<string>",
    "postalCode": "<string>",
    "state": "<string>"
  },
  "phone": "<string>",
  "locationIds": [
    "loc_01j2y8m6jcc9tt24af5pw9x1bc"
  ],
  "identityAttestation": true
}
curl -X POST 'https://api.affinityrx.com/v1/practices/{practiceId}/users' \
  -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.

{
  "object": "registered_user",
  "id": "user_01j2y8m6jcc9tt24af5pw9x1bc",
  "practiceId": "prac_01j2y8m6jcc9tt24af5pw9x1bc",
  "memberId": "mbr_01j2y8m6jcc9tt24af5pw9x1bc",
  "prescriberId": "prov_01j2y8m6jcc9tt24af5pw9x1bc",
  "externalId": "<string>",
  "livemode": false
}
{
  "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": 422,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 429,
  "title": "<string>",
  "traceId": "<string>",
  "type": "<string>"
}
{
  "code": "<string>",
  "data": "<string>",
  "detail": "<string>",
  "instance": "<string>",
  "requestId": "<string>",
  "status": 503,
  "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-7][0-9a-hjkmnp-tv-z]{25}$

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

externalIdstringrequired
emailstringrequired

Pattern: ^[^\s@]+@[^\s@]+\.[^\s@]+$

namestringrequired
rolestringrequired

Allowed: "administrator", "prescriber", "clinical_staff", "billing", "developer"

rolesstring[] | null
Show roles fields
Any of · 1: string[]

Array items · string

string

Allowed: "owner", "administrator", "prescriber", "clinical_staff", "billing", "developer"

Any of · 2: null

null

profileDetailsobject | null
Show profileDetails fields
Any of · 1: object
firstNamestring | null
Show firstName fields
Any of · 1: string

string

Any of · 2: null

null

middleNamestring | null
Show middleName fields
Any of · 1: string

string

Any of · 2: null

null

lastNamestring | null
Show lastName fields
Any of · 1: string

string

Any of · 2: null

null

namePrefixstring | null
Show namePrefix fields
Any of · 1: string

string

Any of · 2: null

null

nameSuffixstring | null
Show nameSuffix fields
Any of · 1: string

string

Any of · 2: null

null

faxstring | null
Show fax fields
Any of · 1: string

string

Any of · 2: null

null

specialtiesobject[] | null
Show specialties fields
Any of · 1: object[]

Array items · object

codestringrequired
descriptionstringrequired
primarybooleanrequired
Any of · 2: null

null

addressesobject[] | null
Show addresses fields
Any of · 1: object[]

Array items · object

purposestringrequired
line1stringrequired
line2stringrequired
citystringrequired
statestringrequired
postalCodestringrequired
countrystringrequired
phonestringrequired
faxstringrequired
Any of · 2: null

null

otherNamesobject[] | null
Show otherNames fields
Any of · 1: object[]

Array items · object

namestringrequired
credentialsstringrequired
typestringrequired
Any of · 2: null

null

identifiersobject[] | null
Show identifiers fields
Any of · 1: object[]

Array items · object

identifierstringrequired
issuerstringrequired
statestringrequired
descriptionstringrequired
Any of · 2: null

null

endpointsobject[] | null
Show endpoints fields
Any of · 1: object[]

Array items · object

endpointstringrequired
typestringrequired
descriptionstringrequired
usestringrequired
affiliationstringrequired
Any of · 2: null

null

certificationsobject[] | null
Show certifications fields
Any of · 1: object[]

Array items · object

namestringrequired
issuerstringrequired
expiresAtstringrequired
Any of · 2: null

null

Any of · 2: null

null

npistring | null
Show npi fields
Any of · 1: string

string

Any of · 2: null

null

licensesobject[] | null
Show licenses fields
Any of · 1: object[]

Array items · object

statestringrequired
licenseNumberstringrequired
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

Any of · 2: null

null

legalNamestring | null | null
Show legalName fields
Any of · 1: string | null
Any of · 1: string

string

Any of · 2: null

null

Any of · 2: null

null

displayNamestring | null | null
Show displayName fields
Any of · 1: string | null
Any of · 1: string

string

Any of · 2: null

null

Any of · 2: null

null

credentialsstring | null | null
Show credentials fields
Any of · 1: string | null
Any of · 1: string

string

Any of · 2: null

null

Any of · 2: null

null

addressobject | null | null
Show address fields
Any of · 1: object | null
Any of · 1: object
citystringrequired
countrystringrequired
line1stringrequired
line2string | null
Show line2 fields
Any of · 1: string

string

Any of · 2: null

null

postalCodestringrequired
statestringrequired
Any of · 2: null

null

Any of · 2: null

null

phonestring | null | null
Show phone fields
Any of · 1: string | null
Any of · 1: string

string

Any of · 2: null

null

Any of · 2: null

null

locationIdsstring[] | null
Show locationIds fields
Any of · 1: string[]

Array items · string

string

Pattern: ^loc_[0-7][0-9a-hjkmnp-tv-z]{25}$

Any of · 2: null

null

identityAttestationbooleanrequired

Allowed: true

Response specifications

200Successful response

application/json

objectstringrequired

Allowed: "registered_user"

idstringrequired

Pattern: ^user_[0-7][0-9a-hjkmnp-tv-z]{25}$

practiceIdstringrequired

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

memberIdstringrequired

Pattern: ^mbr_[0-7][0-9a-hjkmnp-tv-z]{25}$

prescriberIdstring | nullrequired
Show prescriberId fields
Any of · 1: string

string

Pattern: ^prov_[0-7][0-9a-hjkmnp-tv-z]{25}$

Any of · 2: null

null

externalIdstringrequired
livemodebooleanrequired
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

422Validation error

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

503HTTP 503

application/json

codestringrequired
dataobject
detailstringrequired
instancestringrequired
requestIdstringrequired
statusintegerrequired

Minimum: 400

Maximum: 599

titlestringrequired
traceIdstring
typestringrequired

Format: uri

Type to search…

↑↓ navigate↵ selectEsc close