External users

External users are the "C" in B2B2C — your end-users, who never sign in to Juglans directly. They exist to Juglans as shadow rows keyed by (project_id, external_id), where external_id is whatever X-USER-ID value you sent.

How they appear

You don't pre-provision external users. The first time a jg_p_* call carries an X-USER-ID header, the server upserts a row in project_external_users and returns. Subsequent calls with the same header value reuse the row and bump last_seen_at.

The shadow row is what the system uses to partition conversations and the agent runtime's per-thread chat_id. The mapping is one-way: external_id (your value) → external user UUID (ours). We never share that UUID across projects. (Audit-log partitioning by external user is on the roadmap — see Authentication.)

Use cases

  • Support tooling — your support agent looks at "who has hit the platform recently" and can drill into a specific user's conversations via the project owner JWT.
  • GDPR delete — when one of your users invokes their right to erasure, delete the external user to make their conversation history unreachable.

Not for abuse blocking. Deleting an external user does not prevent that X-USER-ID value from reaching the platform again — the next request bearing the same header simply auto-creates a fresh shadow row with a new UUID, orphaning the prior conversations. If you need to block a user, enforce it in your own backend before forwarding the call to Juglans.


Endpoints

GET /api/projects/{id}/external-users

List the project's known end-users, most-recently-seen first. Capped at 100 rows in v1.

Auth: Either (ProjectAccess). Caller must be the project owner.

GET /api/projects/3a7b5c1d-.../external-users
Authorization: Bearer eyJhbGc...
{
  "external_users": [
    {
      "id":            "e0f1a2b3-c4d5-6789-abcd-ef0123456789",
      "external_id":   "customer_47291",
      "display_name":  null,
      "first_seen_at": "2026-04-12T08:30:00Z",
      "last_seen_at":  "2026-04-29T09:45:00Z"
    },
    {
      "id":            "f1a2b3c4-...",
      "external_id":   "customer_88102",
      "display_name":  null,
      "first_seen_at": "2026-04-25T14:00:00Z",
      "last_seen_at":  "2026-04-28T22:11:00Z"
    }
  ]
}

cURL:

curl https://api.juglans.ai/api/projects/3a7b5c1d-.../external-users \
  -H "Authorization: Bearer jg_p_a1b2c3d4..."

DELETE /api/projects/{id}/external-users/{user_id}

Force-offboard an end-user. The shadow row is deleted; any future request bearing the same X-USER-ID will create a fresh shadow row with a new UUID — so previously stored conversations (which referenced the old UUID) are orphaned and no longer reachable through the API.

204 No Content.

Auth: Either (ProjectAccess). Caller must be the project owner.

curl -X DELETE https://api.juglans.ai/api/projects/3a7b5c1d-.../external-users/e0f1a2b3-... \
  -H "Authorization: Bearer eyJhbGc..."

Note: a hard cascade of stored agent-runtime history records (the on-disk per-thread state keyed by the old chat_id) is on the roadmap. v1 makes the data unreachable through the API; reach out if you need a literal disk wipe for compliance.