Skip to main content

Advanced API

The Advanced API provides full control over the ACTP protocol through ACTPClient. This is the foundation that Basic and Standard APIs are built upon.

Use Advanced API when you need:

  • Direct transaction lifecycle control
  • Custom escrow handling
  • Attestation management
  • Integration with external systems (n8n, LangChain, etc.)

ACTPClient

The main entry point for all Advanced API operations.

create()

Factory method to create an ACTPClient instance.

import { ACTPClient } from '@agirails/sdk';

const client = await ACTPClient.create(config: ACTPClientConfig);

ACTPClientConfig

OptionTypeRequiredDescription
mode'mock' | 'testnet' | 'mainnet'YesOperating mode
requesterAddressstringYesYour wallet address
privateKeystringTestnet/MainnetSigning key (0x-prefixed)
stateDirectorystringNoState path (mock only)
rpcUrlstringNoCustom RPC URL
easEASConfigNoAttestation configuration

Modes

ModeDescriptionRequirements
mockLocal developmentNone - state stored in .actp/
testnetBase SepoliaprivateKey, ETH for gas, Mock USDC
mainnetBase MainnetprivateKey, ETH for gas, Real USDC

Example

// Level 2: Advanced API - Direct protocol control
import { ACTPClient } from '@agirails/sdk';

// Mock mode (development)
const mockClient = await ACTPClient.create({
mode: 'mock',
requesterAddress: '0x1234567890123456789012345678901234567890',
});

// Testnet mode (testing)
const testnetClient = await ACTPClient.create({
mode: 'testnet',
requesterAddress: '0x...', // Will be derived from privateKey
privateKey: process.env.PRIVATE_KEY!,
rpcUrl: 'https://base-sepolia.g.alchemy.com/v2/YOUR_KEY', // Optional
});

// Mainnet mode (production)
const mainnetClient = await ACTPClient.create({
mode: 'mainnet',
requesterAddress: '0x...',
privateKey: process.env.PRIVATE_KEY!,
rpcUrl: 'https://base-mainnet.g.alchemy.com/v2/YOUR_KEY',
});

Client Properties

PropertyTypeDescription
basicBasicAdapterBasic API adapter (pay, checkStatus)
standardStandardAdapterStandard API adapter (createTransaction, etc.)
advancedIACTPRuntimeDirect protocol access (Level 2)
modeACTPClientModeCurrent operating mode

API Adapters

ACTPClient provides three access levels:

client.basic

High-level, opinionated API for simple use cases.

// Level 0: Basic API - Simple one-liners
// Create and fund a payment in one call
const result = await client.basic.pay({
to: '0xProvider...',
amount: '100',
deadline: '+24h',
});

// Check status with action hints
const status = await client.basic.checkStatus(result.txId);
if (status.canComplete) {
console.log('Provider can deliver now');
}

See Basic API for full documentation.

client.standard

Balanced API with explicit lifecycle control.

// Level 1: Standard API - Lifecycle control
// Create transaction (INITIATED state)
const txId = await client.standard.createTransaction({
provider: '0xProvider...',
amount: '100',
deadline: '+7d',
});

// Link escrow (auto-transitions to COMMITTED)
const escrowId = await client.standard.linkEscrow(txId);

// Transition state
await client.standard.transitionState(txId, 'DELIVERED');

// Release escrow after dispute window
await client.standard.releaseEscrow(escrowId, {
txId,
attestationUID: '0x...',
});

// Get transaction details
const tx = await client.standard.getTransaction(txId);
console.log('State:', tx?.state);

client.advanced

Direct protocol access for full control with protocol-level types (wei strings, unix timestamps).

// Level 2: Advanced API - Direct protocol control
import { ACTPClient, State } from '@agirails/sdk';
import { parseUnits } from 'ethers';

const client = await ACTPClient.create({
mode: 'mock',
requesterAddress: '0x...',
privateKey: process.env.PRIVATE_KEY,
});

// Create transaction with protocol-level types
const txId = await client.advanced.createTransaction({
provider: '0x...',
requester: '0x...',
amount: parseUnits('100', 6), // Wei (6 decimals for USDC)
deadline: Math.floor(Date.now() / 1000) + 86400,
disputeWindow: 172800,
});

// Get transaction
const tx = await client.advanced.getTransaction(txId);

// State transitions
await client.advanced.linkEscrow(txId);
await client.advanced.transitionState(txId, State.DELIVERED, '0x');

// Time control (mock only)
if ('time' in client.advanced) {
client.advanced.time.advance(3600); // Advance 1 hour
}

// Token minting (mock only)
if ('mintTokens' in client.advanced) {
await client.advanced.mintTokens('0x...', '1000000000'); // 1000 USDC
}

