PAQ withdrawals

Prefer capability channel execute for PAQ withdrawals. The /channel/paq/* endpoints are the provider-specific alternative and also supply the external-wallet sign/process follow-ups.

Prerequisites#

  • API key with PAQ channel enabled
  • Profile context for withdraw create
  • Valid codigopaq for the destination user
  • Token balance / allowance / gas as required by the chain

Flow overview#

  1. Validate phone / código
  2. Preview amounts
  3. Create withdraw
  4. If unsigned: fetch sign payload → process sponsored tx
  5. Poll until completed, failed, or expired

1. Validate código#

curl -sS "https://api-stg.vudy.app/channel/paq/validate-phone?codigopaq=USER_CODE" \
  -H "x-api-key: vudy_sandbox_YOUR_KEY"
const { data } = await fetch(
	"https://api-stg.vudy.app/channel/paq/validate-phone?codigopaq=USER_CODE&capabilityId=CAPABILITY_UUID",
	{ headers: { "x-api-key": process.env.VUDY_API_KEY } },
).then((r) => r.json());
// { ok, valid, response?, signature? } — signature only when capabilityId is valid and consulta passes

When using capability execute, call POST /channels/paq/validate with paramKey: "codigopaq", then send params.codigopaq as ["USER_CODE", "SIGNATURE"].

2. Preview#

curl -sS "https://api-stg.vudy.app/channel/paq/preview?chain=ethereum&token=0xTOKEN_ADDRESS&amount=50" \
  -H "x-api-key: vudy_sandbox_YOUR_KEY"

3. Create withdraw#

curl -sS https://api-stg.vudy.app/channel/paq/withdraw \
  -H "x-api-key: vudy_sandbox_YOUR_KEY" \
  -H "x-profile-id: PROFILE_UUID" \
  -H "x-team-id: TEAM_UUID" \
  -H "Content-Type: application/json" \
  -d '{
    "codigopaq": "USER_CODE",
    "destinationCountry": "GT",
    "chain": "ethereum",
    "token": "USDC",
    "amount": 50,
    "note": "Cash out"
  }'
const { data } = await fetch("https://api-stg.vudy.app/channel/paq/withdraw", {
	method: "POST",
	headers: {
		"x-api-key": process.env.VUDY_API_KEY,
		"x-profile-id": profileId,
		"x-team-id": teamId,
		"Content-Type": "application/json",
	},
	body: JSON.stringify({
		codigopaq: "USER_CODE",
		destinationCountry: "GT",
		chain: "ethereum",
		token: "USDC",
		amount: 50,
		// sendWallet, sendAutomatically optional
	}),
}).then((r) => r.json());
// External flow: { txId, rechargeId, sendWallet, needsSponsorship, ... }
// Managed session wallet: { signed: true, txId, rechargeId, txHash, ... }

4. Sign and process (when needed)#

Poll GET /channels/paq/{txId}. For an external wallet, a pending transaction without txHash returns actionNeeded: true with sign and process steps:

# Sign payload
curl -sS https://api-stg.vudy.app/channel/paq/withdraw/TX_ID/sign-payload \
  -H "x-api-key: vudy_sandbox_YOUR_KEY"

# Process sponsored tx
curl -sS -X POST \
  https://api-stg.vudy.app/channel/paq/withdraw/TX_ID/process-sponsored-tx \
  -H "x-api-key: vudy_sandbox_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"userSignature":"0x..."}'
const payload = await fetch(
	`https://api-stg.vudy.app/channel/paq/withdraw/${txId}/sign-payload`,
	{ headers: { "x-api-key": process.env.VUDY_API_KEY } },
).then((r) => r.json());

// Verify payload.data.signerAddress, then sign payload.data.typedData.
await fetch(
	`https://api-stg.vudy.app/channel/paq/withdraw/${txId}/process-sponsored-tx`,
	{
		method: "POST",
		headers: {
			"x-api-key": process.env.VUDY_API_KEY,
			"Content-Type": "application/json",
		},
		body: JSON.stringify({ userSignature }),
	},
);

Status transitions#

StageStatus
Createdpending
Settledcompleted
Provider/errorfailed
Timed outexpired

Capability path#

Use POST /channels/quote + POST /channels/execute with the discovered PAQ capability. If execute returns walletFlow: "internal", providerPayload may include txHash. If it returns walletFlow: "external", poll and perform the returned sign/process steps (or use providerPayload.signPayload / txToExecute).

Next steps#