Documentation

Programmable payments

Programmable payments hold USDC in smart contracts and release to a single recipient based on vesting schedules (paymentType vesting), time locks (paymentType time_lock), or threshold-based sweeps. Separate from share payouts which split revenue immediately at settlement. Delayed gratification, but on-chain and auditable.

Need machine-readable request/response bodies for your AI or codebase? Download this page as plain Markdown.

When should I use this?

  • Contractor token vesting with cliff and monthly unlocks.
  • Treasury funds locked until a product launch date (time_lock).
  • Auto-sweep excess hot-wallet USDC to cold storage when balance exceeds a threshold.

Why use Videpay?

  • Trustless on-chain release conditions: recipient claims or automaticRelease handles due amounts.
  • prepare → activate/relay → sync lifecycle with typed data and permit support.
  • Threshold rules automate treasury hygiene without cron scripts.
  • Rich webhook coverage for vesting, timelock, and threshold events.

12-month contractor vesting

You lock 12,000 USDC via POST /programmable-payments/vestings/prepare with a 90-day cliff and 12 monthly periods. After the owner signs activation, automaticRelease releases each tranche on schedule and emits programmable-payment.vesting.released.

Before you start

  • Payer wallet with USDC balance and allowance for the programmable payment contract
  • Recipient wallet address at prepare time
  • For threshold rules: sourceWalletAddress monitored and recipientAddress for sweeps

How programmable payments work

  1. Prepare: POST vestings/prepare or time-locks/prepare returns payment record and activation intent.
  2. Activate: payer signs; POST :paymentId/activate/relay submits on-chain. Emits *.created webhook.
  3. Sync: POST :paymentId/sync with txHash if needed to reconcile delayed settlement updates.
  4. Release: POST :paymentId/release for manual claims, or enable automaticRelease for cron automation.
  5. Cancel: POST :paymentId/cancel revokes unreleased vesting balance (vesting only).
  6. Threshold rules: separate CRUD under /threshold-rules with trigger and automation toggles.

Dashboard features

Dashboard → Payments → Programmable payments

Create vesting or time-lock payments from the dashboard forms: same fields as prepare endpoints. View payment status, toggle automaticRelease, trigger manual release, and manage threshold rules. Activation opens the owner wallet signing flow matching POST activate/relay.

  1. Vesting tab: cliff, duration, periods, automaticRelease toggle.
  2. Time lock tab: releaseAt datetime picker.
  3. Threshold rules: source wallet, threshold, sweep amount, automaticTrigger.
  4. Payment detail: sync, release, cancel, automation controls.

Vesting payments

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
payerAddressaddressYesWallet that locks funds (typically merchant owner or treasury hot wallet).
recipientAddressaddressYesWallet that claims vested tranches.
assetstringYesAsset symbol (USDC).
amountdecimal stringYesTotal locked amount in human units (e.g. "12000" for 12,000 USDC).
cliffDelaySecondsintegerYesSeconds after activation before any vesting unlocks.
durationSecondsintegerYesTotal vesting duration in seconds from activation.
periodsintegerYesNumber of equal vesting periods after the cliff.
automaticReleasebooleanNoWhen true, due tranches are released automatically by background jobs.
paymentIduuidNoOptional custom payment UUID.
authorizationobjectNoDashboard only. Step-up confirmation (PIN, OTP, or 2FA) when a logged-in owner acts in the browser. Omit entirely for secret API key integrations: the server skips this check when you authenticate with x-api-key. On sandbox, any emailed OTP code is `000000` (six zeroes). It's giving dev mode. Live sends a real code.
authorization.pinstringNoTransaction PIN when enabled.
authorization.otpChallengeIduuidNoOTP challenge from a prior dashboard auth step. On sandbox, enter `000000` when verifying the emailed code.
authorization.twoFactorCodestringNoTOTP code when 2FA is enabled.
POST/programmable-payments/vestings/prepare

