User Management APIs

This guide covers the APIs for creating, retrieving, updating, and linking consent users in Redacto CMP.

Overview

Consent users represent data principals (individuals whose data you process) in your system. The User Management APIs allow you to:

  • Create users with explicit identifiers
  • Retrieve user information
  • Update user details
  • Link multiple user records to a single identity

Base URL

All user management endpoints use the following base path:

/consent/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/consent-ledger/consent-users/

Authentication: All endpoints require either JWT Auth or CMS API Key authentication.

Create User

Create a new consent user with an explicit identifier.

Endpoint:

POST /consent-ledger/consent-users/

Request Body:

{
  "org_user_id": "user123",
  "primary_email": "[email protected]",
  "primary_mobile": "+1234567890",
  "name": "John Doe",
  "metadata": {
    "account_type": "premium",
    "signup_source": "web"
  }
}
FieldTypeRequiredDescription
org_user_idstringYesYour unique identifier for the user
primary_emailstringNoUser's email address
primary_mobilestringNoUser's phone number
namestringNoUser's full name
metadataobjectNoCustom key-value pairs

Response (201 Created):

{
  "detail": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "organisation_uuid": "org-uuid-here",
    "workspace_uuid": "ws-uuid-here",
    "org_user_id": "user123",
    "org_user_id_type": "UCID",
    "primary_email": "[email protected]",
    "primary_mobile": "+1234567890",
    "name": "John Doe",
    "metadata": {
      "account_type": "premium",
      "signup_source": "web"
    },
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z"
  }
}

Response (409 Conflict):

If a user with the same identifier already exists:

{
  "detail": {
    "conflict_type": "ORG_USER_ID_EXISTS",
    "message": "User with org_user_id 'user123' already exists",
    "existing_user": {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "org_user_id": "user123",
      // ... full user object
    }
  }
}

Conflict Types:

TypeDescription
ORG_USER_ID_EXISTSA user with this org_user_id already exists
EMAIL_EXISTS_SAME_USEREmail exists with same org_user_id type (likely same person)
EMAIL_EXISTS_DIFFERENT_USEREmail exists with different org_user_id type
PHONE_EXISTS_SAME_USERPhone exists with same org_user_id type
PHONE_EXISTS_DIFFERENT_USERPhone exists with different org_user_id type

Get User

Retrieve a user by their UUID or org_user_id.

By UUID

Endpoint:

GET /consent-ledger/consent-users/{user_uuid}

Response (200 OK):

{
  "detail": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "organisation_uuid": "org-uuid-here",
    "workspace_uuid": "ws-uuid-here",
    "org_user_id": "user123",
    "org_user_id_type": "UCID",
    "primary_email": "[email protected]",
    "primary_mobile": "+1234567890",
    "name": "John Doe",
    "metadata": { "account_type": "premium" },
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z"
  }
}

Response (404 Not Found):

{
  "message": "User not found"
}

By org_user_id

Endpoint:

GET /consent-ledger/consent-users/by-org-user-id/{org_user_id}

Response: Same as Get by UUID.

Note: This endpoint only works with the current org_user_id. Old org_user_ids (from before an update) are preserved as aliases but cannot be directly queried.

Update User

Update an existing user's information.

Endpoint:

PATCH /consent-ledger/consent-users/{user_uuid}

Request Body:

Only include fields you want to update:

{
  "primary_email": "[email protected]",
  "name": "John Updated",
  "metadata": {
    "account_type": "enterprise"
  }
}
FieldTypeDescription
org_user_idstringUpdate the user's identifier
primary_emailstringUpdate email address
primary_mobilestringUpdate phone number
namestringUpdate display name
metadataobjectMerged with existing metadata

Response (200 OK):

Returns the updated user object.

Response (409 Conflict):

{
  "message": "org_user_id 'xyz' already exists"
}

Key Behaviors:

  • Only provided fields are updated (partial update)
  • Metadata is merged, not replaced
  • Old identifiers are preserved as aliases

Link Users

Link multiple consent users to a primary user for identity resolution. This is useful when the same person has multiple records from different channels or systems.

Endpoint:

POST /consent-ledger/consent-users/link-users

Request Body:

{
  "primary_org_user_id": "user_primary_123",
  "alias_org_user_ids": ["user_alias_1", "user_alias_2", "anon_session_abc"]
}
FieldTypeRequiredDescription
primary_org_user_idstringYesThe org_user_id of the primary user
alias_org_user_idsarrayYesList of org_user_ids to link as aliases

Response (200 OK):

{
  "detail": {
    "primary_user_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "linked": ["user_alias_1", "anon_session_abc"],
    "already_linked": [],
    "not_found": [],
    "conflicts": [
      {
        "org_user_id": "user_alias_2",
        "existing_primary_org_user_id": "user_other_primary"
      }
    ]
  }
}

Response Categories:

FieldDescription
linkedSuccessfully linked org_user_ids
already_linkedAlready aliased to this primary user
not_foundorg_user_ids that don't exist as users
conflictsAlready aliased to a different primary user

Response (404 Not Found):

{
  "message": "Primary user with org_user_id 'xyz' not found"
}

Response (422 Unprocessable Entity):

{
  "message": "Cannot use 'xyz' as primary user - it is already an alias of 'abc'"
}

Key Behaviors:

  • The primary user cannot itself be an alias
  • All aliases from alias users are transferred to the primary
  • The operation is idempotent (safe to call multiple times)
  • Linking is transactional per user

User Lifecycle

org_user_id Types

When users are created, they're assigned an org_user_id_type that indicates how they were identified:

TypeDescription
UCIDUser Created ID - explicitly provided org_user_id
EMAILDerived from email when org_user_id not provided
PHONEDerived from phone when org_user_id not provided

When you create a user with an explicit org_user_id, the type is set to UCID.

Alias Management

The system automatically manages aliases for identity resolution:

Automatic Alias Creation:

  • org_user_id is always added as an alias
  • Email addresses are added as aliases (if provided)
  • Phone numbers are added as aliases (if provided)

Alias Preservation:

  • When org_user_id is updated, the old value is preserved as an alias
  • When email/phone is updated, old values are preserved as aliases
  • All historical identifiers can be used for internal lookups

Common Use Cases

1. Create User During Registration

// After user completes registration
const response = await fetch(
  `${API_URL}/consent-ledger/consent-users/`,
  {
    method: "POST",
    headers: {
      "X-CMS-API-Key": CMS_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      org_user_id: newUser.id,
      primary_email: newUser.email,
      name: newUser.name,
      metadata: { signup_date: new Date().toISOString() },
    }),
  }
);

2. Link Anonymous Session to Registered User

// After user registers/logs in
const response = await fetch(
  `${API_URL}/consent-ledger/consent-users/link-users`,
  {
    method: "POST",
    headers: {
      "X-CMS-API-Key": CMS_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      primary_org_user_id: user.id,
      alias_org_user_ids: [sessionAnonymousId],
    }),
  }
);

3. Merge Multi-Channel Users

// User consented via web (email) and mobile app (phone)
const response = await fetch(
  `${API_URL}/consent-ledger/consent-users/link-users`,
  {
    method: "POST",
    headers: {
      "X-CMS-API-Key": CMS_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      primary_org_user_id: "customer_123",
      alias_org_user_ids: [
        "[email protected]",
        "phone_+1234567890"
      ],
    }),
  }
);

Error Handling

StatusDescription
200Success
201User created
400Bad request (malformed data)
401Authentication required
404User not found
409Conflict (duplicate user)
422Validation error
500Internal server error


What’s Next