Reference
Organizations
An organization is your customer: the tenant that owns a connection, a directory, a role set and, in your own database, a pile of rows. Almost every other object in this API carries an organization_id, and almost every authorization mistake in a multi-tenant application comes from forgetting to filter on it.
The organization object
Create one organization per customer, and create it early. An organization with no connection is free and carries no behaviour; an organization created three months after the customer, once they finally ask for SSO, means backfilling a tenant id across every row you have already written.
| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier, prefixed org_. Use it as the tenant key in your own schema. |
| object | string | Always "organization". |
| name | string | Display name. Shown in the Admin Portal and in dashboard search; not unique. |
| domains | array | Email domains claimed by this organization. Each entry is an organization_domain with its own id and verification state. |
| allow_profiles_outside_organization | boolean | When false, a sign-in whose email domain is not claimed here is refused. Leave it false unless you knowingly support guest accounts. |
| external_id | string | null | Your own tenant identifier, if you already had one before the migration. |
| metadata | object | Up to 40 string key/value pairs of your own. Never used for routing or authorization. |
| created_at | timestamp | RFC 3339. |
| updated_at | timestamp | RFC 3339. |
The domain object
Domains are how an email address becomes a tenant. Only a verified domain participates in routing, which is deliberate: if claiming a domain were enough, anyone who could create an organization could intercept sign-ins for a company they do not own.
| Field | Type | Description |
|---|---|---|
| id | string | Prefixed org_domain_. |
| object | string | Always "organization_domain". |
| domain | string | The bare domain, without a scheme or a leading @. |
| state | string | pending, verified or failed. Only a verified domain routes a sign-in; a pending one is recorded but ignored. |
| verification_strategy | string | dns or manual. DNS verification asks for a TXT record; manual is set by an operator. |
| verification_token | string | null | The TXT record value to publish, present while the state is pending. |
Free mail domains are refused
Public domains such as the large consumer mail providers cannot be claimed. If a customer genuinely signs in with consumer addresses, route them with a workspace slug or an explicit organization picker instead of by domain.
Endpoints
Paths are relative to https://api.paycux.com. See the reference overview for authentication and environments.
| Method | Path | What it does |
|---|---|---|
| GET | /organizations | List organizations, optionally filtered by claimed email domain. |
| POST | /organizations | Create an organization and claim the email domains it owns. |
| GET | /organizations/:id | Retrieve a single organization with its current domain states. |
| PUT | /organizations/:id | Rename an organization, or replace the set of domains that route to it. |
| DELETE | /organizations/:id | Delete an organization along with its connections, directories and memberships. |
| GET | /organizations/:id/memberships | List the people in an organization, with the role each one holds. |
List organizations
The domains filter is the one that matters at sign-in time: it turns an email address into the tenant it belongs to, which is how you decide whether to show a password field or redirect to an identity provider.
1curl "https://api.paycux.com/organizations?domains[]=foo-corp.example" \2 -H "Authorization: Bearer sk_example_123456789"
1HTTP 2002{3 "object": "list",4 "data": [5 {6 "object": "organization",7 "id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",8 "name": "Foo Corp",9 "allow_profiles_outside_organization": false,10 "domains": [11 {12 "object": "organization_domain",13 "id": "org_domain_01HQ8ZK3M4N5P6R7S8T9V0W1X2",14 "domain": "foo-corp.example",15 "state": "verified"16 }17 ],18 "external_id": null,19 "metadata": {},20 "created_at": "2026-04-11T09:24:02.881Z",21 "updated_at": "2026-04-11T09:24:02.881Z"22 }23 ],24 "list_metadata": { "before": null, "after": null }25}
Create an organization
Create one organization per customer, at the moment the customer is created in your own system rather than when they first ask about SSO. An organization with no connection costs nothing and saves a migration later, because every other record hangs off this id.
1curl -X POST https://api.paycux.com/organizations \2 -H "Authorization: Bearer sk_example_123456789" \3 -H "Content-Type: application/json" \4 -d '{5 "name": "Foo Corp",6 "domain_data": [{ "domain": "foo-corp.example", "state": "verified" }],7 "external_id": "tenant-4812"8 }'
1HTTP 2012{3 "object": "organization",4 "id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",5 "name": "Foo Corp",6 "allow_profiles_outside_organization": false,7 "domains": [8 {9 "object": "organization_domain",10 "id": "org_domain_01HQ8ZK3M4N5P6R7S8T9V0W1X2",11 "domain": "foo-corp.example",12 "state": "verified"13 }14 ],15 "external_id": "tenant-4812",16 "metadata": {},17 "created_at": "2026-04-11T09:24:02.881Z",18 "updated_at": "2026-04-11T09:24:02.881Z"19}
Retrieve an organization
Read this when you need the domain list rather than the name — for example to show an IT admin which domains are still pending verification, and what TXT record is outstanding.
1curl https://api.paycux.com/organizations/org_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \2 -H "Authorization: Bearer sk_example_123456789"
1HTTP 2002{3 "object": "organization",4 "id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",5 "name": "Foo Corp",6 "domains": [7 {8 "object": "organization_domain",9 "id": "org_domain_01HQ8ZK3M4N5P6R7S8T9V0W1X2",10 "domain": "foo-corp.example",11 "state": "verified",12 "verification_strategy": "dns"13 },14 {15 "object": "organization_domain",16 "id": "org_domain_01HQ8ZK3M4N5P6R7S8T9V0W1X3",17 "domain": "foo-corp-eu.example",18 "state": "pending",19 "verification_strategy": "dns",20 "verification_token": "paycux-domain-verification=8f2c41ab"21 }22 ],23 "created_at": "2026-04-11T09:24:02.881Z"24}
Update an organization
domain_data replaces the whole list rather than merging into it, so send every domain the customer should keep. Removing a domain does not sign anybody out, but the next sign-in from that domain no longer resolves to this organization.
1curl -X PUT https://api.paycux.com/organizations/org_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \2 -H "Authorization: Bearer sk_example_123456789" \3 -H "Content-Type: application/json" \4 -d '{5 "name": "Foo Corp International",6 "domain_data": [7 { "domain": "foo-corp.example", "state": "verified" },8 { "domain": "foo-corp-eu.example", "state": "verified" }9 ]10 }'
1HTTP 2002{3 "object": "organization",4 "id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",5 "name": "Foo Corp International",6 "domains": [7 { "domain": "foo-corp.example", "state": "verified" },8 { "domain": "foo-corp-eu.example", "state": "verified" }9 ],10 "updated_at": "2026-07-02T13:18:44.502Z"11}
Delete an organization
This is the widest destructive call in the API. Connections stop accepting assertions, directories stop syncing, and memberships disappear — while the users themselves survive, because they are account-level. Audit log events are retained.
1curl -X DELETE https://api.paycux.com/organizations/org_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \2 -H "Authorization: Bearer sk_example_123456789"
1HTTP 2042(no body)
List memberships
Use this to render a customer's own user list. Filter by role slug when you need to answer the perennial support question of who the admins are before a plan change or an ownership transfer.
1curl "https://api.paycux.com/organizations/org_01HQ8ZK3M4N5P6R7S8T9V0W1X2/memberships?limit=1" \2 -H "Authorization: Bearer sk_example_123456789"
1HTTP 2002{3 "object": "list",4 "data": [5 {6 "object": "organization_membership",7 "id": "om_01HQ8ZK3M4N5P6R7S8T9V0W1X2",8 "user_id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",9 "organization_id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",10 "role": { "slug": "admin" },11 "status": "active",12 "created_at": "2026-04-11T09:23:04.918Z"13 }14 ],15 "list_metadata": { "before": null, "after": "om_01HQ8ZK3M4N5P6R7S8T9V0W1X3" }16}
Errors
Claiming a domain that another organization has already verified returns 422 with the conflicting organization id, rather than moving the domain silently. Deleting an organization that does not exist returns 404. Every error response carries a request id.
Pagination
Both list endpoints on this page are cursor paginated with limit, before and after. An environment with a few thousand organizations is ordinary, so paginate rather than reading the first page and hoping.
1const page = await paycux.organizations.listOrganizations({2 domains: ['foo-corp.example'],3 limit: 100,4});56const organization = page.data[0];