Prepare a vesting payment (paymentType vesting). Emits programmable-payment.vesting.prepared.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",03  "chain": "base",04  "payerAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",05  "recipientAddress": "0xContractor12345678901234567890123456789012",06  "asset": "USDC",07  "amount": "12000",08  "cliffDelaySeconds": 7776000,09  "durationSeconds": 31536000,10  "periods": 12,11  "automaticRelease": true12}

Time-lock payments

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
payerAddressaddressYesWallet that locks funds until releaseAt.
recipientAddressaddressYesWallet that receives funds on release.
assetstringYesAsset symbol (USDC).
amountdecimal stringYesLocked amount in human units.
releaseAtdatetimeYesISO-8601 datetime when funds become releasable.
automaticReleasebooleanNoWhen true, funds release automatically at releaseAt without a manual POST /release.
paymentIduuidNoOptional custom payment UUID.
authorizationobjectNoDashboard only. Step-up confirmation (PIN, OTP, or 2FA) when a logged-in owner acts in the browser. Omit entirely for secret API key integrations: the server skips this check when you authenticate with x-api-key. On sandbox, any emailed OTP code is `000000` (six zeroes). It's giving dev mode. Live sends a real code.
authorization.pinstringNoTransaction PIN when enabled.
authorization.otpChallengeIduuidNoOTP challenge from a prior dashboard auth step. On sandbox, enter `000000` when verifying the emailed code.
authorization.twoFactorCodestringNoTOTP code when 2FA is enabled.
POST/programmable-payments/time-locks/prepare

Prepare a time-lock payment (paymentType time_lock). Emits programmable-payment.timelock.prepared.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",03  "chain": "base",04  "payerAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",05  "recipientAddress": "0xTreasuryCold123456789012345678901234567890",06  "asset": "USDC",07  "amount": "50000",08  "releaseAt": "2027-01-01T00:00:00.000Z",09  "automaticRelease": true10}

Activate, sync, release, and cancel

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
activationSignature / activationDeadline / activationNoncestringNoFrom activationIntent typed data after payer signs.
permitSignature / permitDeadlinestringNoRequired when token permit is needed instead of approve tx.
automaticReleasebooleanNoEnable or disable automatic release/trigger cron.
authorizationobjectNoDashboard only. Step-up confirmation (PIN, OTP, or 2FA) when a logged-in owner acts in the browser. Omit entirely for secret API key integrations: the server skips this check when you authenticate with x-api-key. On sandbox, any emailed OTP code is `000000` (six zeroes). It's giving dev mode. Live sends a real code.
authorization.pinstringNoTransaction PIN when enabled.
authorization.otpChallengeIduuidNoOTP challenge from a prior dashboard auth step. On sandbox, enter `000000` when verifying the emailed code.
authorization.twoFactorCodestringNoTOTP code when 2FA is enabled.
GET/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/activation

Get activation intent and typed data for a prepared payment.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
POST/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/activate/relay

Submit payer activation signature (and optional permit). Emits *.created webhook on confirmation.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",03  "chain": "base",04  "activationSignature": "0x...",05  "activationDeadline": "1740000000",06  "activationNonce": "0",07  "permitSignature": "0x...",08  "permitDeadline": "1740000000"09}
POST/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/sync

Reconcile payment state from an on-chain txHash.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "txHash": "0xabc123def4567890123456789012345678901234567890123456789012345678"03}
POST/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/release

Manually release the next vested tranche or full time-lock amount when due. Emits *.released.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "authorization": {03    "pin": "1234"04  }05}
POST/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/automation

Toggle automaticRelease for background release jobs.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "automaticRelease": false03}
POST/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789/cancel

Cancel unreleased vesting balance (vesting payments only). Emits programmable-payment.vesting.cancelled.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{}
GET/programmable-payments/:pp_1a2b3c4d-5e6f-7890-abcd-ef123456789

Retrieve payment status, released amounts, and schedule metadata.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
GET/programmable-payments?paymentType=vesting&status=active

List programmable payments with filters.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Threshold sweep rules

