Add a user to an organization

POST /v1/organizations/{org_id}/memberships · permission organizations:write

Adds an existing user to the organization directly (source admin_api, status active). Without role_ids the organization's default member role is assigned; each role must be an environment role or a role of this organization. The response carries an ETag; the write is audited as organization_membership.created. Idempotency-Key is optional.

Request

Field Type Required Description
org_id path yes Organization ID (org_…).
user_id string yes User ID (usr_…).
role_ids string[] no Role IDs (rol_…), at most 50.
expires_at string no RFC 3339 time in the future when the membership ends.

Response

201 Created with the membership.

{
  "id": "mem_01j9xn5p9s0t4v6w8x0y2z4a6c",
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "user_id": "usr_01j9xh2k6p7q1r3s5t7v9w1x3y",
  "status": "active",
  "source": "admin_api",
  "reason": null,
  "roles": [
    {
      "role_id": "rol_01j9xr7s1t2w6x8y0z2a4b6c8e",
      "source": "admin_api",
      "assigned_at": "2026-10-12T09:31:00.123456Z"
    }
  ],
  "expires_at": null,
  "created_at": "2026-10-12T09:31:00.123456Z",
  "activated_at": "2026-10-12T09:31:00.123456Z",
  "suspended_at": null,
  "removed_at": null,
  "updated_at": "2026-10-12T09:31:00.123456Z",
  "version": 1
}

Errors

HTTP code When
404 not_found The organization or user does not exist in this environment.
403 role_not_assignable A role is not an environment role or a role of this organization.
403 user_not_active The user is not active.
409 membership_already_exists The user is already a member of the organization.
409 organization_disabled The organization is disabled.
409 organization_membership_limit_reached The organization's membership limit is reached.
409 membership_limit_reached The user's membership limit is reached.
422 anonymous_user_not_allowed The user is anonymous.
422 validation_failed A field is missing or invalid.
401 unauthenticated The credential is missing, invalid or revoked.
403 insufficient_permissions The credential lacks the required permission. Assigning a privileged (is_privileged) role also requires roles:write; without it nothing is written and required_permissions lists both permissions.
429 rate_limited The rate limit was exceeded; retry after the Retry-After period.
503 service_unavailable A dependency is temporarily unavailable; retry after the Retry-After period.

Example

curl -i -X POST "https://api.eu.keenauth.com/v1/organizations/org_01j9xk3m7q8r2s4t6v8w0y2z4a/memberships" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"usr_01j9xh2k6p7q1r3s5t7v9w1x3y","role_ids":["rol_01j9xr7s1t2w6x8y0z2a4b6c8e"]}'

Personal data

This endpoint carries personal data: organization memberships and invitations. Personal data in the KeenAuth APIs describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.