Protocol Modules

The Advanced API exposes protocol modules for direct access:

ModuleDescriptionDocumentation
KernelTransaction lifecyclekernel.md
EscrowFund managementescrow.md
EventsReal-time monitoringevents.md
EASAttestationseas.md
QuotePrice negotiationquote.md
ProofGeneratorDelivery proofsproof-generator.md
MessageSignerEIP-712 signingmessage-signer.md

Transaction States

The ACTP protocol implements an 8-state machine:

INITIATED → QUOTED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED
↓ ↓ ↓ ↓ ↓
CANCELLED CANCELLED CANCELLED CANCELLED DISPUTED → SETTLED
StateDescriptionTerminal
INITIATEDCreated, no escrowNo
QUOTEDProvider quote (optional)No
COMMITTEDEscrow linked, funds lockedNo
IN_PROGRESSProvider working (optional)No
DELIVEREDWork delivered with proofNo
SETTLEDPayment releasedYes
DISPUTEDUnder dispute resolutionNo
CANCELLEDCancelled before completionYes

Helper Methods

getAddress()

Get the client's wallet address.

// Level 2: Advanced API - Direct protocol control
const address = client.getAddress();
console.log('My address:', address);

mintTokens() (Mock only)

Mint test USDC tokens.

// Level 2: Advanced API - Direct protocol control
// Mint 1000 USDC to yourself
await client.mintTokens(client.getAddress(), '1000000000');

// Mint to another address
await client.mintTokens('0x...', '500000000');

getBalance()

Get USDC balance.

// Level 2: Advanced API - Direct protocol control
const balance = await client.getBalance(client.getAddress());
console.log('Balance:', balance); // Wei (6 decimals)

reset() (Mock only)

Reset mock state to initial values.

// Level 2: Advanced API - Direct protocol control
await client.reset();
console.log('State reset to defaults');

Error Handling

The SDK provides typed errors for precise handling:

// Level 2: Advanced API - Direct protocol control
import {
ACTPError,
InsufficientFundsError,
TransactionNotFoundError,
InvalidStateTransitionError,
DeadlineExpiredError,
ValidationError,
} from '@agirails/sdk';

try {
await client.standard.createTransaction({ ... });
} catch (error) {
if (error instanceof InsufficientFundsError) {
console.log('Need more USDC:', error.required, 'have:', error.available);
} else if (error instanceof ValidationError) {
console.log('Invalid input:', error.field, error.message);
} else if (error instanceof DeadlineExpiredError) {
console.log('Transaction expired at:', error.deadline);
} else if (error instanceof ACTPError) {
console.log('ACTP error:', error.code, error.message);
} else {
throw error; // Unknown error
}
}

See Errors for complete error hierarchy.


Complete Example

// Level 2: Advanced API - Direct protocol control
import { ACTPClient, State } from '@agirails/sdk';
import { parseUnits } from 'ethers';

async function main() {
// Create client
const client = await ACTPClient.create({
mode: 'mock',
requesterAddress: '0x1111111111111111111111111111111111111111',
});

// Setup: Mint tokens
const requester = client.getAddress();
const provider = '0x2222222222222222222222222222222222222222';

await client.mintTokens(requester, '1000000000'); // 1000 USDC
await client.mintTokens(provider, '100000000'); // 100 USDC

console.log('Requester balance:', await client.getBalance(requester));

// Create transaction with protocol-level types
const txId = await client.advanced.createTransaction({
provider,
requester,
amount: parseUnits('50', 6),
deadline: Math.floor(Date.now() / 1000) + 86400,
disputeWindow: 172800,
});
console.log('Created transaction:', txId);

// Link escrow (locks funds, auto-transitions to COMMITTED)
await client.advanced.linkEscrow(txId);
console.log('Escrow linked');

// Check transaction state
let tx = await client.advanced.getTransaction(txId);
console.log('State after escrow:', tx?.state); // COMMITTED

// Provider delivers
await client.advanced.transitionState(txId, State.IN_PROGRESS, '0x');
await client.advanced.transitionState(txId, State.DELIVERED, '0x');

tx = await client.advanced.getTransaction(txId);
console.log('State after delivery:', tx?.state); // DELIVERED

// Wait for dispute window (mock: advance time)
if ('time' in client.advanced) {
client.advanced.time.advance(172801); // 2 days + 1 second
}

// Settle transaction
await client.advanced.transitionState(txId, State.SETTLED, '0x');

tx = await client.advanced.getTransaction(txId);
console.log('Final state:', tx?.state); // SETTLED

console.log('Provider balance:', await client.getBalance(provider));
}

main().catch(console.error);

Next Steps