Back to top

API Documentation

Roster

Bulk sync of an external org chart — roles, brands (offices), and users — into Rechat under a single brand. Intended for identity/HR integrations that own the source of truth and push their full roster on a schedule.

Everything hangs off a roster source, one per brand. Create it once, then PUT the roster to it. Records are keyed by the caller’s own external_id, so syncing is idempotent: an external_id seen before updates the existing record, a new one creates it, and re-sending the same payload is a no-op.

PUT treats the payload as the complete roster: a record the source has sent before but omits now is marked deleted. PATCH treats it as a fragment to merge, so absence never removes anything — use it when the caller only knows about the records it is sending. To remove records under PATCH, delete them explicitly.

A sync payload has three optional arrays, each resolved by external_id:

  • roles{ external_id, name, acl }, where acl is an array of Rechat permission strings (e.g. CRM, Deals, Admin).

  • brands{ external_id, name, type, parent }. type is Brokerage or Office; parent references another brand’s external_id to build the tree.

  • users{ external_id, email, first_name, last_name, user_type, memberships }. memberships is an array of { brand, role } pairs referencing brand and role external_ids, placing the user in the tree. Missing brand/role references in a membership are skipped rather than erroring.

Omitting an array leaves that dimension untouched. Related records are returned via associations — request them with ?associations[]=roster_source.roles and ?associations[]=roster_source.users.

Endpoints

Create a roster source

Create a roster source
POST/brands/:brand/roster

Example URI

POST /brands/:brand/roster
URI Parameters
HideShow
brand
string (required) Example: 0a88ff68-e2c2-4dad-83a6-f3f5522329ce
Response  200
HideShow
Body
{
  "code": "OK",
  "data": {
    "type": "roster_source",
    "id": "f213a591-08e2-44ad-87f7-243b34d7b239",
    "created_at": 1789428826.758048,
    "updated_at": 1789428826.758048,
    "deleted_at": null
  }
}

Get a brand's roster source

Get a brand's roster source
GET/brands/:brand/roster

Example URI

GET /brands/:brand/roster
URI Parameters
HideShow
brand
string (required) Example: 0a88ff68-e2c2-4dad-83a6-f3f5522329ce
Response  200
HideShow
Body
{
  "code": "OK",
  "data": {
    "type": "roster_source",
    "id": "f213a591-08e2-44ad-87f7-243b34d7b239",
    "created_at": 1789428826.758048,
    "updated_at": 1789428826.758048,
    "deleted_at": null
  }
}

Sync roster data

Sync roster data
PUT/brands/:brand/roster

Accepts any combination of roles, brands, and users. The example below syncs all three at once; sending a single array performs a partial sync of just that dimension. Records the source previously sent but omits here are marked deleted, including memberships.

Example URI

