Production agents require reliable state management, timeout controls, and careful testing practices to avoid runaway costs and cascading failures. Withpersona provides embedded client initialization and list management APIs that enable you to build verifiable, checkpointed agent workflows at scale. Initialize Withpersona clients with callback handlers to track agent lifecycle events and implement recovery patterns for interrupted workflows. Use Withpersona's list APIs to manage reference data—email and IP address collections—that agents can safely query without external dependencies.
What this tutorial covers
- •Outcome: You will architect a TypeScript agent workflow with state checkpointing, timeout guards, tiered model routing, and comprehensive test coverage.
- •Endpoints used: `POST /api/v1/list/email-addresses`, `POST /api/v1/importer/list-item/email-addresses`, `POST /api/v1/list/ip-addresses`, `POST /api/v1/importer/list-item/ip-addresses`
- •SDK methods: `new Persona.Client({ templateId, referenceId, environmentId, onReady, onComplete, onCancel, onError })`
- •Language: typescript
- •Auth: API key (X-API-Key header) or Bearer token
- •Estimated implementation time: ~18 minutes
Step 1: Initialize Withpersona client with lifecycle callbacks
Withpersona's client initialization with callback handlers is the foundation for checkpointed agent workflows. This pattern matches Google Cloud's production-ready agent guidance for resumable state after interruptions. Set up the client with onReady, onComplete, onCancel, and onError handlers to track agent state transitions and implement recovery logic.
Create typed client with handlers
1import Persona from 'persona';
2
3const client = new Persona.Client({
4 templateId: process.env.PERSONA_TEMPLATE_ID || '',
5 referenceId: process.env.USER_ID || '',
6 environmentId: process.env.PERSONA_ENV_ID || '',
7 onReady: () => client.open(),
8 onComplete: ({ inquiryId, status, fields }) => {
9 console.log('Verification complete!', inquiryId);
10 },
11 onCancel: ({ inquiryId, sessionToken }) => console.log('User cancelled'),
12 onError: (error) => console.log('Error:', error)
13});The client emits state transitions through callbacks, allowing you to persist checkpoints and resume workflows after failures without losing context.
Step 2: Build reference data lists with Withpersona for agent context
Agents that reference static lists—email addresses, IP ranges, domains—should load these once and cache them to reduce external calls. Withpersona's list endpoints let you pre-populate and bulk-import reference data your agents will query. This pattern reduces prompt-context bloat and aligns with production best practices: smaller models for classification, reference lists for deterministic lookups.
Create and populate email address list
Step 3: Implement timeout guards and tiered model routing
Production agents need hard limits on execution time to prevent recursive loops and token overspend. Withpersona clients integrate with timeout policies and model-selection logic. Route simple classification tasks to smaller models and reserve larger models for complex reasoning, following the 80/20 principle from production field reports.
Agent with timeout and model routing
The agent enforces strict timeout boundaries and routes tasks to appropriately-sized models, preventing runaway token spend and ensuring predictable latency.
Step 4: Build IP address reference lists for network filtering
Agents that perform network risk assessment or IP classification benefit from pre-loaded IP address lists. Withpersona's IP list API enables bulk import of trusted or blocked ranges. This pattern mirrors email list management: create once, import in bulk, reference deterministically without repeated LLM calls.
Create and import IP address list
Step 5: Assemble spec-driven test coverage for agent workflows
Production-grade agent workflows require a balanced test pyramid: 80% unit tests for deterministic logic, 15% integration tests for agent–API interactions, 5% end-to-end tests for full workflows. Write specs before implementation, then verify each task in isolation before connecting agents to Withpersona's client callbacks.
Unit and integration tests for agent tasks
1import Persona from 'persona';
2import express from 'express';
3
4// UNIT TESTS: Deterministic logic (80%)
5describe('Agent workflow specs', () => {
6 it('should parse webhook event name from payload', () => {
7 const event = { attributes: { name: 'inquiry.approved' } };
8 expect(event.attributes.name).toBe('inquiry.approved');
9 });
10 it('should extract inquiry status from webhook', () => {
11 const payload = { data: { attributes: { status: 'approved' } } };
12 expect(payload.data.attributes.status).toBe('approved');
13 });
14});
15
16// INTEGRATION TESTS: Agent–API interactions (15%)
17describe('Persona client callback integration', () => {
18 it('should initialize client and invoke onComplete callback', (done) => {
19 const client = new Persona.Client({
20 templateId: 'itmpl_test',
21 referenceId: 'user_123',
22 environmentId: 'env_test',
23 onReady: () => client.open(),
24 onComplete: ({ inquiryId, status, fields }) => {
25 expect(status).toBeDefined();
26 expect(inquiryId).toBeDefined();
27 done();
28 },
29 onError: (error) => done(error)
30 });
31 });
32});
33
34// END-TO-END TESTS: Full workflows (5%)
35const app = express();
36app.use(express.json());
37app.post('/webhook', (req, res) => {
38 const data = req.body.data;
39 const eventName = data.attributes.name;
40 const inquiryStatus = data.attributes.payload.data.attributes.status;
41 if (eventName === 'inquiry.approved' && inquiryStatus === 'approved') {
42 console.log('Workflow verified: inquiry approved');
43 }
44 res.status(200).json({ message: 'Webhook received' });
45});
46app.listen(3000, () => console.log('E2E workflow server listening'));
47The test pyramid ensures fast feedback on deterministic logic (unit), validates Withpersona integration (integration), and confirms end-to-end workflows before production rollout.
Common pitfalls when using Withpersona
- •Skipping feature branch isolation during agent development. Parallel agent work without Git isolation causes merge conflicts and state corruption. Use feature branches and git worktrees for each agent task, allowing safe concurrent development and rollback if needed.
- •Over-prompting and under-reviewing agent outputs. Large system prompts inflate token costs and reduce model agility. Spec-driven development and task review gates catch hallucinations early; keep prompts minimal and pair with deterministic list references from Withpersona.
- •Omitting timeout bounds on recursive agent loops. Without hard runTimeoutSeconds limits, agents spiral into exponential token spend and cascading failures. Production workflows must enforce timeouts at every level and use smaller models for simple tasks to minimize cost and latency.
Ready to ship production agent workflows? Start building with Withpersona's client and list APIs, integrate checkpointing from day one, and enforce timeout guards before your first live test.
Documentation references
The code examples in this tutorial are grounded in the following docs pages:
- •
- •
- •
Want to streamline identity verification?
See how top tech teams use Withpersona to automate KYC, reduce fraud, and accelerate onboarding securely.

