Skip to content

Docs: by job

Organizations and members

Keys call the API; people manage the account. Invite your team with a role, each signing in with an authenticator app, and decide who manages the keys.

Read as markdown

Payerworks writes and explains files; it sends nothing to a payer. Every file a route writes says transmitted: false, and is yours to send on your own connection. A test key is for invented data only, never a real patient.

Keys are how your systems call the API; members are how people manage the account. An organization holds one account (the keys one key started) and the people who manage it, each with a role: owner, admin, developer or viewer.

A member signs in at payerworks.com/console with a password and a code from an authenticator app, always: there is no sign-in without the app. A sign-in never calls a claim, eligibility, file, sandbox, MCP or batch job route; those take a key. With a sign-in, a member manages the account’s keys, webhooks, enrollments, SFTP user and notice address, as far as their role allows, and reads its audit log.

These routes take a sign-in’s ID token as the bearer, Authorization: Bearer <ID token>, where every other route takes a key. Where the sign-in belongs to several organizations, the Payerworks-Organization header names one; a member’s call to one of the account’s routes (its keys, webhooks, events, enrollments, SFTP user, notice address or audit log) names the key it acts on in the Payerworks-Key header (its key id, as GET /v1/org/keys lists them), and is answered as that key would be answered, within the member’s role. Organizations are open only where Payerworks has turned them on; elsewhere nobody can sign in, a sign-in’s token is answered 501 org_not_offered, and keys work as before.

Routes

Each route shows its call with curl and with the two clients, then its real answer, shortened, and the fields it holds. The client calls assume one client made once, const pw = new Payerworks() in JavaScript or pw = payerworks.Payerworks() in Python, each reading PAYERWORKS_API_KEY and PAYERWORKS_BASE_URL, and body is the request.json shown.

GET/v1/org/roles

The roles

The one role table: every role, every permission and the owner’s rules. Readable with a key or a sign-in.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org/roles" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "roles": [
    {
      "role": "owner",
      "words": "Everything an admin does, and the owner's own decisions: owners, the organization's settings, and revoking a removed member's keys.",
      "permissions": [
        "org.read",
        "members.read"
      ]
    },
    {
      "role": "admin",
      "words": "Manages people (never an owner) and every key, webhook, enrollment and SFTP user, test or live.",
      "permissions": [
        "org.read",
        "members.read"
      ]
    }
  ],
  "permissions": [
    {
      "permission": "org.read",
      "words": "See the organization, its account and its settings."
    },
    {
      "permission": "org.update",
      "words": "Rename the organization and choose who manages keys."
    }
  ],
  "owner_rules": [
    "Only an owner invites an owner, makes a member an owner, or changes or removes an owner.",
    "An organization always keeps at least one owner: the last owner cannot be removed, leave, or be given another role."
  ]
}

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in /openapi.json.

Field, Type, What it is
FieldTypeWhat it is
roleslist of objectEvery role, the least last.
permissionslist of object
owner_ruleslist of stringThe owner’s rules: 4 sentences.

GET/v1/org/memberships

Your organizations

The organizations this sign-in belongs to, with its role in each. A sign-in only.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org/memberships" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "data": [
    {
      "org_id": "pwo_25323f4c596673808d9aa7b4",
      "name": "Sample Dental",
      "role": "owner",
      "member_id": "pwm_4a5764717e8b98a5"
    }
  ]
}
Field, Type, What it is
FieldTypeWhat it is
datalist of objectAt most 20.

POST/v1/org

Make an organization

Make an organization for an account: name it and give one key of the account (api_key). The key proves the account and is checked and not kept; you become its owner. An account belongs to one organization. A sign-in only.

Request

curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/org" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
request.jsonJSON
{
  "name": "Sample Dental",
  "api_key": "pw_test_qk3x..."
}
The answer (201)JSON
{
  "org_id": "pwo_25323f4c596673808d9aa7b4",
  "name": "Sample Dental",
  "account_id": "pwk_500de6d41a6eacebb6e34d08",
  "owners": 1,
  "members": 1,
  "key_management": "keys_and_members",
  "created_at": "2026-10-19T15:00:00.000Z",
  "you": {
    "member_id": "pwm_4a5764717e8b98a5",
    "role": "owner",
    "permissions": [
      "org.read",
      "members.read"
    ]
  },
  "kept": "An organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call."
}

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in /openapi.json.