PUT /brands/:brand/roster
URI Parameters
HideShow
brand
string (required) Example: 0a88ff68-e2c2-4dad-83a6-f3f5522329ce
associations
string (required) Example: roster_source.roles,roster_source.users
Request
HideShow
Body
{
  "roles": [
    {
      "external_id": "agent",
      "name": "Agent",
      "acl": [
        "CRM",
        "Deals"
      ]
    },
    {
      "external_id": "admin",
      "name": "Admin",
      "acl": [
        "Admin",
        "BackOffice"
      ]
    }
  ],
  "brands": [
    {
      "external_id": "region-east",
      "name": "East Region",
      "type": "Brokerage"
    },
    {
      "external_id": "region-west",
      "name": "West Region",
      "type": "Brokerage"
    },
    {
      "external_id": "office-ny",
      "name": "New York Office",
      "type": "Office",
      "parent": "region-east"
    },
    {
      "external_id": "office-la",
      "name": "Los Angeles Office",
      "type": "Office",
      "parent": "region-west"
    }
  ],
  "users": [
    {
      "external_id": "user-001",
      "email": "[email protected]",
      "first_name": "John",
      "last_name": "Doe",
      "user_type": "Agent",
      "memberships": [
        {
          "brand": "office-ny",
          "role": "agent"
        }
      ]
    },
    {
      "external_id": "user-002",
      "email": "[email protected]",
      "first_name": "Jane",
      "last_name": "Smith",
      "user_type": "Agent",
      "memberships": [
        {
          "brand": "office-la",
          "role": "agent"
        }
      ]
    },
    {
      "external_id": "user-003",
      "email": "[email protected]",
      "first_name": "Admin",
      "last_name": "User",
      "user_type": "Agent",
      "memberships": [
        {
          "brand": "region-east",
          "role": "admin"
        },
        {
          "brand": "region-west",
          "role": "admin"
        }
      ]
    }
  ]
}
Response  200
HideShow
Body
{
  "code": "OK",
  "data": {
    "type": "roster_source",
    "id": "f213a591-08e2-44ad-87f7-243b34d7b239",
    "created_at": 1789428826.758048,
    "updated_at": 1789428826.758048,
    "deleted_at": null,
    "roles": [
      {
        "type": "roster_role",
        "id": "7c215ecd-df33-4c47-a45f-d6777351093c",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "agent",
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      },
      {
        "type": "roster_role",
        "id": "32ca6e12-a23c-4a28-a15d-82c70b2ed323",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "admin",
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      }
    ],
    "users": [
      {
        "type": "roster_user",
        "id": "109fce88-1ec6-40f6-8237-2effd1cabae6",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "user-001",
        "object": {
          "email": "[email protected]",
          "last_name": "Doe",
          "user_type": "Agent",
          "first_name": "John",
          "external_id": "user-001"
        },
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      },
      {
        "type": "roster_user",
        "id": "ce263d0e-d182-4665-8845-d03869f680c2",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "user-002",
        "object": {
          "email": "[email protected]",
          "last_name": "Smith",
          "user_type": "Agent",
          "first_name": "Jane",
          "external_id": "user-002"
        },
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      },
      {
        "type": "roster_user",
        "id": "13d8e507-2ced-41c0-b2a1-6c0af3f6cb21",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "user-003",
        "object": {
          "email": "[email protected]",
          "last_name": "User",
          "user_type": "Agent",
          "first_name": "Admin",
          "external_id": "user-003"
        },
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      }
    ]
  }
}

Merge roster data

Merge roster data
PATCH/brands/:brand/roster

Same payload as PUT, but only adds and updates — nothing is removed for being absent. The example sends one user; the users omitted from it stay untouched.

Example URI

PATCH /brands/:brand/roster
URI Parameters
HideShow
brand
string (required) Example: 0a88ff68-e2c2-4dad-83a6-f3f5522329ce
associations
string (required) Example: roster_source.users
Request
HideShow
Body
{
  "users": [
    {
      "external_id": "user-004",
      "email": "[email protected]",
      "first_name": "Merged",
      "last_name": "Newcomer",
      "user_type": "Agent",
      "memberships": [
        {
          "brand": "office-ny",
          "role": "agent"
        }
      ]
    }
  ]
}
Response  200
HideShow
Body
{
  "code": "OK",
  "data": {
    "type": "roster_source",
    "id": "f213a591-08e2-44ad-87f7-243b34d7b239",
    "created_at": 1789428826.758048,
    "updated_at": 1789428826.758048,
    "deleted_at": null,
    "users": [
      {
        "type": "roster_user",
        "id": "109fce88-1ec6-40f6-8237-2effd1cabae6",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "user-001",
        "object": {
          "email": "[email protected]",
          "last_name": "Doe Updated",
          "user_type": "Agent",
          "first_name": "John",
          "external_id": "user-001"
        },
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      },
      {
        "type": "roster_user",
        "id": "a766151f-e8e8-4a44-8b19-4d717a3532ba",
        "source": "f213a591-08e2-44ad-87f7-243b34d7b239",
        "external_id": "user-004",
        "object": {
          "email": "[email protected]",
          "last_name": "Newcomer",
          "user_type": "Agent",
          "first_name": "Merged",
          "external_id": "user-004"
        },
        "created_at": 1789428826.758048,
        "updated_at": 1789428826.758048,
        "deleted_at": null
      }
    ]
  }
}

Generated by aglio on 14 Sep 2026