Skip to main content

Organizations

Manage tenant organizations via the Provisioning API.

The Provisioning API is used by Super Terra (the parent platform) to create and manage Courimax tenants. All provisioning endpoints require the X-Provisioning-Secret header.

List Organizations

GET /provisioning/organizations

Headers

HeaderRequiredDescription
X-Provisioning-SecretYesProvisioning secret

Example

curl -X GET "https://api.courimax.com/api/provisioning/organizations" \
-H "X-Provisioning-Secret: your_provisioning_secret"

Response (200 OK)

[
{
"id": "org-uuid",
"slug": "acme-corp",
"name": "Acme Corporation",
"isActive": true,
"createdAt": "2026-08-19T10:00:00.000Z",
"counts": {
"members": 5,
"drivers": 12,
"orders": 342
},
"admins": [
{
"id": "user-uuid",
"email": "admin@acme.com",
"name": "John Doe",
"orgRole": "admin",
"invitePending": false
}
]
}
]

Create Organization

POST /provisioning/organizations

Headers

HeaderRequiredDescription
X-Provisioning-SecretYesProvisioning secret
Content-TypeYesapplication/json

Body Parameters

ParameterTypeRequiredDescription
namestringYesOrganization name
slugstringNoURL-safe slug (auto-generated if not provided)
admin.emailstringYesFirst admin's email
admin.namestringNoFirst admin's name

Example

curl -X POST "https://api.courimax.com/api/provisioning/organizations" \
-H "X-Provisioning-Secret: your_provisioning_secret" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corporation",
"slug": "acme-corp",
"admin": {
"email": "admin@acme.com",
"name": "John Doe"
}
}'

Response (201 Created)

{
"organization": {
"id": "org-uuid",
"slug": "acme-corp",
"name": "Acme Corporation",
"isActive": true,
"createdAt": "2026-08-19T10:00:00.000Z"
},
"admin": {
"id": "user-uuid",
"email": "admin@acme.com",
"name": "John Doe",
"isNewUser": true
},
"invite": {
"expiresAt": "2026-08-26T10:00:00.000Z",
"emailSent": true
}
}

Response Fields

FieldTypeDescription
organizationobjectCreated organization
adminobjectAdmin user details
admin.isNewUserbooleanWhether admin is a new user
inviteobjectInvite details (null if user already exists)
invite.expiresAtstringInvite expiration (7 days)
invite.emailSentbooleanWhether invite email was sent

Error Responses

400 Bad Request - Validation error

{
"statusCode": 400,
"message": "Organization name is required",
"error": "Bad Request"
}

409 Conflict - Slug already taken

{
"statusCode": 400,
"message": "Slug \"acme-corp\" is already taken",
"error": "Bad Request"
}

Add Admin

POST /provisioning/organizations/:id/admins

Path Parameters

ParameterTypeRequiredDescription
idstringYesOrganization ID

Headers

HeaderRequiredDescription
X-Provisioning-SecretYesProvisioning secret
Content-TypeYesapplication/json

Body Parameters

ParameterTypeRequiredDescription
emailstringYesAdmin email
namestringNoAdmin name

Example

curl -X POST "https://api.courimax.com/api/provisioning/organizations/org-uuid/admins" \
-H "X-Provisioning-Secret: your_provisioning_secret" \
-H "Content-Type: application/json" \
-d '{
"email": "newadmin@acme.com",
"name": "Jane Smith"
}'

Response (201 Created)

{
"admin": {
"id": "user-uuid",
"email": "newadmin@acme.com",
"name": "Jane Smith",
"isNewUser": true,
"alreadyMember": false
},
"invite": {
"expiresAt": "2026-08-26T10:00:00.000Z",
"emailSent": true
}
}

Resend Invite

POST /provisioning/admins/:userId/resend-invite

Path Parameters

ParameterTypeRequiredDescription
userIdstringYesUser ID

Headers

HeaderRequiredDescription
X-Provisioning-SecretYesProvisioning secret

Example

curl -X POST "https://api.courimax.com/api/provisioning/admins/user-uuid/resend-invite" \
-H "X-Provisioning-Secret: your_provisioning_secret"

Response (200 OK)

{
"admin": {
"id": "user-uuid",
"email": "admin@acme.com",
"name": "John Doe"
},
"invite": {
"expiresAt": "2026-08-26T10:00:00.000Z",
"emailSent": true
}
}

Reset Password

POST /provisioning/admins/:userId/reset-password

Path Parameters

ParameterTypeRequiredDescription
userIdstringYesUser ID

Headers

HeaderRequiredDescription
X-Provisioning-SecretYesProvisioning secret
Content-TypeYesapplication/json

Body Parameters

ParameterTypeRequiredDescription
passwordstringNoNew password (auto-generated if not provided)

Example

curl -X POST "https://api.courimax.com/api/provisioning/admins/user-uuid/reset-password" \
-H "X-Provisioning-Secret: your_provisioning_secret" \
-H "Content-Type: application/json" \
-d '{
"password": "NewSecurePassword123!"
}'

Response (200 OK)

{
"ok": true,
"email": "admin@acme.com"
}

If no password is provided, a secure temporary password is generated and returned.

Invite Acceptance

Get Invite

GET /provisioning/invite/:token

This endpoint is public (no authentication required) and is used to display invite details before acceptance.

curl -X GET "https://api.courimax.com/api/provisioning/invite/invite-token"

Accept Invite

POST /provisioning/invite/:token/accept
curl -X POST "https://api.courimax.com/api/provisioning/invite/invite-token/accept" \
-H "Content-Type: application/json" \
-d '{
"password": "SecurePassword123!"
}'

Response (200 OK)

{
"ok": true,
"email": "admin@acme.com"
}

Rate Limiting

Provisioning endpoints have rate limits:

  • GET /organizations: 120 requests per hour
  • POST /organizations: 30 requests per hour
  • POST /organizations/:id/admins: 60 requests per hour
  • POST /admins/:userId/resend-invite: 30 requests per hour
  • POST /admins/:userId/reset-password: 30 requests per hour

Next Steps