Upsert Role

Create or update a role based on customer role ID. This is an idempotent operation that creates a new role if it doesn't exist, or updates the existing role if it does.

Endpoint

POST /v1/workspaces/{workspaceId}/role/upsert

Authentication

Requires Bearer token authentication. See Authentication for details on obtaining an access token.

Authorization: Bearer YOUR_ACCESS_TOKEN

Path Parameters

ParameterTypeRequiredDescription
workspaceIdstring (UUID)YesThe ID of your workspace

Request Body

FieldTypeRequiredDescription
customerRoleIdstringYesYour custom role identifier (used to determine if role exists)
namestringNoDisplay name for the role
descriptionstringNoDescription of the role's purpose

Response

Success Response

Status Code: 200 OK (update) or 201 Created (create)

Headers:

X-API-Version: v1

Body:

{
  "workflowId": "550e8400-e29b-41d4-a716-446655440000",
  "role": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "name": "Sales Manager",
    "description": "Access to sales-related content",
    "customerRoleId": "sales-manager",
    "createdAt": "2025-11-11T10:00:00Z",
    "updatedAt": "2025-11-11T15:30:00Z"
  },
  "created": false
}
FieldTypeDescription
workflowIdstring (UUID)Workflow ID for tracking the async operation
roleobjectThe created or updated role object
createdbooleantrue if role was created, false if updated

Examples

Create New Role via Upsert

When no role with the customer role ID exists:

curl -X POST \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/role/upsert' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'organizationid: your-organization-id' \
  -H 'Content-Type: application/json' \
  -d '{
    "customerRoleId": "sales-manager",
    "name": "Sales Manager",
    "description": "Access to sales content"
  }'

Response:

{
  "workflowId": "789e0123-f45a-67b8-c901-234567890def",
  "role": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "name": "Sales Manager",
    "description": "Access to sales content",
    "customerRoleId": "sales-manager",
    "createdAt": "2025-11-11T14:30:00Z",
    "updatedAt": "2025-11-11T14:30:00Z"
  },
  "created": true
}

Update Existing Role via Upsert

When a role with the customer role ID already exists:

curl -X POST \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/role/upsert' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'organizationid: your-organization-id' \
  -H 'Content-Type: application/json' \
  -d '{
    "customerRoleId": "sales-manager",
    "name": "Senior Sales Manager",
    "description": "Enhanced sales content access"
  }'

Response:

{
  "workflowId": "456e7890-a12b-34c5-d678-901234567890",
  "role": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "name": "Senior Sales Manager",
    "description": "Enhanced sales content access",
    "customerRoleId": "sales-manager",
    "createdAt": "2025-11-11T14:30:00Z",
    "updatedAt": "2025-11-11T16:45:00Z"
  },
  "created": false
}

Idempotent Role Provisioning

Run the same upsert multiple times safely:

# First call - creates role
curl -X POST \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/role/upsert' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'organizationid: your-organization-id' \
  -H 'Content-Type: application/json' \
  -d '{
    "customerRoleId": "admin",
    "name": "Administrator",
    "description": "Full access"
  }'
 
# Second call - updates existing role (no error)
curl -X POST \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/role/upsert' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'organizationid: your-organization-id' \
  -H 'Content-Type: application/json' \
  -d '{
    "customerRoleId": "admin",
    "name": "Administrator",
    "description": "Full access"
  }'

Error Responses

400 Bad Request

Missing required field:

{
  "error": "Bad Request",
  "message": "Missing required field: customerRoleId"
}

401 Unauthorized

{
  "error": "Unauthorized",
  "message": "Invalid or missing API key"
}

500 Internal Server Error

{
  "error": "Internal Server Error",
  "message": "Failed to upsert role"
}

Notes

Idempotency

This endpoint is idempotent - you can call it multiple times with the same customerRoleId safely:

  • First call: Creates the role
  • Subsequent calls: Update the role with new values
  • No 409 Conflict errors

Customer Role ID Required

Unlike the create endpoint, customerRoleId is required for upsert. This is because it's used to determine whether to create or update.

Determination Logic

The endpoint determines whether to create or update based on:

  1. Search for existing role with matching customerRoleId
  2. If found: Update that role
  3. If not found: Create new role

Asynchronous Processing

Like create and update operations, upsert is asynchronous. Track progress using the returned workflowId.

Best Practices

Use for Synchronization

Perfect for keeping roles synchronized with external systems:

async function syncRole(workspaceId, externalRole) {
  await fetch(
    `https://api.sharely.ai/v1/workspaces/${workspaceId}/role/upsert`,
    {
      method: 'POST',
      headers: {
        'x-api-key': 'sk-sharely-your-api-key',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        customerRoleId: externalRole.id,
        name: externalRole.name,
        description: externalRole.description
      })
    }
  );
}

Infrastructure as Code

Use in deployment scripts for consistent role provisioning:

#!/bin/bash
# Ensure roles exist with specific configuration
 
roles=(
  "admin:Administrator:Full system access"
  "editor:Content Editor:Can edit content"
  "viewer:Viewer:Read-only access"
)
 
for role in "${roles[@]}"; do
  IFS=: read -r id name desc <<< "$role"
 
  curl -X POST \
    "https://api.sharely.ai/v1/workspaces/${WORKSPACE_ID}/role/upsert" \
    -H "x-api-key: ${API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"customerRoleId\": \"$id\",
      \"name\": \"$name\",
      \"description\": \"$desc\"
    }"
done

Automated Provisioning

Ideal for automated user provisioning workflows where you need to ensure roles exist.

Related Endpoints

Use Cases

CI/CD Pipeline

Ensure roles exist in each environment:

# .github/workflows/deploy.yml
- name: Provision Roles
  run: |
    curl -X POST \
      "https://api.sharely.ai/v1/workspaces/${{ secrets.WORKSPACE_ID }}/role/upsert" \
      -H "x-api-key: ${{ secrets.API_KEY }}" \
      -H 'Content-Type: application/json' \
      -d '{"customerRoleId": "admin", "name": "Admin", "description": "Full access"}'

Configuration Management

Maintain role configurations in code:

const roleConfigs = [
  { customerRoleId: 'admin', name: 'Administrator', description: 'Full access' },
  { customerRoleId: 'editor', name: 'Editor', description: 'Edit content' },
  { customerRoleId: 'viewer', name: 'Viewer', description: 'View only' }
];
 
async function ensureRoles(workspaceId) {
  for (const config of roleConfigs) {
    await fetch(
      `https://api.sharely.ai/v1/workspaces/${workspaceId}/role/upsert`,
      {
        method: 'POST',
        headers: {
          'x-api-key': 'sk-sharely-your-api-key',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(config)
      }
    );
  }
}