Skip to content

Link a user to an organization

POST
/organizations/{oid}/user/{uid}/link
curl --request POST \
--url https://apisandbox.puurk.com/organizations/example/user/example/link \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "status": "active", "start_date": "2026-04-15T12:00:00Z", "termination_date": "2026-04-15T12:00:00Z", "commission_basis": "profit", "commission_fixed": 1, "commission_rate": 1, "commission_trigger": "sale", "role": "owner", "oldUid": "example" }'

Link an existing user to an organization, optionally migrating them from a previous uid. This writes the organization’s roles map, so it is a role modification. Setting a role requires one of: an organization role of owner or agencyadmin in this organization; a superadmin claim; or a service token holding the admin scope action on organizations (globally or for this organization). admin is a scope action, not an organization role, and is rejected as a role value with 400.

oid
required
string

Organization ID

uid
required
string

User ID

Request body

Media typeapplication/json

Body for POST /organizations/{oid}/user/{uid}/link. Every field is optional.

object
status

Membership status.

string
nullable
Allowed values: active terminated
start_date

When the person started with this organization. ISO 8601, or null to clear.

string format: date-time
nullable
termination_date

When the person left. ISO 8601, or null to clear.

string format: date-time
nullable
commission_basis
string
nullable
Allowed values: profit retail
commission_fixed

Fixed commission amount in cents

integer
nullable
commission_rate

Commission rate

number
nullable
commission_trigger
string
nullable
Allowed values: sale service
role

The role to grant. Defaults to read. Setting a role requires one of: an organization role of owner or agencyadmin in this organization; a superadmin claim; or a service token holding the admin scope action on organizations (globally or for this organization). admin is a scope action, not an organization role, and is rejected as a role value with 400.

string
Allowed values: owner manager read write provider accountant officeadmin agencyadmin agencyuser none
oldUid

A previous uid for this person. When supplied, its entry is removed from the organization’s roles map in the same write. Note the camelCase name: unlike the other fields, the service reads oldUid, and an old_uid is silently ignored.

string

User linked. The body is the organization, not the user — its roles map reflects the change.

Media typeapplication/json
object
id

Unique identifier for the organization

string
eid

External identifier for the organization

string
name

Name of the organization

string
ein

Employer Identification Number

string
logo_path

Path to the organization’s logo

string
type

Type of organization. Validated on create and update; any other value is rejected with 400 Invalid type. Must be one of: client, test.

string
Allowed values: client test
roles

User roles in the organization

object
key
additional properties

Role of a user in an organization, as stored in the organization’s roles map. admin is not a role: it is a service-token scope action, and a request that sends it as a role gets 400. Of the organization roles, only owner and agencyadmin may change other members’ roles.

string
Allowed values: owner manager read write provider accountant officeadmin agencyadmin agencyuser none
settings

Organization settings

object
key
additional properties
boolean
features

Puurk features enabled for the organization

object
key
additional properties
boolean
Example
{
"type": "client",
"roles": {
"additionalProperty": "owner"
}
}

bad_request — invalid start_date or termination_date, or role is not an OrganizationRole (Invalid role. Must be one of: owner, manager, read, write, provider, accountant, officeadmin, agencyadmin, agencyuser, none). admin is rejected here: it is a scope action, not a role.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}

Unauthorized

forbidden — the caller is the target user, or the caller holds none of: an organization role of owner or agencyadmin, a superadmin claim, or a service token with the admin scope action on organizations.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}

not_found — the organization does not exist.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}

conflict — this would remove the organization’s last owner.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}