Roxels/ docs
api

Persons API

A person is a participant identity persisted across conversations. The story of identity in Roxels — what it gets you, when to trust it, how to verify it — lives in Identity and resumption. This page covers the REST endpoints for managing person records programmatically.

When you need this API

For most embed integrations, you don't call this API directly — passing external_id to Roxels.start(...) or creating a conversation with a persons array auto-creates the person.

You'll call this API when:

  • You want to pre-register persons with extra context before their first conversation.
  • You want to batch-import participants from an existing system.
  • You're auditing which users have run which conversations.
  • You need to delete a person's history.

List persons

curl https://api.roxels.ai/v1/persons \
  -H "Authorization: Bearer sk-your-key-here"

Response:

{
  "items": [
    {
      "id": "person_xxx",
      "external_id": "user_123",
      "name": "Ada Lovelace",
      "first_seen_at": "2026-05-01T12:00:00Z",
      "last_seen_at": "2026-05-22T10:14:00Z",
      "conversation_count": 4
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Standard cursor pagination — see Pagination and errors.

Query parameters:

Param Description
external_id Filter to one external id. Useful for "does this user already exist?" lookups.
cursor, limit Pagination.

Get a person

curl https://api.roxels.ai/v1/persons/person_xxx \
  -H "Authorization: Bearer sk-your-key-here"

Response: the full person record, including accumulated org_context.

{
  "id": "person_xxx",
  "external_id": "user_123",
  "name": "Ada Lovelace",
  "first_seen_at": "...",
  "last_seen_at": "...",
  "conversation_count": 4,
  "org_context": {
    "plan": "pro",
    "joined_at": "2026-05-01",
    "role": "engineer"
  }
}

Create or upsert a person

Pre-register a participant so the agent has context about them on first contact:

curl -X POST https://api.roxels.ai/v1/persons \
  -H "Authorization: Bearer sk-your-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "user_123",
    "name": "Ada Lovelace",
    "org_context": {
      "plan": "pro",
      "joined_at": "2026-05-01",
      "role": "engineer"
    }
  }'

Body fields:

Field Type Description
external_id string Your stable identifier for this person. Required.
name string Display name. The agent uses this in conversation.
org_context object Arbitrary key/value context. Available to the agent during every conversation with this person, and accessible as {{context.<key>}} in webhook templates.

If a person with that external_id already exists, the call upserts: the name is updated and org_context is shallow-merged. Existing keys you don't include are preserved.

Response: the created or updated person record (same shape as Get).

Patterns

Pre-register on sign-up

The cleanest path: when a new user signs up in your system, mirror them into Roxels with whatever context you have.

# Your sign-up handler, server-side
def on_signup(user):
    requests.post(
        "https://api.roxels.ai/v1/persons",
        headers={"Authorization": f"Bearer {ROXELS_API_KEY}"},
        json={
            "external_id": user.id,
            "name": user.full_name,
            "org_context": {
                "plan": user.plan,
                "signed_up_at": user.signed_up_at.isoformat(),
                "industry": user.industry,
            },
        },
    )

The user's first conversation has rich context. The agent can greet them by name, reference their plan, tune the conversation to their industry.

Refresh context periodically

org_context is a snapshot. If your user's data changes (they upgrade plans, change roles), update the person record:

curl -X POST https://api.roxels.ai/v1/persons \
  -H "Authorization: Bearer sk-your-key-here" \
  -d '{
    "external_id": "user_123",
    "org_context": { "plan": "enterprise" }
  }'

Same external_id → upsert. The plan key updates; other context preserved.

A common rhythm: refresh the person record once a day from your backend, or on significant events (upgrade, role change, account merge).

Batch import

For migrating an existing user base:

for user in your_users:
    requests.post(
        "https://api.roxels.ai/v1/persons",
        headers={...},
        json={...},
    )

There's no bulk endpoint yet — N individual POSTs is the right pattern. Throttle to respect rate limits.

Look up before assuming

If you're unsure whether you've ever sent a particular user to Roxels:

curl "https://api.roxels.ai/v1/persons?external_id=user_123" \
  -H "Authorization: Bearer sk-your-key-here"

Returns either a one-item list (exists) or empty (doesn't).

Deletion (right to be forgotten)

Currently, deletion is done by Roxels support — email support@roxels.ai with the external_id or person.id to delete. A self-service endpoint is on the roadmap.

When a person is deleted:

  • All conversation transcripts and findings tied to them are removed.
  • The external_id is freed; future conversations with the same id create a fresh person.
  • Outputs that already fired (webhooks delivered, callbacks executed) are NOT recalled — they're already in your system.

For ongoing data minimization, delete promptly when a user closes their account.

How external_id flows through the rest of the API

When you pass external_id to:

  • Roxels.start({ externalId: "user_123" }) — Embed creates the session linked to that person.
  • Roxels.init({ externalId: "user_123" }) — Same; propagated to the next start().
  • POST /v1/interviews with persons: [{ external_id }] — Same.

The person is looked up by external_id in your org and the conversation is attached. The full identity story, including the trust model and server-side verification pattern, is in Identity and resumption.