Client Reference
What this does
This page documents the published Zkp2pClient API surface for @zkp2p/sdk. Use it as the reference layer for custom integrations after you have read the higher-level walkthroughs:
The stable npm tag is 0.11.1. The Curator v3 routes and OrchestratorV3 behaviour documented here are available on @zkp2p/sdk@latest.
Constructor
Create a client with new Zkp2pClient(opts).
| Field | Required | Description |
|---|---|---|
walletClient | Yes | viem WalletClient with an attached account for signing |
chainId | Yes | Chain ID used for contract and API routing |
rpcUrl | No | Optional RPC override; otherwise the SDK uses the wallet client's chain transport |
runtimeEnv | No | Runtime environment: production, preproduction, or staging. Defaults to production |
indexerUrl | No | Override for the indexer GraphQL endpoint |
baseApiUrl | No | Override for ZKP2P service APIs |
apiKey | No | Optional curator API key — not required to get started. When provided, it enables auto-fetching signalIntent() gating signatures and enriches authenticated quote responses with maker payeeData |
authorizationToken | No | Optional bearer token for hybrid authentication |
getAuthorizationToken | No | Async token provider for long-lived clients |
indexerApiKey | No | Optional x-api-key header for indexer proxy authentication |
timeouts.api | No | API timeout in milliseconds |
import { Zkp2pClient } from "@zkp2p/sdk";
const client = new Zkp2pClient({
walletClient,
chainId: 8453,
});
Most public SDK methods work without apiKey or authorizationToken. Auth credentials are optional for normal deposit, quote, and intent flows and mostly affect response richness. signalIntent() can auto-fetch its gating signature when you provide apiKey or authorizationToken; if you do not want the SDK to make that request, pass gatingServiceSignature and signatureExpiration yourself.
Set baseApiUrl to the service root, for example https://api.zkp2p.xyz. Do not append /v1, /v2, or /v3; the SDK appends the current versioned paths internally.
The published 0.11.1 package declares node >= 22 for Node runtimes and viem ^2.37.3 as a peer dependency, and depends on @zkp2p/contracts-v2@0.4.0, @zkp2p/indexer-schema@0.20.0, and @zkp2p/zkp2p-attestation@2.0.0. Venmo identity registration requires 0.5.2 or newer — the first release whose attestation package supports the current Venmo identity registration shape.
Prepared transactions
Most write methods are "prepareable":
- Calling the method directly sends the transaction and returns a hash
- Calling
.prepare()on the same method returns aPreparedTransactionwith{ to, data, value, chainId }
const prepared = await client.signalIntent.prepare({
depositId: 42n,
amount: 100_000000n,
toAddress: "0xYourRecipientAddress",
processorName: "wise",
payeeDetails:
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
fiatCurrencyCode: "USD",
conversionRate: 1_020000000000000000n,
});
await relayer.submit({
to: prepared.to,
data: prepared.data,
value: prepared.value,
});
createDeposit() is the main exception because it may also post curator data. Use prepareCreateDeposit() when you need calldata without sending:
const { depositDetails, prepared } = await client.prepareCreateDeposit({
token: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: 1_000_000000n,
intentAmountRange: { min: 10_000000n, max: 500_000000n },
processorNames: ["wise"],
payeeData: [{ offchainId: "maker@example.com" }],
conversionRates: [
[{ currency: "USD", conversionRate: "1020000000000000000" }],
],
});
When intentGuardian is omitted, createDeposit() and
prepareCreateDeposit() use the paid guardian deployed for the client's
environment. Production and preproduction use
0x83671606454fA72ba1e2831E18C5090D25629414; staging uses
0x3355bb8CEFA54509d244384CFA7f2A71fdb1FDD6. This lets a payer purchase more
time for a live intent through the intent-lifetime extension methods. Pass
intentGuardian explicitly when using a custom guardian.
Payee registration
Use registerPayeeDetails() when you want to register payment details first and reuse the returned hashes in a later createDeposit() call.
| Parameter | Type | Description |
|---|---|---|
processorNames | string[] | Payment platforms such as wise, revolut, or venmo |
payeeData | Array<Record<string, string>> | Processor-specific payment details in the same order as processorNames |
depositData | Array<Record<string, string>> | Deprecated alias for payeeData |
registerPayeeDetails() posts each payee identity to curator POST /v2/makers/create with { processorName, offchainId, telegramUsername?, metadata? }. Curator returns the hashedOnchainId used by deposits, quotes, intents, seller credential status, and seller credential uploads. This endpoint does not accept legacy proof JSON or encrypted session material; identity attestations are requested separately through the attestation helpers below.
const { hashedOnchainIds } = await client.registerPayeeDetails({
processorNames: ["wise", "revolut"],
payeeData: [{ offchainId: "maker@example.com" }, { offchainId: "maker" }],
});
await client.createDeposit({
token: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: 1_000_000000n,
intentAmountRange: { min: 10_000000n, max: 500_000000n },
processorNames: ["wise", "revolut"],
payeeData: [{ offchainId: "maker@example.com" }, { offchainId: "maker" }],
conversionRates: [
[{ currency: "USD", conversionRate: "1020000000000000000" }],
[{ currency: "EUR", conversionRate: "950000000000000000" }],
],
payeeDetailsHashes: hashedOnchainIds,
});
Identity attestation
Identity registration is a separate Attestation Service flow for platforms that need a live account identity before curator registration. The SDK exposes it through the Nitro attestation client re-export and through the lower-level apiRequestIdentityAttestation() helper.
Current identity platform/action pairs:
| Platform | Action type | Encrypted session material | Public params |
|---|---|---|---|
venmo | register_venmo | Cookie | { SENDER_ID } |
paypal | register_paypal | Cookie | {} |
wise | register_wise | Cookie, X-Access-Token | { PROFILE_ID } |
@zkp2p/zkp2p-attestation@1.5.1Do not send a captured Venmo stories URL in encrypted session material. The current Venmo identity request sends only a replayable Cookie header plus public params.SENDER_ID. The Attestation Service derives https://account.venmo.com/api/stories?feedType=me&externalId={SENDER_ID}, verifies the authenticated account id, and requires Venmo to return a valid stories array. Upgrade to @zkp2p/sdk@0.5.2 or newer if your code still references sessionMaterial.url.
import { createNitroAttestationClient } from "@zkp2p/sdk";
const nitro = createNitroAttestationClient({
environment: "production",
attestationServiceUrl: "https://attestation-service.zkp2p.xyz",
});
const identity = await nitro.requestIdentityAttestation({
platform: "venmo",
actionType: "register_venmo",
callerAddress: "0x0000000000000000000000000000000000000002",
sessionMaterial: {
Cookie: "venmo-session-cookie-header",
},
params: {
SENDER_ID: "123456789",
},
});
console.log(identity.identity.payeeIdHash);
If you already encrypted session material outside the Nitro client, call the raw endpoint helper:
import { apiRequestIdentityAttestation } from "@zkp2p/sdk";
const response = await apiRequestIdentityAttestation(
{
callerAddress: "0x0000000000000000000000000000000000000002",
encryptedSessionMaterial,
params: { SENDER_ID: "123456789" },
},
"https://attestation-service.zkp2p.xyz",
"venmo",
"register_venmo",
);
callerAddress is required and is signed into the returned IdentityAttestation. Consumers that verify the response must bind it to the expected caller address, platform, action type, payee hash, canonical identity dataHash, and validity window.
Intent operations
signalIntent() / signalIntent.prepare()
Signals a taker-side intent and reserves liquidity from a deposit.
| Parameter | Required | Description |
|---|---|---|
depositId | Yes | Deposit ID to use |
amount | Yes | Token amount in base units |
toAddress | Yes | Recipient address for the on-chain asset |
processorName | Yes | Payment platform name |
payeeDetails | Yes | Hashed payee details for the deposit/payment method |
fiatCurrencyCode | Yes | Fiat currency such as USD or EUR |
conversionRate | Yes | Agreed conversion rate with 18 decimals |
referralFees | No | Multi-recipient referral fee list |
referrer / referrerFee | No | Deprecated legacy single-referrer fields |
referrerFeeConfig | No | Onramp-friendly referrer fee configuration |
postIntentHook | No | Post-intent hook contract address |
preIntentHookData | No | Data for a pre-intent hook |
data | No | Arbitrary bytes passed into hook-enabled flows |
escrowAddress | No | Escrow override when you want explicit routing |
orchestratorAddress | No | Orchestrator override |
gatingServiceSignature | No | Pre-obtained signature if you do not want SDK auto-fetching |
signatureExpiration | No | Signature expiration timestamp |
txOverrides | No | viem transaction overrides plus optional referrer code(s) |
cancelIntent() / cancelIntent.prepare()
Cancels a signaled intent before fulfillment.
| Parameter | Required | Description |
|---|---|---|
intentHash | Yes | 0x-prefixed 32-byte intent hash |
orchestratorAddress | No | Explicit orchestrator override |
txOverrides | No | viem transaction overrides |
fulfillIntent() / fulfillIntent.prepare()
Fulfills a signaled intent with a payment proof. The SDK handles attestation encoding for you.
| Parameter | Required | Description |
|---|---|---|
intentHash | Yes | 0x-prefixed 32-byte intent hash |
proof | Yes | zkTLS proof object/JSON string or a buyer TEE proof input |
timestampBufferMs | No | Allowed timestamp variance in milliseconds |
attestationServiceUrl | No | Override for the attestation service |
orchestratorAddress | No | Explicit orchestrator override |
postIntentHookData | No | Hook payload passed to the orchestrator |
txOverrides | No | viem transaction overrides |
callbacks | No | UI lifecycle callbacks such as onAttestationStart, onAttestationComplete, onTxSent, and onTxMined |
precomputedAttestation | No | Pre-encoded attestation data for advanced flows |
releaseFundsToPayer() / releaseFundsToPayer.prepare()
Manual release path for returning reserved funds to the deposit owner when an intent should not be fulfilled.
| Parameter | Required | Description |
|---|---|---|
intentHash | Yes | 0x-prefixed 32-byte intent hash |
orchestratorAddress | No | Explicit orchestrator override |
txOverrides | No | viem transaction overrides |
Intent lifetime extension
The standalone IntentGuardian lets any payer buy more time for a live intent.
Use hasIntentGuardian() to gate the feature, then read
getIntentGuardianPolicy() and call quoteIntentExtension() immediately
before signing. The fee is owner-governed, so pass the fresh quote through the
required maxCost ceiling.
| Method | Purpose |
|---|---|
hasIntentGuardian() | Non-throwing deployment capability check |
getIntentGuardianPolicy() | Read the current fee and lifetime limits |
quoteIntentExtension() | Read the authoritative on-chain cost |
getIntentGuardianPayerFunding() | Read payer token balance and allowance |
extendIntentLifetime() / .prepare() | Pay for and submit the lifetime extension |
extendIntentLifetime() requires escrow, depositId, intentHash,
additionalTime in seconds, and maxCost. The guardian charges the target
deposit's token, pays the deposit owner, and does not refund extension
payments.
Deposit hook controls
OrchestratorV3 has one generic pre-intent hook slot per deposit. The whitelist-hook methods in the SDK target OrchestratorV2 and remain available for existing V2 integrations; new Groups access control uses client.accessPolicy instead.
| Method | Description | Key parameters |
|---|---|---|
setDepositPreIntentHook() / .prepare() | Set the hook called before an intent is accepted | depositId, preIntentHook, escrowAddress?, orchestratorAddress? |
getDepositPreIntentHook() | Read the configured pre-intent hook | depositId, escrowAddress?, orchestratorAddress? |
setDepositWhitelistHook() / .prepare() | Set the legacy V2 whitelist hook | depositId, whitelistHook, escrowAddress?, orchestratorAddress? |
getDepositWhitelistHook() | Read the legacy V2 whitelist hook | depositId, escrowAddress?, orchestratorAddress? |
cleanupOrphanedIntents() / .prepare() | Permissionless cleanup for orphaned V2 or V3 intents | intentHashes, escrowAddress?, orchestratorAddress? |
Deposit access policy
client.accessPolicy wraps the environment's WhitelistPolicy and
AddressGroupRegistry. Check client.accessPolicy.isSupported before reading
or preparing writes; unsupported deployments fail closed. Reads include
isEnabled, getAllowedGroups, isWhitelisted, groupExists, and
isMember.
Build edits with planAccessPolicyUpdate(persisted, draft) or
diffAccessPolicy(). Prepare one step with preparePlanStep(...) or the full
ordered plan with preparePlan(...). Writes are depositor-only. In production,
the active OrchestratorV3 lifecycle hook checks this policy before admitting an
intent, so a restricted deposit rejects takers who are not directly listed or
members of an allowed group.
Vault and rate-manager operations
At the client layer, vaults are exposed as rate managers. These flows are most relevant when you are delegating deposits or managing shared pricing.
New intents route through EscrowV2 and OrchestratorV3. Existing intent reads, cancellation, and fulfillment resolve the V2 or V3 orchestrator that owns the intent. Pass an explicit escrowAddress or orchestratorAddress only when targeting a configured deployment.
Create a vault
Use createRateManager() to create a new vault.
| Field | Required | Description |
|---|---|---|
config.manager | Yes | Manager address |
config.feeRecipient | Yes | Address that receives manager fees |
config.maxFee | Yes | Maximum allowed fee |
config.fee | Yes | Current fee |
config.depositHook | No | Optional deposit hook contract |
config.minLiquidity | No | Minimum USDC liquidity required for delegation |
config.name | Yes | Human-readable name |
config.uri | Yes | Metadata URI |
txOverrides | No | viem transaction overrides |
Delegation methods
Use one of the delegation paths below depending on how the deposit is routed.
| Method | Use it when | Key parameters |
|---|---|---|
setDepositRateManager() | Delegating through the controller/registry path | escrow, depositId, registry, rateManagerId |
clearDepositRateManager() | Clearing controller-based delegation | escrow, depositId |
setRateManager() | Writing directly to EscrowV2 | depositId, rateManagerAddress, rateManagerId, escrowAddress? |
clearRateManager() | Clearing direct EscrowV2 delegation | depositId, escrowAddress? |
Vault configuration
| Method | Description | Key parameters |
|---|---|---|
setVaultFee() | Update vault manager fee | rateManagerId, newFee |
setVaultMinRate() | Set floor rate for one payment method/currency pair | rateManagerId, paymentMethodHash, currencyHash, rate |
setVaultMinRatesBatch() | Batch version of setVaultMinRate() | rateManagerId, paymentMethods, currencies, rates |
setVaultConfig() | Update manager, fee recipient, hook, name, or URI | rateManagerId, newManager, newFeeRecipient, newHook?, newName, newUri |
Payment method management
| Method | Description | Key parameters |
|---|---|---|
addPaymentMethods() | Add new payment platforms to an existing deposit | depositId, paymentMethods, paymentMethodData, currencies |
setPaymentMethodActive() | Activate or deactivate a payment method | depositId, paymentMethod, isActive |
removePaymentMethod() | Convenience alias for deactivating a payment method | depositId, paymentMethod |
Currency management
| Method | Description | Key parameters |
|---|---|---|
addCurrencies() | Add currencies to an existing payment method | depositId, paymentMethod, currencies |
deactivateCurrency() | Disable a currency for a payment method | depositId, paymentMethod, currencyCode |
removeCurrency() | Alias for deactivateCurrency() | depositId, paymentMethod, currencyCode |
Rate-manager reads
| Method | Returns | Notes |
|---|---|---|
getDepositRateManager(escrow, depositId) | { registry, rateManagerId } | Reads current delegation state |
getManagerFee(escrow, depositId) | bigint | Reads the effective manager fee |
getEffectiveRate({ escrow, depositId, paymentMethod, fiatCurrency }) | bigint | Reads effective EscrowV2 rate after manager logic |
For EscrowV2 pricing flows, the client also exposes setOracleRateConfig(), removeOracleRateConfig(), setOracleRateConfigBatch(), updateCurrencyConfigBatch(), and deactivateCurrenciesBatch().
Quote API
Use getQuote(req, opts?) to fetch available liquidity for a taker flow. The
dev SDK calls POST /v3/quote/exact-fiat by default, or
POST /v3/quote/exact-token when isExactFiat is false.
| Request field | Required | Description |
|---|---|---|
paymentPlatforms | Yes | Platforms to search, such as ['wise', 'revolut'] |
fiatCurrency | Yes | Fiat currency code |
user | Yes | Taker address |
recipient | Yes | Asset recipient address |
destinationChainId | Yes | Destination chain ID |
destinationToken | Yes | Destination token address |
amount | Yes | Amount as a string |
referrer | No | Referrer code for quote attribution |
referrerFeeConfig | No | Referrer fee recipient and BPS |
useMultihop | No | Enable multihop routing |
quotesToReturn | No | Limit quote count |
isExactFiat | No | Treat amount as fiat instead of token amount |
escrowAddresses | No | Limit search to specific escrows |
includeNearbyQuotes | No | Include nearby suggestions when no exact quote is available |
nearbySearchRange | No | Max percent deviation for nearby quote search |
nearbyQuotesCount | No | Number of nearby suggestions above and below |
includePrivateOrderbooks | No | Include whitelist-gated private orderbook deposits scoped to the requesting user |
The response includes:
responseObject.quotes: matched quotesresponseObject.nearbySuggestions: optional nearby matches whenincludeNearbyQuotesis enabled and no exact quote is availablesignalIntentAmount: gross amount you should pass intosignalIntent()when a referrer fee is appliedreferrerFeeAmount: computed fee output for the suppliedreferrerFeeConfig
const quote = await client.getQuote({
paymentPlatforms: ["wise"],
fiatCurrency: "USD",
user: "0xYourAddress",
recipient: "0xRecipientAddress",
destinationChainId: 8453,
destinationToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: "100",
isExactFiat: true,
includeNearbyQuotes: true,
});
getQuotesBestByPlatform()
Use getQuotesBestByPlatform(req, opts?) when you want the single best quote per supported payment platform instead of a flat list. The SDK calls /v3/quote/best-by-platform (or /v3/quote/best-by-platform-exact-token when isExactFiat is false) and returns one entry per platform with maker payeeData enriched into each bestQuote.
| Request field | Required | Description |
|---|---|---|
fiatCurrency | Yes | Fiat currency code |
user | Yes | Taker address |
recipient | Yes | Asset recipient address |
destinationChainId | Yes | Destination chain ID |
destinationToken | Yes | Destination token address |
amount | Yes | Amount as a string |
isExactFiat | No | Treat amount as fiat instead of token amount. Defaults to true |
referrer | No | Referrer code for quote attribution |
referrerFeeConfig | No | Referrer fee recipient and BPS |
escrowAddresses | No | Limit search to specific escrows. Defaults to the client's configured escrows |
minDepositSuccessRateBps | No | Minimum maker success rate in basis points (0-10000) |
supportBusinessAccounts | No | Allow quotes from business accounts |
intentGatingService | No | Filter by a specific intent gating service address |
includePrivateOrderbooks | No | Include whitelist-gated private orderbook deposits. Defaults to false |
The response shape mirrors getQuote but is keyed by platform:
responseObject.platformQuotes: array of{ platform, bestQuote }entriesresponseObject.quoteExpiresAt: quote expiration timestamp- Each
bestQuotecarries the samereferrerFeeAmount/ display fields asgetQuotewhen areferrerFeeConfigis supplied
const best = await client.getQuotesBestByPlatform({
fiatCurrency: "USD",
user: "0xYourAddress",
recipient: "0xRecipientAddress",
destinationChainId: 8453,
destinationToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: "100",
isExactFiat: true,
});
for (const { platform, bestQuote } of best.responseObject?.platformQuotes ??
[]) {
console.log(platform, bestQuote?.intent?.depositId, bestQuote?.payeeData);
}
Referral account APIs
Use these methods when your app needs to create, redeem, rename, or read Peer referral codes. Referral identity is keyed by wallet address. Privy bearer tokens are still supported for Peer-account flows, but external integrations can use wallet signatures without creating Privy users.
Public reads do not send auth headers and can be called from any browser origin:
| Method | Curator path | Description |
|---|---|---|
getReferralDashboard({ address }) | GET /v2/referral?address=0x... | Read a referrer's code, redemption state, reward rates, referee counts, and lifetime fees |
getReferralEarnings({ address }) | GET /v2/referral/earnings?address=0x... | Read the earnings breakdown for a referrer wallet |
lookupReferralCode(code) | GET /v2/referral/code/{code} | Resolve a code to { code, referrerWalletAddress, isActive } |
Bearer-authenticated writes use authorizationToken or getAuthorizationToken from the client or per-call options:
| Method | Curator path | Description |
|---|---|---|
createReferralCode(opts?) | POST /v2/referral/code | Create or fetch the caller's own code |
redeemReferralCode(code, opts?) | POST /v2/referral/redeem | Redeem another user's code for the authenticated wallet |
updateReferralCode(code, opts?) | PATCH /v2/referral/code | Rename the authenticated wallet's code |
Signature-authenticated writes use the configured viem walletClient and require no Privy account:
| Method | Required options | Description |
|---|---|---|
createReferralCodeWithSignature(opts?) | None | Signs and posts the CreateCode payload |
redeemReferralCodeWithSignature(code, opts?) | Optional referrerWalletAddress | Signs RedeemCode; if referrerWalletAddress is omitted, the SDK first calls lookupReferralCode(code) |
updateReferralCodeWithSignature(code, opts) | oldCode | Signs RenameCode; oldCode prevents stale rename replay |
import { Zkp2pClient } from "@zkp2p/sdk";
const client = new Zkp2pClient({
walletClient,
chainId: 8453,
});
const dashboard = await client.getReferralDashboard({
address: "0x1111111111111111111111111111111111111111",
});
const lookup = await client.lookupReferralCode("PEER42");
const { code: myCode } = await client.createReferralCodeWithSignature();
await client.redeemReferralCodeWithSignature("PEER42", {
referrerWalletAddress: lookup.referrerWalletAddress,
});
await client.updateReferralCodeWithSignature("MYCODE", {
oldCode: myCode,
});
The signature domain is:
{ name: 'ZKP2PReferral', version: '1' }
The SDK signs issuedAt as Unix seconds and defaults production signatures to audience base_production. Override audience when using a non-production API environment. Server-side freshness is 10 minutes, with a small future clock-skew allowance. Do not combine a bearer token and signature body on the same write; curator requires exactly one auth mode.
Rate limits are per minute: public dashboard and earnings reads are 30 per IP, code lookup is 60 per IP, and writes are limited to 20 per IP plus 10 per IP-wallet pair.
Seller Autopilot
Use these methods to upload seller credentials, inspect credential status, and verify seller payments for Seller Autopilot flows. Supported seller platforms are venmo, cashapp, wise, and paypal.
Seller credential upload and identity attestation are different flows. Identity attestation proves an account identity for registration. Seller Autopilot stores an encrypted credential bundle that lets the enclave verify future seller-side payments. Direct bundle upload supports venmo, cashapp, and wise; PayPal seller credentials use the Google OAuth helper. Curator status is keyed by { processorName, payeeDetails }, not maker id.
uploadSellerCredential()
Use uploadSellerCredential(params, opts?) to create a signed credential bundle through the attestation service and store the public credential status in curator. Returns CuratorSellerCredentialUploadResponse.
For registered payee platforms (venmo and cashapp), pass the seller identity plus platform-specific session material:
| Field | Required | Description |
|---|---|---|
platform | Yes | venmo or cashapp |
offchainId | Yes | Stable seller identity used for payee registration |
payeeId | Yes | Platform payee identifier |
telegramUsername | No | Optional seller Telegram username |
metadata | No | Optional curator metadata |
sessionMaterial | Yes | Platform-specific session material |
For Wise, pass only the platform and Wise session material. The enclave derives the payee hash from the submitted token:
| Field | Required | Description |
|---|---|---|
platform | Yes | wise |
sessionMaterial.apiToken | Yes | Wise Personal API Token |
sessionMaterial.profileId | No | Wise profile identifier. If omitted and multiple profiles exist, handle the profile-selection response |
Optional opts fields:
| Field | Required | Description |
|---|---|---|
baseApiUrl | No | Override for the curator base API URL |
attestationServiceUrl | No | Override for the attestation service used to sign the credential bundle |
timeoutMs | No | Request timeout in milliseconds |
attestationRuntime | No | Runtime overrides for fetch, subtle, or getRandomValues |
VenmoSessionMaterial
| Field | Required | Description |
|---|---|---|
recipientUsername | Yes | Venmo username that receives the seller payment |
accountId | Yes | Venmo account identifier |
sessionCookie | Yes | Authenticated Venmo session cookie |
requestHeaders | No | Optional request headers captured from the authenticated session |
CashAppSessionMaterial
| Field | Required | Description |
|---|---|---|
recipientCashtag | Yes | Cash App cashtag that receives the seller payment |
customerId | Yes | Cash App customer identifier |
sessionCookie | Yes | Authenticated Cash App session cookie |
requestHeaders | No | Optional request headers captured from the authenticated session |
requestPayload | Yes | Captured Cash App request payload used during verification |
WiseSessionMaterial
| Field | Required | Description |
|---|---|---|
apiToken | Yes | Wise API token |
profileId | No | Wise profile identifier |
import { Zkp2pClient } from "@zkp2p/sdk";
const client = new Zkp2pClient({
walletClient,
chainId: 8453,
});
const response = await client.uploadSellerCredential(
{
platform: "venmo",
offchainId: "peer-seller",
payeeId: "123456789",
sessionMaterial: {
recipientUsername: "peer-seller",
accountId: "123456789",
sessionCookie: "session_cookie",
requestHeaders: {
"user-agent": "Mozilla/5.0",
},
},
},
{ timeoutMs: 10_000 },
);
uploadSellerCredentialBundle()
Use uploadSellerCredentialBundle(params, opts?) when the encrypted credential bundle was already created elsewhere — typically inside a capture extension via apiCreateSellerCredentialBundle() — and you only need to register the payee and store the bundle with curator. This is the page-side half of the extension Seller Autopilot capture flow. Available from 0.5.0.
For registered payee platforms (venmo and cashapp):
| Field | Required | Description |
|---|---|---|
platform | Yes | venmo or cashapp |
offchainId | Yes | Stable seller identity used for payee registration |
bundle | Yes | Encrypted SellerCredentialBundle returned by the capture |
telegramUsername | No | Optional seller Telegram username |
metadata | No | Optional curator metadata |
For Wise, pass only platform: 'wise' and the bundle. Optional opts fields are baseApiUrl and timeoutMs.
For registered payee platforms, this helper:
- Calls curator
POST /v2/makers/createwith the suppliedoffchainId, optionaltelegramUsername, optionalmetadata, andprocessorName. - Verifies the returned
hashedOnchainIdequalsbundle.payeeIdHash. - Stores the bundle with curator
POST /v2/makers/{platform}/{hashedOnchainId}/seller-credential.
The hash check is required. It prevents a tampered capture from binding an encrypted credential bundle to different public payee details.
const response = await client.uploadSellerCredentialBundle({
platform: "venmo",
offchainId: capture.offchainId,
bundle: capture.credentialBundle,
});
uploadGoogleOAuthSellerCredential()
Use uploadGoogleOAuthSellerCredential(params, opts?) when curator owns the Google OAuth encryption hop for PayPal credentials.
| Field | Required | Description |
|---|---|---|
platform | Yes | paypal |
authorizationCode | Yes | One-time Google OAuth code |
payeeDetails | Yes | Hashed payee details |
redirectUri | Yes | OAuth redirect URI used to obtain the code |
payeeEmail | Yes | PayPal seller email |
This helper posts to curator POST /v2/makers/paypal/{payeeDetails}/seller-credential/google-oauth. The payeeDetails value is the hashed PayPal payee details bytes32.
getSellerCredentialStatus()
Use getSellerCredentialStatus(params, opts?) to fetch public seller credential status from curator. Returns CuratorSellerCredentialStatusResponse.
| Field | Required | Description |
|---|---|---|
processorName | Yes | Seller payment platform: venmo, cashapp, wise, or paypal |
payeeDetails | Yes | Hashed payee details bytes32 |
Optional opts fields:
| Field | Required | Description |
|---|---|---|
baseApiUrl | No | Override for the curator base API URL |
timeoutMs | No | Request timeout in milliseconds |
The SDK calls curator GET /v2/makers/{processorName}/{payeeDetails}/seller-credential/status. The public status DTO is { platform, payeeIdHash, status, credentialType }; maker row ids are intentionally not returned.
import { Zkp2pClient } from "@zkp2p/sdk";
const client = new Zkp2pClient({
walletClient,
chainId: 8453,
});
const response = await client.getSellerCredentialStatus(
{
processorName: "paypal",
payeeDetails:
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
},
{ timeoutMs: 10_000 },
);
verifySellerPayment()
Use verifySellerPayment(params, opts?) to verify a seller payment through curator's seller-credential proxy. Returns CuratorSellerVerifyResponse.
verifySellerPayment() requires curator's internal x-api-key, not standard SDK consumer keys. It returns 410 GONE when the seller credential is inactive or fails a re-probe.
| Field | Required | Description |
|---|---|---|
platform | Yes | Seller payment platform: venmo, cashapp, wise, or paypal |
txId | Yes | Payment transaction identifier to verify |
chainId | Yes | Chain ID associated with the verification request |
intent | Yes | SellerVerifyIntentDetails payload for the seller payment verification |
Optional opts fields:
| Field | Required | Description |
|---|---|---|
baseApiUrl | No | Override for the curator base API URL |
timeoutMs | No | Request timeout in milliseconds |
import { Zkp2pClient, type SellerVerifyIntentDetails } from "@zkp2p/sdk";
declare const sellerVerifyIntentDetails: SellerVerifyIntentDetails;
const client = new Zkp2pClient({
walletClient,
chainId: 8453,
});
const response = await client.verifySellerPayment(
{
platform: "wise",
txId: "transfer_123",
chainId: 8453,
intent: sellerVerifyIntentDetails,
},
{ timeoutMs: 10_000 },
);
Standalone API and attestation helpers
The package also exports low-level helpers for integrations that call service APIs directly instead of going through Zkp2pClient.
| Helper | Purpose |
|---|---|
apiGetOrderbook(params, opts) | Fetch orderbook entries for a fiat currency, optional platform, sort, limit, chain, and token |
apiGetDepositBundle(params, opts) | Fetch one deposit with related intents, events, profit snapshots, fund activities, and daily snapshots |
apiValidatePayeeDetails(req, baseApiUrl, timeoutMs?) | Validate a payee identity before registration |
apiGetPayeeDetails(req, apiKey, baseApiUrl, authToken?, timeoutMs?) | Resolve curator payee details from a hashed on-chain ID |
apiGetOwnerDeposits(req, apiKey, baseApiUrl, authToken?, timeoutMs?) | Fetch owner deposits from the service API |
apiGetReferralDashboard(opts) | Low-level referral dashboard read; pass address for public mode or authorizationToken for caller mode |
apiGetReferralEarnings(opts) | Low-level referral earnings read; pass address for public mode or authorizationToken for caller mode |
apiLookupReferralCode(code, opts) | Resolve a referral code to its owner wallet and active status |
apiCreateReferralCode(req, opts) | Create or fetch a referral code with bearer auth or a signature body |
apiRedeemReferralCode(req, opts) | Redeem a referral code with bearer auth or a signature body |
apiUpdateReferralCode(req, opts) | Rename a referral code with bearer auth or a signature body |
createNitroAttestationClient(opts) | Verify the Nitro enclave and request typed identity attestations, Buyer TEE attestations, or seller credential bundles through @zkp2p/zkp2p-attestation |
apiRequestIdentityAttestation(payload, attestationServiceUrl, platform, actionType) | Request an identity attestation from POST /identity after session material has already been encrypted |
createEncryptedBuyerTeeSessionMaterial(input) | Encrypt buyer TEE session material for a buyer-payment proof |
apiCreateSellerCredentialBundle(payload, attestationServiceUrl, platform, timeoutMs?, runtime?) | Create a signed seller credential bundle directly through attestation service |
apiUploadSellerCredentialBundle(params, baseApiUrl?, timeoutMs?) | Register payee details if needed, verify the bundle payee hash, and store an encrypted seller credential bundle with curator |
apiGetOrderbook() accepts { currency, paymentPlatform?, sortBy?, sortDirection?, sellerAutomatedRelease?, limit?, chainId?, token? }. sellerAutomatedRelease takes 'include' | 'exclude' | 'only' to control how Seller Autopilot liquidity appears in results. apiGetDepositBundle() accepts { depositId, escrowAddress, dailySnapshotLimit? }.
Querying on-chain data
For common read flows, start with the RPC-first methods:
getDeposits()getAccountDeposits(owner)getDeposit(depositId)getDepositsById(ids)getIntents()getAccountIntents(owner)getIntent(intentHash)getPvDepositById(depositId)getPvDepositsFromIds(ids)getPvAccountDeposits(owner)getPvAccountIntents(owner)getPvIntent(intentHash)resolvePayeeHash(depositId, paymentMethodHash)getFulfillIntentInputs(intentHash)getDepositPreIntentHook(depositId, options?)getDepositWhitelistHook(depositId, options?)getDeployedAddresses()getUsdcAddress()
For copy-paste examples around deposits and intents, see Offramp Integration.
Indexer
Use client.indexer when you need historical data, richer filtering, or pagination across all deposits and intents. All methods live on a flat namespace.
Deposit queries
getDeposits(filter?, pagination?)getDepositsWithRelations(filter?, pagination?, options?)getDepositById(compositeId, options?)getDepositsByIds(ids)getDepositsByIdsWithRelations(ids, options?)getDepositsByPayeeHash(payeeHash, options?)
Intent queries
getIntentsForDeposits(depositIds, statuses?)getOwnerIntents(owner, statuses?)getIntentsByRateManager(rateManagerId, statuses?)getIntentByHash(intentHash)getExpiredIntents({ now, depositIds, limit? })getFulfilledIntentEvents(intentHashes)— fulfillment events, includingtakerAmountNetFeesgetIntentFulfillmentAmounts(intentHash)— includestakerAmountNetFees, the net USDC the taker received after feesgetFulfillmentAndPayment(intentHash)
Fund activity and snapshots
getDepositFundActivities(depositId)getMakerFundActivities(depositor, limit?)getDepositDailySnapshots(depositId, limit?)getProfitSnapshotsByDeposits(depositIds)
Rate manager (vault) queries
getRateManagers(pagination?, filter?)getRateManagerDetail(managerId, options?)getRateManagerDelegations(managerId, pagination?)getDelegationForDeposit(depositId, options?)getManagerDailySnapshots(managerId, options?)getManualRateUpdates(managerId, options?)getOracleConfigUpdates(managerId, options?)
Raw access
query<T>({ query, variables? })— raw GraphQLclient— rawIndexerClientinstance
The package also exports IndexerRateManagerService and the standalone helper fetchIndexerFulfillmentAndPayment(client.indexer.client, intentHash).
Indexer converters
The SDK exports converter helpers for turning indexer payloads into the same EscrowDepositView shape produced by RPC reads.
| Helper | Purpose |
|---|---|
convertIndexerDepositToEscrowView(deposit, chainId, escrowAddress) | Converts a single indexer deposit (with relations) into an EscrowDepositView |
convertDepositsForLiquidity(deposits, chainId, escrowAddress, options?) | Filters and converts indexer deposits into the active liquidity set used by takers. Pass { includePrivateOrderbooks: true } to also include deposits gated by a non-zero whitelist hook (defaults to false, public orderbooks only) |
convertIndexerIntentsToEscrowViews(intents, depositViewsById) | Converts indexer intents into EscrowIntentView[] |
Oracle helpers
The SDK exports helper constants and encoders for oracle-backed ARM spread pricing.
| Helper | Purpose |
|---|---|
getSpreadOracleConfig(currency, adapters?) | Resolve the bundled Chainlink oracle config for a fiat currency |
encodeSpreadOracleAdapterConfig(config) | Encode Chainlink adapter config |
encodePythAdapterConfig(config) | Deprecated compatibility encoder for custom Pyth configs |
validateOracleFeedsOnChain(publicClient, pythContract?) | Return currencies whose bundled feeds are available on-chain |
supportsInlineOracleRateConfig({ escrowAddress? }) | Client method that reports whether the target Escrow ABI accepts inline oracle configs |
Useful constants include CHAINLINK_ORACLE_ADAPTER, DEFAULT_ORACLE_MAX_STALENESS_SECONDS, CHAINLINK_ORACLE_FEEDS, and its deprecated alias SPREAD_ORACLE_FEEDS. PYTH_ORACLE_ADAPTER, PYTH_ORACLE_FEEDS, and encodePythAdapterConfig() remain compatibility exports; the bundled Pyth feed map is empty and is not an automatic fallback.
Referrer fees
Use these helpers when you want to validate or normalize referrer fee settings before calling getQuote() or signalIntent().
| Helper | Purpose |
|---|---|
assertValidReferrerFeeConfig(config, context) | Throws if the config is invalid for getQuote, getQuotesBestByPlatform, or signalIntent |
isValidReferrerFeeRecipient(value) | Checks whether a referrer fee recipient is a valid address |
isValidReferrerFeeBps(value) | Checks whether a BPS value is allowed |
parseReferrerFeeConfig(recipient, feeBpsValue) | Builds a ReferrerFeeConfig from loosely typed input |
referrerFeeConfigToPreciseUnits(config) | Converts the fee config into precise units for on-chain use |
Attribution
The SDK includes ERC-8021 helpers for Base builder attribution.
| Helper | Purpose |
|---|---|
getAttributionDataSuffix(referrer?) | Builds the attribution suffix |
appendAttributionToCalldata(calldata, referrer?) | Appends attribution to existing calldata |
encodeWithAttribution(request, referrer?) | Encodes calldata and appends attribution in one step |
sendTransactionWithAttribution(walletClient, request, referrer?, overrides?) | Sends a transaction with appended attribution |
Useful constants:
BASE_BUILDER_CODEZKP2P_IOS_REFERRERZKP2P_ANDROID_REFERRER
Contract helpers
| Helper | Description |
|---|---|
getContracts(chainId, env?) | Returns deployed addresses and ABIs for escrow, orchestrator, verifier, ProtocolViewer, USDC, and related contracts |
getRateManagerContracts(chainId, env?) | Returns rate-manager registry/controller addresses and ABIs |
getPaymentMethodsCatalog(chainId, env?) | Returns the platform-to-hash catalog used for payment-method resolution |
getGatingServiceAddress(chainId, env?) | Returns the signer used for intent gating |
Common companion helpers:
currencyInfogetCurrencyInfoFromHash()getCurrencyInfoFromCountryCode()resolveFiatCurrencyBytes32()resolvePaymentMethodHash()resolvePaymentMethodHashFromCatalog()resolvePaymentMethodNameFromHash()
Error handling
All SDK-specific errors extend ZKP2PError.
| Class | Code | Extra fields | Use it for |
|---|---|---|---|
ZKP2PError | Any ErrorCode | details?, field? | Shared base class |
ValidationError | VALIDATION | field?, details? | Invalid input |
NetworkError | NETWORK | details? | RPC or network failures |
APIError | API | status?, details? | Failed API requests |
ContractError | CONTRACT | details? | Contract call or simulation failures |
Available error codes: VALIDATION, NETWORK, API, CONTRACT, UNKNOWN.
import {
APIError,
ContractError,
ValidationError,
ZKP2PError,
} from "@zkp2p/sdk";
try {
await client.createDeposit({
/* ... */
});
} catch (error) {
if (error instanceof ValidationError) {
console.error(error.field, error.message);
} else if (error instanceof APIError) {
console.error(error.status, error.message);
} else if (error instanceof ContractError) {
console.error(error.details);
} else if (error instanceof ZKP2PError) {
console.error(error.code, error.message);
}
}
Logging
Use setLogLevel() to adjust SDK logging.
import { setLogLevel } from "@zkp2p/sdk";
setLogLevel("debug"); // 'debug' | 'info' | 'error'
Help?
If you run into issues, join our Discord.