Field, Type, What it is
FieldTypeWhat it is
org_idstringpwo_ and 24 lowercase hexadecimal characters.
namestring1 to 80 characters.
account_idstringThe account it manages: the keys one key started.
ownersinteger
membersinteger
key_managementone of "keys_and_members", "members_only"keys_and_members: An API key of the account may still make, rotate and revoke the account's keys, as before the organization; members may too. members_only: Only a signed-in member with the role for it makes, rotates and revokes the account's keys; an API key is refused (keys_managed_by_members).
created_atstring
updated_atstring or null
youOrgYou
pending_invitationsintegerGET /v1/org only: invitations not yet accepted or canceled.
keptstringAn organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call.

GET/v1/org

Your organization

The organization, with your role and what it lets you do. Name it in the Payerworks-Organization header when your sign-in belongs to several. A sign-in only.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "org_id": "pwo_25323f4c596673808d9aa7b4",
  "name": "Sample Dental",
  "account_id": "pwk_500de6d41a6eacebb6e34d08",
  "owners": 1,
  "members": 1,
  "key_management": "keys_and_members",
  "created_at": "2026-10-19T15:00:00.000Z",
  "you": {
    "member_id": "pwm_4a5764717e8b98a5",
    "role": "owner",
    "permissions": [
      "org.read",
      "members.read"
    ]
  },
  "kept": "An organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call.",
  "pending_invitations": 0
}

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in /openapi.json.

Field, Type, What it is
FieldTypeWhat it is
org_idstringpwo_ and 24 lowercase hexadecimal characters.
namestring1 to 80 characters.
account_idstringThe account it manages: the keys one key started.
ownersinteger
membersinteger
key_managementone of "keys_and_members", "members_only"keys_and_members: An API key of the account may still make, rotate and revoke the account's keys, as before the organization; members may too. members_only: Only a signed-in member with the role for it makes, rotates and revokes the account's keys; an API key is refused (keys_managed_by_members).
created_atstring
updated_atstring or null
youOrgYou
pending_invitationsintegerGET /v1/org only: invitations not yet accepted or canceled.
keptstringAn organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call.

PUT/v1/org

Change your organization

Rename it, or choose who manages the account’s keys (key_management): keys_and_members, the default, where an API key of the account may still make, rotate and revoke its keys, or members_only, where only a signed-in member with the role for it may. An owner’s.

Request

curl -sS -X PUT "$PAYERWORKS_BASE_URL/v1/org" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
request.jsonJSON
{
  "name": "Sample Dental Group"
}
The answer (200)JSON
{
  "org_id": "pwo_25323f4c596673808d9aa7b4",
  "name": "Sample Dental Group",
  "account_id": "pwk_500de6d41a6eacebb6e34d08",
  "owners": 1,
  "members": 1,
  "key_management": "keys_and_members",
  "created_at": "2026-10-19T15:00:00.000Z",
  "you": {
    "member_id": "pwm_4a5764717e8b98a5",
    "role": "owner",
    "permissions": [
      "org.read",
      "members.read"
    ]
  },
  "kept": "An organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call."
}

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in /openapi.json.

Field, Type, What it is
FieldTypeWhat it is
org_idstringpwo_ and 24 lowercase hexadecimal characters.
namestring1 to 80 characters.
account_idstringThe account it manages: the keys one key started.
ownersinteger
membersinteger
key_managementone of "keys_and_members", "members_only"keys_and_members: An API key of the account may still make, rotate and revoke the account's keys, as before the organization; members may too. members_only: Only a signed-in member with the role for it makes, rotates and revokes the account's keys; an API key is refused (keys_managed_by_members).
created_atstring
updated_atstring or null
youOrgYou
pending_invitationsintegerGET /v1/org only: invitations not yet accepted or canceled.
keptstringAn organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call.

GET/v1/org/members

The members

Every member: the email address of the sign-in, the name, the role, when they joined and who invited them. A sign-in only.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org/members" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "data": [
    {
      "member_id": "pwm_4a5764717e8b98a5",
      "email": "jane.doe@sample-dental.com",
      "name": "Jane Doe",
      "role": "owner",
      "joined_at": "2026-10-19T15:00:00.000Z",
      "invited_by": null,
      "updated_at": null,
      "you": true
    },
    {
      "member_id": "pwm_727f8c99a6b3c0cd",
      "email": "john.doe@sample-dental.com",
      "name": "John Doe",
      "role": "developer",
      "joined_at": "2026-10-19T15:00:00.000Z",
      "invited_by": "pwm_4a5764717e8b98a5",
      "updated_at": null,
      "you": false
    }
  ]
}
Field, Type, What it is
FieldTypeWhat it is
datalist of OrgMemberAt most 200.

