Skip to main content

Session Tickets Guide

Session tickets provide a secure way to grant temporary access for impersonation, AI agent access, webhook app access, and API auth app access.

Prerequisites

Before using any API methods, you must initialize the SDK:
use wacht::WachtClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the client with an API key
    let client = WachtClient::new("wk_live_...");

    // Now you can use the API
    Ok(())
}

Ticket Types

The SDK supports four ticket types:
TypeUse Case
ImpersonationAllow admins to impersonate other users
AgentAccessGrant access to specific AI agents
WebhookAppAccessGrant access to a webhook app
ApiAuthAccessGrant access to an API auth app

Creating Tickets

Impersonation Ticket

Allow an admin to impersonate another user:
use wacht::WachtClient;
use wacht::models::{CreateSessionTicketRequest, TicketType};

let client = WachtClient::new("wk_live_...");

let response = client.session().create(
    CreateSessionTicketRequest::impersonation("user_123")
)
.send()
.await?;

println!("Ticket: {}", response.ticket);
println!("Expires at: {}", response.expires_at);

Agent Access Ticket

Grant access to specific AI agents with a concrete actor ID:
use wacht::WachtClient;
use wacht::models::{CreateSessionTicketRequest, TicketType};

let client = WachtClient::new("wk_live_...");

let response = client.session().create(
    CreateSessionTicketRequest::agent_access(
        vec!["agent_1".to_string(), "agent_2".to_string()],
        "777"
    )
)
.send()
.await?;

println!("Ticket: {}", response.ticket);

Webhook App Access Ticket

Grant access to a webhook app:
use wacht::WachtClient;
use wacht::models::{CreateSessionTicketRequest, TicketType};

let client = WachtClient::new("wk_live_...");

let response = client.session().create(
    CreateSessionTicketRequest::webhook_app_access("payment-webhooks")
)
.send()
.await?;

println!("Ticket: {}", response.ticket);

API Auth App Access Ticket

Grant access to an API auth app:
use wacht::WachtClient;
use wacht::models::{CreateSessionTicketRequest, TicketType};

let client = WachtClient::new("wk_live_...");

let response = client.session().create(
    CreateSessionTicketRequest::api_auth_access("mobile-app")
)
.send()
.await?;

println!("Ticket: {}", response.ticket);

With Custom Expiration

Set a custom expiration timestamp (Unix timestamp):
use wacht::WachtClient;
use wacht::models::{CreateSessionTicketRequest, TicketType};
use std::time::{SystemTime, UNIX_EPOCH};

let client = WachtClient::new("wk_live_...");

let expires_at = SystemTime::now()
    .duration_since(UNIX_POCH)
    .unwrap()
    .as_secs() as i64 + 3600; // 1 hour from now

let response = client.session().create(
    CreateSessionTicketRequest::impersonation("user_123")
        .expires_at(expires_at)
)
.send()
.await?;

Exchanging Tickets

Tickets are exchanged on the frontend using the session API:
GET /session/ticket/exchange?ticket=<ticket_string>
The exchange endpoint:
  • Validates the ticket
  • Creates the appropriate session (impersonation, agent, webhook, or API auth)
  • Returns session details
  • Deletes the ticket (single-use)

Exchange Response

The response varies by ticket type:

Impersonation Response

{
  "success": true,
  "message": "Impersonation successful",
  "session": { ... }
}

Agent Access Response

{
  "success": true,
  "message": "Agent session created",
  "session_id": "1234567890123456789",
  "actor": {
    "id": "777",
    "display_name": "Debug Actor 777",
    "subject_type": "debug",
    "external_key": "777"
  },
  "agents": [
    {
      "id": "agent_1",
      "name": "Support Agent",
      "description": "Handles customer support"
    }
  ]
}

Webhook App Access Response

{
  "success": true,
  "message": "Webhook app session created",
  "session_id": "123456789",
  "webhook_app": {
    "app_slug": "payment-webhooks",
    "name": "Payment Webhooks",
    "signing_secret": "whsec_xxx",
    "is_active": true
  }
}

API Auth App Access Response

{
  "success": true,
  "message": "API auth app session created",
  "session_id": "123456789",
  "api_auth_app": {
    "id": "mobile-app",
    "app_slug": "mobile-app",
    "name": "Mobile Application",
    "is_active": true,
    "rate_limits": { ... }
  }
}

Security Considerations

  1. Single-use: Tickets are deleted after exchange
  2. Expiration: Always set reasonable expiration times
  3. HTTPS: Only exchange tickets over secure connections
  4. Validation: The frontend validates deployment ID matches

Error Handling

use wacht::{Error, WachtClient};
use wacht::models::{CreateSessionTicketRequest, TicketType};

let client = WachtClient::new("wk_live_...");

match client.session().create(
    CreateSessionTicketRequest::impersonation("invalid_user")
)
.send()
.await {
    Ok(response) => println!("Ticket: {}", response.ticket),
    Err(Error::Api { status, message, .. }) => {
        eprintln!("API Error {}: {}", status, message);
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}