Personas

Personas represent browser identities with their own credentials keychain and email inbox. Attach a persona to an agent or journey so the agent knows which credentials to use for authentication.

Overview

Personas are distinct from roles. Where a role controls what an agent says (prompt injection), a persona represents a browser identity with its own credentials and email inbox. Attach a persona to an agent or journey so the agent knows which credentials to use when it needs to log in.

Credentials

Each persona has a credentials keychain. Credentials are stored encrypted and retrieved by the agent at runtime. Two types are supported: username_password (email and password pair) and secret (a single value like an API key or token). A persona can hold multiple credentials, for example an application login plus an API token, or credentials for different environments. The agent picks the right one by label.

Email inbox

Each persona gets a dedicated email address derived deterministically from its name and tenant. Inbound emails are stored and can be read by the agent during execution. This is useful for testing email verification flows, OTP codes, password resets, and any other flow that requires receiving an email.

POST /api/v1/personas

Create a new persona

Parameters

ParameterTypeInRequiredDescription
namestringbodyYesPersona name (unique per tenant, max 40 characters)

Status Codes

CodeDescription
201Persona created
400Validation error
401Unauthorized
409Duplicate persona name

Response Body

{
  "id": "aa0e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Sarah",
  "is_default": false,
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
POST /api/v1/personas
cURL
Response
GET /api/v1/personas

List personas

Parameters

ParameterTypeInRequiredDescription
limitintegerqueryNoNumber of results to return (default: 20)
cursoruuidqueryNoCursor for pagination

Status Codes

CodeDescription
200OK
401Unauthorized

Response Body

{
  "personas": [
    {
      "id": "aa0e8400-e29b-41d4-a716-446655440000",
      "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Sarah",
      "is_default": false,
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-15T10:30:00Z"
    }
  ],
  "next_cursor": "bb0e8400-e29b-41d4-a716-446655440000"
}
GET /api/v1/personas
cURL
Response
GET /api/v1/personas/{id}

Get persona by ID

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID

Status Codes

CodeDescription
200OK
400Invalid UUID
401Unauthorized
404Persona not found

Response Body

{
  "id": "aa0e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Sarah",
  "is_default": false,
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
GET /api/v1/personas/{id}
cURL
Response
DELETE /api/v1/personas/{id}

Delete a persona

Deletes a non-default persona. Returns 409 Conflict if the persona is the tenant default — change the default first.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID

Status Codes

CodeDescription
204Persona deleted
400Invalid UUID
401Unauthorized
404Persona not found
409Cannot delete default persona
DELETE /api/v1/personas/{id}
cURL
Response
PUT /api/v1/personas/{id}/default

Set a persona as the tenant default

Atomically changes the default persona for the tenant. The previous default is unset. Returns the updated persona.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID

Status Codes

CodeDescription
200Default updated
400Invalid UUID
401Unauthorized
404Persona not found

Response Body

{
  "id": "aa0e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Sarah",
  "is_default": true,
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:35:00Z"
}
PUT /api/v1/personas/{id}/default
cURL
Response
GET /api/v1/personas/{id}/credentials

List persona credentials

Returns all credentials associated with this persona. Sensitive values (passwords, secrets) are never included in the response.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID

Status Codes

CodeDescription
200OK
400Invalid UUID
401Unauthorized
404Persona not found

Response Body

{
  "credentials": [
    {
      "id": "cc0e8400-e29b-41d4-a716-446655440000",
      "persona_id": "aa0e8400-e29b-41d4-a716-446655440000",
      "label": "Staging login",
      "cred_type": "username_password",
      "email": "user@example.com",
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-15T10:30:00Z"
    }
  ]
}
GET /api/v1/personas/{id}/credentials
cURL
Response
POST /api/v1/personas/{id}/credentials

Add a credential to a persona

Creates a new encrypted credential on the persona. The test run can retrieve these at runtime via the get_credentials tool. For username_password and magic_link types, the email is auto-derived from the persona name — emails sent to this address are readable via the test run's emails_read tool (used for magic links, verification codes, and OTPs). For external type, the email is customer-provided and the test run CANNOT read emails sent to it.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID
labelstringbodyYesHuman-readable label for this credential
cred_typestringbodyYesCredential type: username_password (auto-derived email + password), magic_link (auto-derived email, no password — test run reads login link from its inbox via emails_read), secret (API key or token), or external (customer-provided email + password — note: the test run CANNOT read emails sent to external addresses; emails_read only works with the auto-derived email)
emailstringbodyNoLogin email — auto-derived for username_password/magic_link; required and user-supplied for external
passwordstringbodyNoLogin password (required for username_password and external, stored encrypted)
valuestringbodyNoSecret value (required for secret type, stored encrypted)
auth_notesstringbodyNoOptional notes about how to authenticate (shown to the test run)

Status Codes

CodeDescription
201Credential created
400Validation error
401Unauthorized
404Persona not found

Response Body

{
  "id": "cc0e8400-e29b-41d4-a716-446655440000",
  "persona_id": "aa0e8400-e29b-41d4-a716-446655440000",
  "label": "Staging login",
  "cred_type": "username_password",
  "email": "user@example.com",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
POST /api/v1/personas/{id}/credentials
cURL
Response
DELETE /api/v1/personas/{id}/credentials/{credentialId}

Delete a credential

Removes a credential from the persona.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesPersona ID
credentialIduuidpathYesCredential ID

Status Codes

CodeDescription
204Credential deleted
400Invalid UUID
401Unauthorized
404Persona or credential not found
DELETE /api/v1/personas/{id}/credentials/{credentialId}
cURL
Response