Code Migration Examples
Conceptual v1 to v2 API pattern changes
Creating a Payment
v1 and v2 both use the /transactions endpoint. The main change is sender/receiver structure in
place of implicit customer_id / processing_id.
- Method:
POST /transactions - Body includes:
amount,type='payment',customer_id(payer),processing_id(recipient),payment_method_id - Response: Transaction with
status=processing
- Method:
POST /transactions - Body includes:
amount,type='payment',sender(account + method_id),receiver(account) - Response: Transaction with
status=processing
Creating a Payout
Payout type name changed from credit to payout, and sender/receiver structure is now
explicit.
- Method:
POST /transactions - Body includes:
amount,type='credit',processing_id(sender),customer_id(recipient),payment_method_id(bank account on customer) - Response: Transaction with
status=processing
- Method:
POST /transactions - Body includes:
amount,type='payout',sender(biller account),receiver(payee account-
method_idfor the destination bank)
-
- Optional:
funding_timing='instant'for RTP routing
Setting Up a Customer
v1 creates customers on the /customers endpoint. v2 unifies this under /accounts with
type='customer' and lets you optionally attach an Entity when you need KYC/KYB on the payer.
- Method:
POST /customers - Body includes:
name,email,phone,address - No identity verification — customers are just billing records
- Method:
POST /accountswithtype='customer' - Same core fields as v1 (
name,email,phone,address) - Optional
entityobject: attach identity/KYC data when the use case requires it (lending, high-value recurring billing, international). Omit for simple payment collection. - When an Entity is attached, KYC triggers automatically — monitor status via webhooks
Enabling Autopay
v1 stored a single default_payment_method pointer on the customer. v2 moves this to the
PaymentMethod itself via account_defaults.paying, which lets a single method cover payments,
refunds, or both without an extra pointer on the account.
- Set
default_payment_methodon the Customer to the payment method ID - One default per customer; used for autopay and any implicit charges
- Set
account_defaults.payingon the PaymentMethod to'payments'(or'refunds'/'all') — the account's autopay default is whichever method is flagged forpayments - Lives on the PaymentMethod, not the account — switch defaults by updating a different method
- Pairs with
account_defaults.funding('deposits'/'withdraws'/'all') for processing-account routing
Webhook Handling
Signature verification, idempotent event IDs, and configurable retries are available on both v1 and v2 webhooks — the handler pattern is the same across versions.
- Compute
HMAC-SHA256(body, webhook_secret)and compare to theX-Payload-Signatureheader - Deduplicate retries on the event ID
- Dispatch by
event.trigger(e.g.processed,reject,void,refund); useevent.triggered_on.idandevent.triggered_on.objectto fetch the affected resource - Optional in v2: OAuth authentication for enterprise webhooks (access token in
Authorizationheader)
You can adopt signature verification, idempotent event IDs, and configurable retries on your existing v1 webhooks today — no migration required.
Querying Reports (ARM System)
v1 had the full ARM (Advanced Report/Query) system. v2 keeps it largely unchanged, with optional custom attribute support.
- Use
select,filter_by,group_by, and aggregate functions (sum,avg,count,min,max,stddev,variance) - Limited to built-in transaction fields (amount, status, type, created_at, etc.)
-
select,filter_by,group_by, aggregate functions unchanged — same syntax as v1 - New: complex query composition. Unlocks query shapes that chained per-field predicates
couldn't express:
- Parenthesized groups for precedence control
- Complex OR / mixed AND-OR logic across different fields
- Node: native composable helpers (
pl.or(...),pl.and(...),.gte(),.ne(), etc.) - Other SDKs / raw API: string-based query language via the
q:parameter with operators==,!=,>=,<=,>,<,&&,||,date("..."),attrs[name],!= null
- Include custom attributes (
attrs[name]) in queries,fields, andgroup_by - Minimal migration effort: existing v1 queries work with minimal or no changes — adopt the new composition features when you want richer filter expressions
Two-Step Processing (Auth & Capture)
v1 had a per-API-key toggle. v2 redesigns it as two explicit modes.
- Configure API key setting:
authorize_and_capture = true/false - If true: transaction created with
status='authorized', capture later by updating status to'processed' - If false: transaction created directly with
status='processed'(single-step)
- Automatic mode (default): Payment Form / Checkout Plugin creates the authorization. Your server has 2 minutes to capture (status update). Auto-cancels if not captured. Prevents order-payment mismatches.
- Manual mode: You explicitly set
status='authorized'via API. Traditional authorize-and-capture with you controlling timing. No auto-cancel. Use for charge-after-shipment.
Payment Collection UI
v1 and v2 share the same payment collection surfaces. v2 reorganizes naming and adds the Payment Form enhancement over v1's Secure Input.
API-based:
- Create PaymentMethod inline or reference existing token
- Create Transaction directly via
POST /transactions
Form-based:
- Secure Input (embedded form fields) via Payload.js
- Checkout Plugin (modal) via Payload.js
- Payment Link (hosted, one-time or reusable) — example above
- All tokenize sensitive data client-side, return token to server
- Payment API — Direct transaction creation, maximum flexibility (unchanged)
- Payment Form — Embedded form via Payload.js with custom CSS styling (enhancement over v1 Secure Input). Tokenization still client-side, token returned to server.
- Checkout Plugin — Modal, same as v1 Checkout Plugin
- Payment Link — Same resource, now uses
payer/billerterminology (example above)
Setting Account Funding Defaults
v1 had net / gross / itemized funding modes set directly on the processing account. v2
moves funding configuration under processing settings, renames net → netted, and adds a
new manual style plus per-transaction timing tiers.
- Set
funding_styledirectly on the processing account:net,gross, oritemized - Standard settlement timing (next business day)
- Single funding method per account
- Funding style lives on processing settings (
account.processing.settings.funding.style):gross,itemized,netted, or newmanual(funds held until released) - Per-transaction timing:
funding_timingon paying transactions —standard,rapid(accelerated), orinstant(immediate availability) - Funding delay:
funding.delay(0–10 days) on processing settings for global delay;funding_delayon individual transactions for overrides - Default funding method routing:
account_defaults.fundingon PaymentMethod objects — values are'deposits','withdraws', or'all'to designate which method handles which direction - Processing Rules: admin-configured conditional overrides based on amount, card type, etc.
Migration note: Existing v1 configurations carry over as-is (with net renamed to
netted). Opt into the new options (manual style, timing tiers, multi-method funding)
when you need them.
Multi-Party Splits (Dynamic Funding)
Multi-party splits are net-new in v2 — there was no direct v1 equivalent.
- Single
POST /transactionscall includes atransfersarray - Transaction succeeds or fails atomically — all splits happen together or not at all
- Reverse flow also supported: multiple sources → single recipient
- Creates Transfer objects for tracking and webhook events
Sending a Payout Enrollment Link
v1 had a dedicated PaymentActivation endpoint for sending payout enrollment links. v2
consolidates this into the general-purpose Intent API, which handles enrollment links,
verification flows, and other time-bounded actions behind one resource.
-
POST /payment_activationswithnameandemail - Recipient receives an email with a link to enroll a payout method
-
POST /intentswithtype: 'payouts_enrollment_link'and asend_toarray - Send to multiple recipients in one call via the
send_toarray - Same Intent resource powers other flows (verification, etc.) — one endpoint to learn