Autonomous agents need a unified way to execute global payments while enforcing spend limits, KYC compliance, and idempotent retries across multiple rails. Soap is an AI-native payment infrastructure platform that orchestrates cards, banking, stablecoins, and crypto with built-in compliance controls and ML-powered auth optimization. Soap's customer, KYC, and checkout endpoints let agents handle identity verification, balance management, and multi-currency settlement in production workflows. Agent-driven payments demand idempotency and synchronous spend control—Soap's API surface supports both, plus settlement tracking across a unified ledger.
What this tutorial covers
- •Outcome: You will implement a complete agent payment loop: onboarding a customer, verifying identity, checking spend limits, and executing a withdrawal via Soap's endpoints.
- •Endpoints used: `POST /api/v1/customers`, `GET /api/v1/customers/search`, `POST /api/v1/kyc/upsert`, `POST /api/v1/checkouts`, `GET /api/v1/charges/{id}`
- •Language: typescript
- •Auth: API key (X-API-Key header) or Bearer token
- •Estimated implementation time: ~18 minutes
Step 1: Onboard and search customers with Soap
Agents must first resolve or create a customer identity in Soap. Use POST /api/v1/customers to create and GET /api/v1/customers/search to look up existing accounts by email or phone. This step ensures every agent payment is tied to a known customer entity, enabling compliance tracking and settlement reconciliation.
Create and search customer records
1const axios = require('axios');
2
3const onboardCustomer = async (email: string, phone_number: string) => {
4 const apiKey = 'YOUR_API_KEY';
5 try {
6 const searchResponse = await axios.get('https://api-sandbox.paywithsoap.com/api/v1/customers/search', {
7 params: {
8 email: email
9 },
10 headers: {
11 'Authorization': apiKey
12 }
13 });
14
15 let customerId: string;
16 if (searchResponse.data && searchResponse.data.id) {
17 customerId = searchResponse.data.id;
18 console.log('Customer found:', customerId);
19 } else {
20 const createResponse = await axios.post('https://api-sandbox.paywithsoap.com/api/v1/customers', {
21 email: email,
22 phone_number: phone_number,
23 first_name: 'Agent',
24 last_name: 'User'
25 }, {
26 headers: {
27 'Authorization': apiKey,
28 'Content-Type': 'application/json'
29 }
30 });
31 customerId = createResponse.data.id;
32 console.log('Customer created:', customerId);
33 }
34 return customerId;
35 } catch (error) {
36 console.error('Customer onboarding failed:', error);
37 throw error;
38 }
39};
40
41onboardCustomer('agent@example.com', '15551234567');Response:
1{
2 "event_id": "ev_tDaWu5aTVa2kbvDjGe55rxZpaMEmVFWB",
3 "type": "checkout.failed",
4 "data": {
5 "id": "chk_twijxXgVFofj9mdnvzF7vhbJSZEhfUpC",
6 "type": "deposit",
7 "charge": {
8 "id": "ch_yRZcCGouimTgbz4thtrfbj2mh3ZT6vnz",
9 "status": "failed",
10 "from_status": "created",
11 "amount_cents": 2500,
12 "transaction_type": "credit"
13 },
14 "customer": {
15 "id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870"
16 },
17 "line_items": [],
18 "line_items_total_amount_cents": null
19 }
20}Step 2: Verify identity with KYC in Soap
Before agents execute payments, Soap requires KYC verification for compliance. Use POST /api/v1/kyc/upsert to submit identity data (name, address, document type, and number). Synchronous KYC gates unauthorized spending and ensures all agent transactions are audit-compliant and regulatory-approved.
Upsert KYC identity verification
Response:
1{
2 "event_id": "ev_Gv7KrD7xg2Puy7AaZ1mSLTKxTURTjPaM",
3 "type": "checkout.review.approved",
4 "data": {
5 "id": "chk_KpjVV7XSXqxsW7Wg17oFmqsWQy482bhb",
6 "type": "withdrawal",
7 "review": {
8 "id": "cpilr_TfnBjgUPXvCG6KmuwxuMcRPmTFGkXm1L",
9 "status": "approved",
10 "decline_reason": null,
11 "reviewed_at": "2026-04-08T15:00:00Z",
12 "created_at": "2026-04-08T14:30:00Z",
13 "amount_cents": 5000
14 },
15 "customer": {
16 "id": "cus_Mhv5fucQqcFPhn7P8dC7GnyuMZ2R63ry"
17 }
18 }
19}Step 3: Enforce spend limits before checkout with Soap
Soap's agent payment flows demand synchronous spend-control checks before authorization. This section shows how to maintain an application ledger of committed vs. authorized amounts, preventing overspend. Even a 50 ms latency overhead for spend checks is worth the safety guardrail in autonomous workflows.
Check spend limits before checkout
1import axios from 'axios';
2
3const spendLedger: Record<string, { amount_cents: number }> = {};
4
5const enforceSpendLimit = async (
6 customerId: string,
7 requestedAmount: number,
8 maxLimitCents: number
9): Promise<boolean> => {
10 const committed = spendLedger[customerId]?.amount_cents || 0;
11 if (committed + requestedAmount > maxLimitCents) {
12 console.warn(`Spend limit exceeded for ${customerId}`);
13 return false;
14 }
15 return true;
16};
17
18const createCheckoutWithLimit = async (
19 customerId: string,
20 lineItems: Array<{ price_cents: number }>,
21 maxLimitCents: number
22) => {
23 const totalCents = lineItems[0]?.price_cents || 0;
24 const canProceed = await enforceSpendLimit(customerId, totalCents, maxLimitCents);
25 if (!canProceed) throw new Error('Spend limit enforced');
26
27 const response = await axios.post(
28 'https://api-sandbox.paywithsoap.com/api/v1/checkouts',
29 {
30 customer_id: customerId,
31 type: 'deposit',
32 line_items: lineItems,
33 experience: 'web',
34 return_url: 'https://myapp.com/store'
35 },
36 { headers: { 'Authorization': 'YOUR_API_KEY', 'Content-Type': 'application/json' } }
37 );
38 spendLedger[customerId] = { amount_cents: totalCents };
39 return response.data;
40};The application maintains a synchronized view of authorized and committed amounts, preventing the agent from issuing payment requests that exceed the daily limit.
Step 4: Create checkout and execute withdrawal via Soap
Once spend limits pass, use Soap's POST /api/v1/checkouts to create a withdrawal session. The agent then submits the payment, and Soap orchestrates the multi-rail settlement. Checkouts in Soap are idempotent by design—agents can safely retry with the same customer_id and amount without duplicate charges.
Create and track checkout session
Response:
1{
2 "event_id": "ev_Gv7KrD7xg2Puy7AaZ1mSLTKxTURTjPaM",
3 "type": "checkout.review.approved",
4 "data": {
5 "id": "chk_KpjVV7XSXqxsW7Wg17oFmqsWQy482bhb",
6 "type": "withdrawal",
7 "review": {
8 "id": "cpilr_TfnBjgUPXvCG6KmuwxuMcRPmTFGkXm1L",
9 "status": "approved",
10 "decline_reason": null,
11 "reviewed_at": "2026-04-08T15:00:00Z",
12 "created_at": "2026-04-08T14:30:00Z",
13 "amount_cents": 5000
14 },
15 "customer": {
16 "id": "cus_Mhv5fucQqcFPhn7P8dC7GnyuMZ2R63ry"
17 }
18 }
19}Step 5: Retrieve and audit charge details with Soap
After settlement, use GET /api/v1/charges/{id} to fetch the final charge record and confirm payment method, processor metadata, and customer reconciliation. Soap's charge endpoint provides the authoritative settlement record for agent payment audits, enabling complete traceability and compliance reporting.
Fetch charge details and settlement record
1import axios from 'axios';
2
3const auditChargeDetails = async (chargeId: string) => {
4 try {
5 const response = await axios.get(`https://api-sandbox.paywithsoap.com/api/v1/charges/${chargeId}`, {
6 headers: {
7 'Authorization': 'YOUR_API_KEY'
8 }
9 });
10
11 const charge = response.data;
12 console.log('Charge settlement record:', charge);
13 console.log('Charge ID:', charge.id);
14 console.log('Status:', charge.status);
15 console.log('Amount (cents):', charge.amount_cents);
16 console.log('Transaction type:', charge.transaction_type);
17 return charge;
18 } catch (error) {
19 console.error('Audit failed:', error);
20 }
21};
22
23auditChargeDetails('ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK');Response:
1{
2 "event_id": "ev_tDaWu5aTVa2kbvDjGe55rxZpaMEmVFWB",
3 "type": "checkout.failed",
4 "data": {
5 "id": "chk_twijxXgVFofj9mdnvzF7vhbJSZEhfUpC",
6 "type": "deposit",
7 "charge": {
8 "id": "ch_yRZcCGouimTgbz4thtrfbj2mh3ZT6vnz",
9 "status": "failed",
10 "from_status": "created",
11 "amount_cents": 2500,
12 "transaction_type": "credit"
13 },
14 "customer": {
15 "id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870"
16 },
17 "line_items": [],
18 "line_items_total_amount_cents": null
19 }
20}Common pitfalls when using Soap
- •Idempotency key reuse across retries. Agents must generate and cache idempotency keys per withdrawal attempt. Without proper key management, agent retries risk duplicate charges. Use a per-agent state store or distributed lock to ensure one key per logical transaction.
- •Race conditions on concurrent spend checks. If the agent issues multiple payment requests concurrently, synchronous spend checks can fail to prevent overspending if your ledger is not transactionally updated. Use atomic operations (e.g., database transactions or DynamoDB conditional writes) to serialize spend authorization.
- •Missing settlement reconciliation. Agents that create checkouts but never poll or retrieve charge details lose audit trails and settlement confirmation. Always fetch the final charge record via GET /api/v1/charges/{id} to close the loop and validate processor metadata.
- •KYC compliance gaps for cross-region agents. Agents operating across multiple regions or currencies may trigger varying KYC requirements. Validate that each customer's KYC status (verified, pending, failed) is checked before payment, and handle regional overrides in your spend-limit logic.
Your agent payment infrastructure is ready. Deploy this TypeScript workflow against Soap's production API and unlock autonomous, compliant, multi-rail settlement at scale with Soap.
Documentation references
The code examples in this tutorial are grounded in the following docs pages:
- •
- •
- •
- •
- •
Ready to scale with AI-driven payments?
Join innovators using Soap’s unified platform to boost auth rates, fight fraud, and manage global compliance with ease.