Monitor a source wallet balance and sweep USDC to a recipient when balance exceeds thresholdAmount. Use automaticTrigger for hands-off treasury hygiene.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
sourceWalletAddressaddressYesHot wallet monitored for balance threshold.
recipientAddressaddressYesCold storage or treasury wallet receiving swept funds.
assetstringYesAsset symbol to monitor and sweep (USDC).
thresholdAmountdecimal stringYesBalance above which a sweep is eligible.
sweepAmountdecimal stringYesAmount to transfer when triggered.
automaticTriggerbooleanNoWhen true, background jobs trigger sweeps when balance exceeds threshold.
ruleIduuidNoOptional custom rule UUID.
authorizationobjectNoDashboard only. Step-up confirmation (PIN, OTP, or 2FA) when a logged-in owner acts in the browser. Omit entirely for secret API key integrations: the server skips this check when you authenticate with x-api-key. On sandbox, any emailed OTP code is `000000` (six zeroes). It's giving dev mode. Live sends a real code.
authorization.pinstringNoTransaction PIN when enabled.
authorization.otpChallengeIduuidNoOTP challenge from a prior dashboard auth step. On sandbox, enter `000000` when verifying the emailed code.
authorization.twoFactorCodestringNoTOTP code when 2FA is enabled.
POST/programmable-payments/threshold-rules

Create a threshold sweep rule. Emits programmable-payment.threshold.created.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",03  "chain": "base",04  "sourceWalletAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",05  "recipientAddress": "0xColdStorage1234567890123456789012345678901",06  "asset": "USDC",07  "thresholdAmount": "100000",08  "sweepAmount": "50000",09  "automaticTrigger": true10}
GET/programmable-payments/threshold-rules?limit=20

List threshold rules with optional status and wallet filters.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
GET/programmable-payments/threshold-rules/ptr_3c4d5e6f-7890-abcd-ef12-345678901234

Retrieve a threshold rule.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
POST/programmable-payments/threshold-rules/ptr_3c4d5e6f-7890-abcd-ef12-345678901234/trigger

Manually trigger a sweep when balance exceeds threshold. Emits programmable-payment.threshold.triggered.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "authorization": {03    "pin": "1234"04  }05}
POST/programmable-payments/threshold-rules/ptr_3c4d5e6f-7890-abcd-ef12-345678901234/automation

Toggle automaticTrigger for background monitoring.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "automaticTrigger": true03}
POST/programmable-payments/threshold-rules/ptr_3c4d5e6f-7890-abcd-ef12-345678901234/deactivate

Deactivate a threshold rule. Emits programmable-payment.threshold.deactivated.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{}

Payment type reference

FieldTypeRequiredDescription
paymentTypeenumNovesting or time_lock: set by prepare endpoint, echoed in responses and webhooks.
automaticReleasebooleanNoCron releases due vesting tranches or time-lock funds at releaseAt.
cliffDelaySecondsintegerNoVesting only, seconds before first unlock.
durationSeconds / periodsintegerNoVesting only, total duration and number of equal unlock periods.
releaseAtdatetimeNoTime-lock only, ISO datetime when funds unlock.

Webhooks you'll receive

Register a webhook endpoint and verify the X-Protocol-Signature header on every delivery before fulfilling orders or updating your database.

Webhookprogrammable-payment.vesting.prepared

Sent when vesting prepare completes and awaits activation.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.vesting.prepared04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.vesting.created

Sent when vesting funds are locked on-chain after activation.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.vesting.created04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.vesting.released

Sent when a vesting tranche is released to the recipient.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.vesting.released04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.vesting.cancelled

Sent when unreleased vesting balance is cancelled.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.vesting.cancelled04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.timelock.prepared

Sent when time-lock prepare completes.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.timelock.prepared04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.timelock.created

Sent when time-lock funds are locked on-chain.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.timelock.created04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.timelock.released

Sent when time-lock funds release to the recipient.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.timelock.released04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.threshold.created

Sent when a threshold sweep rule is created.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.threshold.created04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.threshold.triggered

Sent when a threshold sweep executes on-chain.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.threshold.triggered04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookprogrammable-payment.threshold.deactivated

Sent when a threshold rule is deactivated.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: programmable-payment.threshold.deactivated04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...