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:
This reference tracks @zkp2p/sdk@latest, including the Curator v3,
OrchestratorV3, StakeVault, and DisputeProtectionPolicy surfaces.
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 |
rpcTransport | No | viem Transport override for RPC reads |
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 | Internal curator API key sent as x-api-key; only verifySellerPayment() uses it. Public endpoints such as quotes, maker reads, and POST /v3/sign ignore it, and quote responses carry payeeData.offchainId for every caller |
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 |
apiHeaders | No | Extra headers sent on curator quote, orderbook, and /v3/sign requests, such as x-pp-key for service callers |
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() fetches a missing gating signature through POST /v3/sign when baseApiUrl is configured; it does not require an API key for that request. Set baseApiUrl to the correct Curator root, or supply both 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.
@zkp2p/sdk@latest declares node >= 22 for Node runtimes and viem ^2.37.3 as a peer dependency. Its package metadata pins the compatible contracts, indexer schema, and attestation dependencies; do not override those versions independently. Install stable releases through the latest dist-tag.
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 | CuratorPayeeDataInput[] | One entry per processor, in the same order as processorNames. offchainId is required; telegramUsername, metadata, and identityAttestation are optional |
depositData | CuratorPayeeDataInput[] | 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. Request identity attestations separately through the attestation helpers below, then pass the result as payeeData[].identityAttestation; the SDK forwards it as metadata.identityAttestation.
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 } |
cashapp | register_cashapp | sessionCookie, requestPayload, optional requestHeaders | {} |
alipay | register_alipay | Cookie | {} |
Typed maker registration through payeeData[].identityAttestation accepts the MakerIdentityPlatform union: paypal, wise, and alipay.
Do not send a captured Venmo stories URL in encrypted session material. The 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.
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. Public maker registration does not authenticate or compare it to a linked wallet; verification still checks platform, action type, payee hash, canonical identity dataHash, signature, 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 | Buyer TEE proof input: { proofType: 'buyerTee', encryptedSessionMaterial, params }. Legacy zkTLS proof objects and JSON strings are rejected |
timestampBufferMs | No | Allowed timestamp variance in milliseconds |
attestationServiceUrl | No | Override for the attestation service |
attestationServiceFallbackUrls | No | Alternate attestation-service origins tried after network failures; omit for the default proxy, pass [] to disable fallback |
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.
| 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 unwind transactions; unsupported deployments fail closed with
AccessPolicyUnsupportedError. Reads include isEnabled, getAllowedGroups,
isWhitelisted, maxGroupsPerDepositPaymentMethod, groupExists, and isMember.
These methods remain available for integrations that must inspect or unwind
policies written before Groups were retired. Existing deposits continue to
enforce their stored policy until they are closed. Historical-policy writes are
limited to prepareDisable, prepareRemoveAllowedGroups, and
prepareRemoveWhitelistedAddresses.
New sell-deposit flows may call
prepareConfigurePeerPayMerchantDeposit({ escrow, depositId, paymentMethod })
as part of the same atomic creation batch. It always selects the protocol-owned
Peer Pay merchant group for the client's runtime environment; callers cannot
supply another group ID. General-purpose additive policy planners and writes
remain removed.
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().
Taker staking and dispute-protection risk
StakeVault collateral belongs to an effective stake owner. A taker may use
self-stake or select an owner that has explicitly authorized that taker. Always
read stakeOwnerOf(taker) immediately before attributing capacity; an expired
or revoked selection falls back to the taker's own stake on-chain.
Stake and policy reads
| Method | Returns or purpose |
|---|---|
getStakeBalance(stakeOwner) | Total stake owned |
getLockedStake(stakeOwner) | Stake locked behind live chargeback windows |
getFreeStake(stakeOwner) | Stake available for new chargebackable intents or withdrawal |
getClaimable(beneficiary) | USDC already released into the beneficiary's claim balance |
getStakeOwner(taker) | Effective owner after authorization checks |
getSelectedStakeOwner(taker) | Raw selected owner; zero address means no selection |
getTakerAuthorization(stakeOwner, taker) | Whether the owner currently sponsors the taker |
getStakeVaultState({ staker, taker? }) | Combined stake, ownership, authorization, and admissions snapshot |
getAdmissionsPaused() | Whether new chargebackable admissions are paused |
getRiskWindow(paymentMethodHash) | Minimum collateral lock window in seconds |
isDisputeProtectionEnabled(escrow, depositId, paymentMethod) | Whether that deposit payment method uses chargeback coverage |
Stake and keeper writes
| Method | Signer and behavior |
|---|---|
ensureStakeAllowance({ amount }) | Approves the StakeVault token allowance when needed |
depositStake({ amount }) | Deposits caller-owned USDC stake |
withdrawStake({ amount }) | Withdraws immediately, bounded by current free stake |
claim() | Withdraws the caller's complete claimable balance |
setTakerAuthorization({ taker, authorized }) | Lets a stake owner add or revoke a sponsored taker |
selectStakeOwner({ stakeOwner }) | Lets a taker select an owner that currently authorizes it |
clearStakeOwner() | Returns the taker to self-stake |
setDisputeProtectionEnabled({ escrow, depositId, paymentMethod, enabled }) | Depositor opt-in or opt-out; supports direct and .prepare() use |
releaseMaturedDisputeProtectionIntent() / releaseMaturedDisputeProtectionIntents() | Permissionless keeper release with a caller-pinned policy address |
StakeVault, dispute-protection, and keeper writes have direct and .prepare() forms; ensureStakeAllowance() is a plain async call. There is no
withdrawal request, cooldown, or exit queue: withdrawStake() is limited by
the current freeStake value.
Indexed state and risk helpers
client.indexer.getStakingState() accepts chainId, environment (base or
base_staging),
vaultAddress, disputeProtectionPolicyAddress, taker, and a freshly read
stakeOwner. It returns indexed ownership, balances, claims, authorizations,
risk windows, and row-level freshness. If indexed ownership has not caught up
with the supplied on-chain owner, it returns zero capacity instead of
attributing another account's stake.
The package also exports pure admission helpers:
| Helper | Contract-equivalent result |
|---|---|
calculateRequiredCoverage(amount, disputeProtected) | Full intent amount for protected methods, otherwise zero |
calculateStakeBackedCapacity(freeStake) | Maximum protected amount supportable by current free stake |
selectRiskMode(amount, freeStake, disputeProtected) | UNBONDED, STAKE_BACKED, or an insufficient-stake error |
Deployment readiness
getDisputeProtectionReadiness({ verifyPassiveSuccessor? }) pins all RPC reads
to one block and verifies the packaged deployment identity before returning one
of these states:
| State | Meaning |
|---|---|
active_successor_verified | The exact successor hook and full policy/vault stack are active |
recognized_predecessor | The exact predecessor hook remains active |
passive_successor | The predecessor remains active and the explicitly requested successor proof passed |
verified_no_hook | OrchestratorV3 has the zero lifecycle hook |
mismatch | Build identity, runtime code, wiring, or RPC verification failed |
An active_successor_verified result reports orchestratorPaused,
allowMultipleIntents, and policyAdmissionsPaused separately.
readyForDisputeProtection is true only when those operational gates allow new
protected traffic. This preserves exact deployment identity during an
admissions pause so settlement and matured-lock release can continue. Passive
verification is opt-in so known predecessor and zero-hook deployments do not
query an inactive successor by default. Local source builds carry a
deterministic, non-distributable development identity and therefore return
mismatch before RPC. Trusted package artifacts also expose their immutable
identity as SDK_BUILD_METADATA and @zkp2p/sdk/build-metadata.json.
Quote API
Both quote methods use Curator v3 and accept eligibility and payment-verification preferences in the first argument (req). The optional second argument (opts) only overrides transport settings.
getQuote(req, opts?)
Fetch available liquidity for selected payment platforms. The SDK calls POST /v3/quote/exact-fiat by default, or POST /v3/quote/exact-token when isExactFiat: false.
| Request field | Type | Required | Description |
|---|---|---|---|
paymentPlatforms | string[] | Yes | Platforms to search, such as ['wise', 'revolut'] |
fiatCurrency | string | Yes | Fiat currency code, such as USD |
user | string | Yes | Taker EVM address; eligibility and available stake are evaluated for this user |
recipient | string | Yes | Asset recipient EVM address |
destinationChainId | number | Yes | Destination chain ID; current v3 quotes support Base (8453) |
destinationToken | string | Yes | Destination token EVM address |
amount | string | Yes | Positive integer string in base units. Both modes use the destination token's decimals. With USDC (6 decimals), '100000000' means 100 USD in exact-fiat mode or 100 USDC in exact-token mode |
isExactFiat | boolean | No | true (default): fix fiat input and quote token output. false: fix token output and quote required fiat input |
mode | QuoteVisibilityMode | No | Eligibility mode; defaults to eligible. See modes |
quotePreference | QuotePreference | No | SAR / Buyer TEE pool selection and fallback. See preferences |
referrer | string | No | Referrer attribution |
referrerFeeConfig | ReferrerFeeConfig | No | Single fee { recipient, feeBps }; converted to a one-entry referralFees array when that array is omitted |
referralFees | ReferrerFeeConfig[] | No | Up to five { recipient, feeBps } entries. Takes precedence over referrerFeeConfig in the API request, including when empty. Use one representation per request |
useMultihop | boolean | No | Present in the SDK type, but current Curator v3 rejects true with Multihop not supported; omit or use false |
quotesToReturn | number | No | Positive integer quote limit, sent as a query parameter; Curator caps it at 20 |
escrowAddresses | string[] | No | Limit search to these escrows. Omitted or empty arrays use the client's configured escrow |
excludedPayToValues | string[] | No | Payee identifiers to exclude, for example a maker already tried for this order; maximum 100 values |
includeNearbyQuotes | boolean | No | Include suggestions at other amounts when no exact match exists; defaults to false |
nearbySearchRange | number | No | Maximum percentage deviation, 1-100 (10 = plus/minus 10%). Omit for no percentage limit |
nearbyQuotesCount | number | No | Suggestions per direction, 1-10; defaults to 3 |
includePrivateOrderbooks and intentGatingService are no longer fields in the published quote request types. Use mode for eligibility; whitelist access is evaluated for user. all is an orderbook browsing mode and is rejected by quote endpoints.
Quote modes
These values apply to both quote methods. mode controls which deposits the taker may access; it is independent of quotePreference.
mode | Behavior |
|---|---|
eligible | Default. Direct-route quotes: public deposits without disputes, plus whitelist-enabled deposits where user is whitelisted. A whitelisted taker can use the direct route without locking dispute stake |
eligible_with_chargeback | Also includes dispute-route quotes, even when the user has insufficient free stake. Stake must be available to lock when signaling such an intent |
eligible_with_chargeback_staked | Also includes dispute-route quotes, but only when the user's current free stake covers the required signal amount |
eligible_with_chargeback_staked is a subset of eligible_with_chargeback. Eligibility and free stake can change between quoting and signaling; a quote does not reserve either liquidity or stake.
Quote preferences
Use the singular field name quotePreference. SAR means Seller Automated Release; Buyer TEE means buyer-provided payment verification.
quotePreference | Search behavior |
|---|---|
| Omitted | Buyer TEE / non-SAR pool only, with no SAR fallback |
EXCLUSIVE_SAR | SAR pool only |
PREFER_SAR | SAR first, then Buyer TEE / non-SAR fallback |
PREFER_BUYER_TEE | Buyer TEE / non-SAR first, then SAR fallback |
EXCLUSIVE_BUYER_TEE | Buyer TEE / non-SAR pool only |
For getQuote, a preferred pass with exact matches ends the search; fallback is not used to fill the requested count with another pool. For getQuotesBestByPlatform, fallback fills platforms missing a best quote while preserving the primary pass's available quotes. SAR availability is evaluated from live seller credentials, not just whether the platform supports automation.
Per-call options
Both methods accept these fields in the second argument:
| Option | Type | Description |
|---|---|---|
baseApiUrl | string | Override the service root for this call; omit version suffixes. Defaults to the client's configured API root |
timeoutMs | number | Override the API timeout in milliseconds. Defaults to the client's timeouts.api |
import type { QuoteRequest } from "@zkp2p/sdk";
const request = {
paymentPlatforms: ["wise"],
fiatCurrency: "USD",
user: "0x0000000000000000000000000000000000000001",
recipient: "0x0000000000000000000000000000000000000002",
destinationChainId: 8453,
destinationToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: "100000000", // 100 USD, in 6-decimal units
isExactFiat: true,
mode: "eligible",
quotePreference: "PREFER_SAR",
quotesToReturn: 3,
includeNearbyQuotes: true,
nearbySearchRange: 10,
nearbyQuotesCount: 3,
} satisfies QuoteRequest;
const quote = await client.getQuote(request, { timeoutMs: 15_000 });
for (const match of quote.responseObject.quotes) {
console.log(match.payeeData.offchainId, match.tokenAmountFormatted);
}
Quote responses
getQuote() returns GetQuoteResponse, with { success, message, statusCode, responseObject }. The response object includes:
| Field | Description |
|---|---|
quotes | Array of matched quotes |
nearbySuggestions | Optional { below, above } arrays when nearby discovery is enabled and no exact match exists. Each entry contains a quote and suggested amount / percentage difference fields |
fiat, token, fees | Currency, token metadata (including decimals), and aggregate fee information |
quoteExpiresAt | Quote expiration timestamp |
orchestratorAddress | Orchestrator used for routing |
mode | Effective eligibility mode |
Each quote includes:
fiatAmount,tokenAmount, and theirFormattedvariants;conversionRateand optionaltakerConversionRateuse 18-decimal precision.intent, includingdepositId,escrowAddress, optionalorchestratorAddress,processorName,payeeDetails,amount, and recipient/currency data.maker.offchainIdand SDK-derivedpayeeData.offchainId. The SDK drops quotes with missing maker identity;payeeDatais no longer a rich metadata lookup gated on API-key authentication.- Optional
signalIntentAmount(gross token base units to pass tosignalIntent()), fee amount/display fields, andserviceFeeBps/takerReferralFeeBps. Keep the referral fees used for signaling consistent with the quote request. whitelistEnabled,allowedGroupIds,disputeProtectionOptedOut, anddisputeProtectionRequiresStakefor access and stake UX.- Optional
sellerAutomatedReleaseAvailable, indicating live, fresh seller automation credentials for this quote.
The SDK adds the compatibility fields referrerFeeAmount, referrerFeeAmountFormatted, and referrerFeeBps when referrerFeeConfig is supplied. Do not assume these SDK-derived display fields are populated for referralFees-only requests.
getQuotesBestByPlatform(req, opts?)
Fetch one best quote per supported platform. The SDK calls POST /v3/quote/best-by-platform by default, or POST /v3/quote/best-by-platform-exact-token when isExactFiat: false.
| Request field | Type | Required | Description |
|---|---|---|---|
fiatCurrency | string | Yes | Fiat currency code |
user | string | Yes | Taker EVM address used for eligibility and stake checks |
recipient | string | Yes | Asset recipient EVM address |
destinationChainId | number | Yes | Destination chain ID; currently Base (8453) |
destinationToken | string | Yes | Destination token EVM address |
amount | string | Yes | Same positive integer base-unit encoding as getQuote |
isExactFiat | boolean | No | Defaults to true |
mode | QuoteVisibilityMode | No | Same modes; defaults to eligible |
quotePreference | QuotePreference | No | Same preferences, with fallback per missing platform |
referrer | string | No | Referrer attribution |
referrerFeeConfig | ReferrerFeeConfig | No | Single referral fee configuration |
referralFees | ReferrerFeeConfig[] | No | Referral fee list; same limit and precedence as getQuote |
escrowAddresses | string[] | No | Limit to specific escrows; omitted or empty uses the client's configured escrow |
excludedPayToValues | string[] | No | Payee identifiers to exclude; maximum 100 |
minDepositSuccessRateBps | number | No | Minimum maker success rate, 0-10000 basis points |
supportBusinessAccounts | boolean | No | Allow business-account quotes; defaults to false |
This request searches all supported platforms: it has no paymentPlatforms, quotesToReturn, useMultihop, or nearby-search options. Although Curator's exact-quote API accepts additional filters, the SDK only exposes minDepositSuccessRateBps and supportBusinessAccounts on QuotesBestByPlatformRequest.
The result is GetBestByPlatformResponse. Its responseObject has the same metadata, expiry, orchestrator, and mode fields as getQuote, with platformQuotes instead of quotes. Each entry contains { platform, supported, available, bestQuote? }; check availability before using bestQuote. Best quotes have the same SDK-derived payee identity and fee display behavior as getQuote.
const best = await client.getQuotesBestByPlatform(
{
fiatCurrency: "USD",
user: "0x0000000000000000000000000000000000000001",
recipient: "0x0000000000000000000000000000000000000002",
destinationChainId: 8453,
destinationToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
amount: "100000000", // Receive exactly 100 USDC (6 decimals)
isExactFiat: false,
mode: "eligible_with_chargeback_staked",
quotePreference: "PREFER_BUYER_TEE",
supportBusinessAccounts: false,
},
{ timeoutMs: 15_000 },
);
for (const { platform, available, bestQuote } of best.responseObject
.platformQuotes) {
if (!available || !bestQuote) continue;
console.log(
platform,
bestQuote.intent.depositId,
bestQuote.payeeData.offchainId,
);
}
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. New Venmo and PayPal connections use the Google OAuth helper. The low-level encrypted-bundle API still supports backend Venmo cookie credentials, including already-stored credentials; cookie capture is not a client onboarding option. 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 Cash App, pass the seller identity plus platform-specific session material:
| Field | Required | Description |
|---|---|---|
platform | Yes | 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 |
callerAddress | No | Optional caller wallet address forwarded to the attestation service with the bundle request |
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 |
callerAddress | No | Optional caller wallet address forwarded to the attestation service with the bundle request |
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 |
attestationServiceFallbackUrls | No | Alternate attestation-service origins tried after network failures; pass [] to disable fallback |
timeoutMs | No | Request timeout in milliseconds |
attestationRuntime | No | Runtime overrides for fetch, subtle, or getRandomValues |
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: "cashapp",
offchainId: "peer-seller",
payeeId: "123456789",
sessionMaterial: {
recipientCashtag: "peer-seller",
customerId: "123456789",
requestPayload: capturedRequestBody,
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.
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. The client forwards its resolved authorization token to curator when one is configured.
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: "cashapp",
offchainId: capture.offchainId,
bundle: capture.credentialBundle,
});
Hosted Venmo receipt linking
For partner cash-out onboarding, use stable @zkp2p/cash@0.6.1 and its
optional receipt-linking methods.
Cash handles registration and environment selection. Linking never gates
cashout() or prepare().
Direct @zkp2p/sdk@0.14.2 consumers can call the top-level
getVenmoGmailConnectUrl({ payeeDetails, peerOrigin }) or
openVenmoGmailConnect({ payeeDetails, peerOrigin }) for an already-registered
Venmo payee hash. Call the popup helper directly from a click handler. It
resolves { payeeDetails } and rejects with VenmoGmailConnectError, preserving
codes such as venmo_google_oauth_receipt_not_found. Google-hosted school and
custom domains are verified by receipts, not rejected by email suffix.
The Peer-hosted page owns Google consent and code upload; partners receive no
Google codes, tokens, or email contents. Use the matching Peer/Curator
environment and read getSellerCredentialStatus() after returning or an
ambiguous popup closure. Only active plus google_oauth means linked.
Native/redirect hosts can open the generated URL and read status on return.
See the flow specification.
uploadGoogleOAuthSellerCredential()
Use uploadGoogleOAuthSellerCredential(params, opts?) when curator owns the Google OAuth encryption hop for PayPal or Venmo credentials. This is the lower-level code-upload API used by the hosted flow; partner apps should use the hosted linking helpers above.
| Field | Required | Description |
|---|---|---|
platform | Yes | paypal or venmo |
authorizationCode | Yes | One-time Google OAuth code |
payeeDetails | Yes | Hashed payee details |
redirectUri | Yes | OAuth redirect URI used to obtain the code |
payeeEmail | PayPal only | PayPal seller email |
This helper posts to curator POST /v2/makers/{platform}/{payeeDetails}/seller-credential/google-oauth. The payeeDetails value is the registered maker hash returned by /v2/makers/create. For Venmo, Curator resolves the numeric account ID from the registered username and verifies the identity hash before exchanging the Google code; do not send an account ID. All Venmo connect and reconnect UI uses this Gmail flow. Existing stored cookie credentials remain usable; the backend dual-credential wire API is separate from client onboarding.
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 |
metadata | No | Optional metadata object forwarded to the curator proxy |
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 |
apiGetOrderbookTable(params, opts) | Fetch aggregated orderbook table rows from /v3/orderbook/table with the same params as apiGetOrderbook() |
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, baseApiUrl, 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, options?) | 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?, options?) | Create a signed seller credential bundle directly through attestation service |
apiUploadSellerCredentialBundle(params, baseApiUrl?, timeoutMs?, authorizationToken?) | Register payee details if needed, verify the bundle payee hash, and store an encrypted seller credential bundle with curator |
apiGetOrderbook() accepts { currency, paymentPlatform?, mode?, takerAddress?, sortBy?, sortDirection?, sellerAutomatedRelease?, limit?, offset?, amount?, showSmallOrders?, hideExtremeSpread?, chainId?, token? }. mode takes the OrderbookVisibilityMode values all, eligible, or eligible_with_chargeback. 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.
The stable SDK uses @zkp2p/indexer-schema@0.22.0. Its default GraphQL endpoints are https://indexer.zkp2p.xyz/v1/graphql for production, https://indexer-preprod.zkp2p.xyz/v1/graphql for preproduction, and https://indexer-staging.zkp2p.xyz/v1/graphql for staging. Use indexerUrl only for an explicit override. Indexer history can lag a confirmed transaction; use the receipt and on-chain reads to establish confirmation.
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?)
Staking query
getStakingState({ chainId, environment, vaultAddress, disputeProtectionPolicyAddress, taker, stakeOwner })getStakeLocks({ chainId, vaultAddress, stakeOwner, status?, limit?, cursor? })getTakerStakeAuthorizations({ chainId, vaultAddress, stakeOwner | taker, authorized?, limit?, cursor? })pages one side of the authorization graph: the takers a stake owner has authorized, or the stake owners that have authorized a takergetStakeActivity({ chainId, vaultAddress, merchant, kind?, limit?, cursor? })getDisputeProtectionIntents({ chainId, policyAddress, throughBlockNumber, limit?, cursor? })
The page methods return { items, nextCursor, asOf }. Pass opaque cursors back
unchanged. Limits are integers from 1 through 100 and numeric fields are
unsigned decimal strings. asOf is the latest row observed in that page, not
an indexer-head or strong-consistency watermark.
throughBlockNumber is required for finalized disputes and applies an exact
inclusive upper bound to disputedAtBlockNumber. Choose the finalized cutoff in
application code and reuse it for every cursor in one ingestion pass. The
dispute page also returns endCursor, the opaque cursor of its last item even
when nextCursor is null; it is null only for an empty page. Follow
nextCursor within a pass, then persist the terminal endCursor with the
committed block/log position for the next poll.
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 |
getStakeVaultContract(chainId, env?) | Returns the StakeVault address and ABI |
getDisputeProtectionPolicyContract(chainId, env?) | Returns the DisputeProtectionPolicy address and ABI |
getOrchestratorV3Contract(chainId, env?) | Returns the current OrchestratorV3 address and ABI |
getPaymentMethodsCatalog(chainId, env?) | Returns the platform-to-hash catalog used for payment-method resolution |
getGatingServiceAddress(chainId, env?) | Returns the signer used for intent gating |
A constructed client also exposes client.getStakeVaultContract(), client.getOrchestratorV3Contract(), and client.getDisputeProtectionPolicyContract(), which return the coordinates already resolved for its chain and runtime environment.
Common companion helpers:
currencyInfogetCurrencyInfoFromHash()getCurrencyInfoFromCountryCode()resolveFiatCurrencyBytes32()resolvePaymentMethodHash()resolvePaymentMethodHashFromCatalog()resolvePaymentMethodNameFromHash()
Error handling
SDK-specific errors extend ZKP2PError, except AccessPolicyUnsupportedError, which extends Error and is thrown by client.accessPolicy when WhitelistPolicy or AddressGroupRegistry is not deployed for the environment.
| 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.