PUT/v1/org/members/{id}

Change a member’s role

A new role: owner, admin, developer or viewer. Only an owner makes, changes or demotes an owner, and the last owner is never demoted.

Request

curl -sS -X PUT "$PAYERWORKS_BASE_URL/v1/org/members/pwm_727f8c99a6b3c0cd" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
request.jsonJSON
{
  "role": "viewer"
}
The answer (200)JSON
{
  "member_id": "pwm_727f8c99a6b3c0cd",
  "email": "john.doe@sample-dental.com",
  "name": "John Doe",
  "role": "viewer",
  "joined_at": "2026-10-19T15:00:00.000Z",
  "invited_by": "pwm_4a5764717e8b98a5",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "you": false
}
Field, Type, What it is
FieldTypeWhat it is
member_idstring
emailstringThe sign-in’s verified email address.
namestringAt most 120 characters.
roleone of "owner", "admin", "developer", "viewer"
joined_atstring
invited_bystring or nullThe member who invited them; null for the one who made the organization.
updated_atstring or null
youbooleanTrue for the member asking.

DELETE/v1/org/members/{id}

Remove a member

The member loses access at once. revoke_keys=true, an owner’s choice, also revokes the keys they made or rotated in the console (each one whose secret they were shown); left out, those keys keep working and are listed in the answer. The last owner is never removed, and a member may remove themselves to leave.

Request

curl -sS -X DELETE "$PAYERWORKS_BASE_URL/v1/org/members/pwm_727f8c99a6b3c0cd" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "removed": {
    "member_id": "pwm_727f8c99a6b3c0cd",
    "email": "john.doe@sample-dental.com",
    "name": "John Doe",
    "role": "viewer",
    "joined_at": "2026-10-19T15:00:00.000Z",
    "invited_by": "pwm_4a5764717e8b98a5",
    "updated_at": "2026-10-19T15:00:00.000Z"
  },
  "left": false,
  "keys_made": [],
  "keys_rotated": [],
  "keys_revoked": [],
  "keys_not_revoked": []
}
Field, Type, What it is
FieldTypeWhat it is
removedOrgMember
leftbooleanTrue when the member removed themselves.
keys_madelist of stringThe keys the member made in the console; null when they could not be read (keys_note says so).
keys_rotatedlist of stringThe keys the member rotated in the console without making them; null when they could not be read.
keys_revokedlist of stringRevoked by this removal, as an owner asked (revoke_keys=true): made or rotated.
keys_not_revokedlist of stringAsked to be revoked (revoke_keys=true) and still working: the revocation failed, or the key was past the 25 one removal revokes. Revoke each with DELETE /v1/keys/{id}.
keys_notestringPresent only when the member was removed but their keys could not be read: what to do next.

GET/v1/org/invitations

The invitations waiting

Every invitation not yet accepted or canceled: the address, the role, who invited and until when the link works. A sign-in only.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org/invitations" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "data": [
    {
      "invitation_id": "pwi_03101d2a3744515e",
      "email": "john.doe@sample-dental.com",
      "role": "developer",
      "invited_by": "pwm_4a5764717e8b98a5",
      "created_at": "2026-10-19T15:00:00.000Z",
      "expires_at": "2026-10-26T15:00:00.000Z",
      "expired": false
    },
    {
      "invitation_id": "pwi_4d5a6774818e9ba8",
      "email": "rick.roe@sample-dental.com",
      "role": "viewer",
      "invited_by": "pwm_4a5764717e8b98a5",
      "created_at": "2026-10-19T15:00:00.000Z",
      "expires_at": "2026-10-26T15:00:00.000Z",
      "expired": false
    }
  ]
}
Field, Type, What it is
FieldTypeWhat it is
datalist of OrgInvitationAt most 50 waiting.

POST/v1/org/invitations

Invite a person

Invite a person by email with a role. Payerworks emails a link that works for 7 days, and only for a sign-in at that verified address; the email names neither the organization nor who invited. An organization sends at most 25 invitations a UTC day.

Request

curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/org/invitations" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
request.jsonJSON
{
  "email": "john.doe@sample-dental.com",
  "role": "developer"
}
The answer (201)JSON
{
  "invitation_id": "pwi_03101d2a3744515e",
  "email": "john.doe@sample-dental.com",
  "role": "developer",
  "invited_by": "pwm_4a5764717e8b98a5",
  "created_at": "2026-10-19T15:00:00.000Z",
  "expires_at": "2026-10-26T15:00:00.000Z",
  "expired": false,
  "emailed": true
}
Field, Type, What it is
FieldTypeWhat it is
invitation_idstringpwi_ and 16 lowercase hexadecimal characters.
emailstring
roleone of "owner", "admin", "developer", "viewer"
invited_bystring
created_atstring
expires_atstring
expiredbooleanThe link works for 7 days.
emailedbooleanPOST only: whether the email went.
join_urlstringPOST only, when the email did not go: the link to hand to the person yourself.
canceledthe value trueDELETE only.

DELETE/v1/org/invitations/{id}

Cancel an invitation

The link stops working at once.

Request

curl -sS -X DELETE "$PAYERWORKS_BASE_URL/v1/org/invitations/pwi_4d5a6774818e9ba8" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "invitation_id": "pwi_4d5a6774818e9ba8",
  "email": "rick.roe@sample-dental.com",
  "role": "viewer",
  "invited_by": "pwm_4a5764717e8b98a5",
  "created_at": "2026-10-19T15:00:00.000Z",
  "expires_at": "2026-10-26T15:00:00.000Z",
  "expired": false,
  "canceled": true
}
Field, Type, What it is
FieldTypeWhat it is
invitation_idstringpwi_ and 16 lowercase hexadecimal characters.
emailstring
roleone of "owner", "admin", "developer", "viewer"
invited_bystring
created_atstring
expires_atstring
expiredbooleanThe link works for 7 days.
emailedbooleanPOST only: whether the email went.
join_urlstringPOST only, when the email did not go: the link to hand to the person yourself.
canceledthe value trueDELETE only.

POST/v1/org/join

Accept an invitation

Accept an invitation with the token from its link (the part after #join=). The sign-in’s verified email address must be the address the invitation was sent to. A sign-in only.

Request

curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/org/join" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
request.jsonJSON
{
  "token": "3uv4BRIfLDlGU2BteoeUoa67yNXi7_wJFiMwPUpXZHE"
}
The answer (201)JSON
{
  "organization": {
    "org_id": "pwo_25323f4c596673808d9aa7b4",
    "name": "Sample Dental Group",
    "account_id": "pwk_500de6d41a6eacebb6e34d08",
    "owners": 1,
    "members": 2,
    "key_management": "keys_and_members",
    "created_at": "2026-10-19T15:00:00.000Z",
    "you": {
      "member_id": "pwm_727f8c99a6b3c0cd",
      "role": "developer",
      "permissions": [
        "org.read",
        "members.read"
      ]
    },
    "kept": "An organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call."
  },
  "member": {
    "member_id": "pwm_727f8c99a6b3c0cd",
    "email": "john.doe@sample-dental.com",
    "name": "John Doe",
    "role": "developer",
    "joined_at": "2026-10-19T15:00:00.000Z",
    "invited_by": "pwm_4a5764717e8b98a5",
    "updated_at": null,
    "you": true
  }
}

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in /openapi.json.

Field, Type, What it is
FieldTypeWhat it is
organizationOrganization
memberOrgMember

GET/v1/org/keys

The account’s keys

Every key of the organization’s account, test and live, as GET /v1/keys lists them, with who made each: a member in the console, or a key. Never a key itself. A sign-in only.

Request

curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/org/keys" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
The answer (200)JSON
{
  "account_id": "pwk_500de6d41a6eacebb6e34d08",
  "data": [
    {
      "key_id": "pwk_500de6d41a6eacebb6e34d08",
      "name": "Server",
      "mode": "test",
      "last_four": "4Lvg",
      "created_at": "2026-10-19T12:00:00.000Z",
      "expires_at": null,
      "expired": false,
      "revoked_at": null,
      "rotated_at": null,
      "previous_secret_accepted_until": null,
      "current": false,
      "made_by": {
        "kind": "key",
        "id": null
      }
    }
  ]
}
Field, Type, What it is
FieldTypeWhat it is
account_idstring
datalist of objectEvery key of the account, test and live; never a key itself.

Reading the answer

  • GET /v1/org answers the organization with you: your member id, your role and the permissions it gives. The console shows a control only for a permission the API answered.
  • GET /v1/org/roles is the one role table, the same for every organization, and readable with a key too.
  • A removal answers the keys the member made in the console: keys_revoked when an owner asked for revoke_keys=true, and keys_not_revoked otherwise, so nothing is revoked as a side effect.
  • An invitation that could not be emailed answers emailed: false with its link in join_url, to hand to the person yourself.

Troubleshooting

  • org_session_required (401): The route needs a member’s console sign-in, not an API key. GET /v1/org/roles is the one a key may read.
  • org_choose (400): The sign-in belongs to several organizations: name one in the Payerworks-Organization header.
  • org_role_forbidden (403): Your role does not allow that; needs names the permission, and GET /v1/org/roles which roles hold it.
  • org_last_owner (409): An organization always keeps at least one owner. Make another member an owner first, then step down or leave.
  • org_invitation_email_mismatch (403): An invitation admits only a sign-in whose verified email address is the one it was sent to. Sign in with that address.
  • org_acting_key_required (400): A member’s call to one of the account’s routes names the key it acts on in the Payerworks-Key header.

Every refusal these routes may answer, with its status. Any route may also answer the codes every route shares, on Every error.

Code, Status, What it means
CodeStatusWhat it means
invalid_org_invitation_id400An invitation id is pwi_ followed by 16 lowercase hexadecimal characters.
invalid_org_member_id400A member id is pwm_ followed by 16 lowercase hexadecimal characters.
invalid_org_request400The request is not what this route takes: errors names each field and why.
org_acting_key_required400Name the key this change is for in the Payerworks-Key header (its key id; GET /v1/org/keys lists them).
org_choose400This sign-in belongs to several organizations: name one in the Payerworks-Organization header (GET /v1/org/memberships lists them).
org_session_invalid401The sign-in could not be checked, or it has ended. Sign in again.
org_session_required401This route needs a member's console sign-in, not an API key. Sign in at payerworks.com/console.
keys_managed_by_members403This account's organization chose that only its signed-in members manage keys. Make, rotate or revoke the key at payerworks.com/console.
org_email_not_verified403Confirm this sign-in's email address first: the code was emailed when the sign-in was made.
org_invitation_email_mismatch403This invitation was sent to another address. Sign in with the address the email reached.
org_key_not_usable403The api_key given is not a usable key (unknown, revoked or expired), so it proves no account.
org_not_a_member403This sign-in belongs to no organization yet. Make one with POST /v1/org, or open an invitation's link.
org_owner_only403Only an owner may do that: invite or make an owner, change or remove an owner, revoke a removed member's keys, or change the organization's settings.
org_role_forbidden403Your role in this organization does not allow that. GET /v1/org/roles says which role does.
org_session_not_accepted403A member's sign-in manages an account; it does not make this call. Call this route with an API key.
org_acting_key_not_found404The organization's account has no usable key with that id.
org_invitation_not_found404No pending invitation matches. It may have been accepted or canceled; ask for a new one.
org_member_not_found404This organization has no member with that id.
org_not_found404No organization with that id has this sign-in as a member.
org_account_taken409That key's account already belongs to an organization. Ask one of its owners to invite you.
org_already_member409That person is already a member of this organization.
org_changed_meanwhile409The organization changed while this request was made. Read it again and send the change again.
org_invitation_pending409An invitation to that address is already waiting. Cancel it to send another.
org_last_owner409An organization always keeps at least one owner. Make another member an owner first.
org_limit_reached409An organization holds at most 200 members and 50 pending invitations, and a sign-in belongs to at most 20 organizations.
org_invitation_expired410An invitation's link works for 7 days. Ask a member of the organization for a new one.
org_invitations_daily_limit429An organization sends at most 25 invitations a UTC day. Send more tomorrow.
org_not_offered501Organizations and member sign-in are not open on this deployment yet. Keys still work as before.
store_unavailable503We could not read or write this key's records just now; the message says what was not done. Retry in a moment.

Code lists

The roles

Role, What it may do, Permissions
RoleWhat it may doPermissions
ownerEverything an admin does, and the owner's own decisions: owners, the organization's settings, and revoking a removed member's keys.org.read, members.read, keys.read, webhooks.read, events.read, enrollments.read, sftp.read, usage.read, audit.read, keys.write_test, webhooks.write_test, enrollments.write_test, sftp.write_test, members.invite, members.change_role, members.remove, keys.write_live, webhooks.write_live, enrollments.write_live, sftp.write_live, contact.write, org.update
adminManages people (never an owner) and every key, webhook, enrollment and SFTP user, test or live.org.read, members.read, keys.read, webhooks.read, events.read, enrollments.read, sftp.read, usage.read, audit.read, keys.write_test, webhooks.write_test, enrollments.write_test, sftp.write_test, members.invite, members.change_role, members.remove, keys.write_live, webhooks.write_live, enrollments.write_live, sftp.write_live, contact.write
developerBuilds with test keys: makes and rotates them, sets their webhooks, enrollments and SFTP users; reads everything live.org.read, members.read, keys.read, webhooks.read, events.read, enrollments.read, sftp.read, usage.read, audit.read, keys.write_test, webhooks.write_test, enrollments.write_test, sftp.write_test
viewerReads everything (never a key itself, never a secret) and changes nothing. A seat for an auditor or a manager.org.read, members.read, keys.read, webhooks.read, events.read, enrollments.read, sftp.read, usage.read, audit.read

The owner’s rules

  • Only an owner invites an owner, makes a member an owner, or changes or removes an owner.
  • An organization always keeps at least one owner: the last owner cannot be removed, leave, or be given another role.
  • Removing a member never revokes the keys they made or rotated in the console unless an owner says so in that removal (revoke_keys=true): a key whose secret they were shown, made or rotated, is theirs to revoke.
  • Only an owner decides whether an API key may still manage the account's keys (key_management).

What an organization keeps

An organization is kept while it exists: its name, its members (each sign-in's email address, name and role) and its pending invitations (an email address and a role, for 7 days). Never a claim, a patient or the body of a call.

Example

organizations.mjs runs every step below against the API with a test key. It needs payerworks.mjs and sample-data.mjs beside it.

organizations.mjsJavaScript
// Payerworks example: organizations, members and roles. Docs: https://payerworks.com/docs/organizations
//
// Run it with Node 18 or later, with the JavaScript client (https://payerworks.com/sdk/payerworks.mjs)
// and sample-data.mjs beside this file:
//   PAYERWORKS_API_KEY=pw_test_... PAYERWORKS_BASE_URL=<the base URL shown with your key> node organizations.mjs
// A test key and invented data only. Payerworks sends nothing to a payer: every file it writes is yours.
//
// Keys call the API; members manage the account. A member signs in at payerworks.com/console with a
// password and an authenticator app, and the organization routes take that sign-in. With a key, this
// file reads the one role table and shows the refusal every other organization route gives a key.
import { pathToFileURL } from 'node:url';
import { Payerworks, PayerworksError } from './payerworks.mjs';
import { refusalOf } from './sample-data.mjs';

/** @param {Payerworks} pw */
export async function run(pw) {
  // 1. The one role table, the same for every organization: readable with a key.
  const table = await pw.getOrgRoles();

  // 2. The failure path: the organization itself answers a member's sign-in, never a key.
  const refused = await refusalOf(() => pw.getOrg(), { PayerworksError });

  return {
    roles: table.roles.map((r) => r.role),
    permissions: table.permissions.length,
    owner_rules: table.owner_rules.length,
    refused,
  };
}

// Run as a script: node <this file>, with PAYERWORKS_API_KEY and PAYERWORKS_BASE_URL set.
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  console.log(JSON.stringify(await run(new Payerworks()), null, 2));
}
What it answered, run against the API in Payerworks’ own tests (your request ids will differ)JSON
{
  "roles": [
    "owner",
    "admin",
    "developer",
    "viewer"
  ],
  "permissions": 22,
  "owner_rules": 4,
  "refused": {
    "status": 401,
    "code": "org_session_required",
    "request_id": "req_2"
  }
}

Talk to us

What happens next

  1. 1

    A person at Payerworks reads what you sent, usually within a business day.

  2. 2

    One reply by email names the next step: our trading partner details, where each of your payers stands, or a key for the API.

  3. 3

    Nothing follows unless you answer. There is no sequence behind this form.

Or write to hello@payerworks.com.

Talk to Payerworks

Who you are and what you want to connect. A person replies by email, usually within a business day, and there is no follow-up sequence.

Used to reply to you and for nothing else.