# Validate corporate ACH account
Source: https://docs.revolv3.com/api-reference/accountverification/validate-corporate-ach-account
/api-reference/swagger.json post /api/account-verification/ach/corporate
Validates a **corporate (business) ACH bank account** to ensure it can be used for payment processing and payouts.
This endpoint is commonly used when onboarding business merchants or partners to confirm that their company’s bank account and routing information are valid before linking it to payment flows.
It helps prevent failed transactions due to incorrect or unsupported corporate account details and returns a validation result with status and any detected errors.
# Validate personal ACH account
Source: https://docs.revolv3.com/api-reference/accountverification/validate-personal-ach-account
/api-reference/swagger.json post /api/account-verification/ach/person
Validates a **personal ACH bank account** to confirm that it can be used for electronic payments.
This endpoint is typically used during customer onboarding or before initiating the first ACH transaction to ensure the provided account number and routing number are correct and accepted by the system.
It returns a verification result and any relevant error information if the account fails validation.
# Get Merchant Access Token
Source: https://docs.revolv3.com/api-reference/authentication/get-merchant-access-token
/api-reference/swagger.json post /api/Authentication/token
Generates an **access token** used to authenticate API requests on behalf of a specific merchant.
This endpoint is typically called as part of the login or credential exchange process and requires valid client credentials (Merchant Client ID, Developer API Key), which can be generated in the Merchant Settings Profile page.
The returned token should be included in the `Authorization` header of subsequent requests to secure endpoints.
Access tokens are time-limited and may need to be refreshed once a year.
Related Links:
# Create Checkout Link
Source: https://docs.revolv3.com/api-reference/checkout/create-checkout-link
/api-reference/swagger.json post /api/Checkout
Generates a **secure, one-time checkout link** that can be shared with a customer to initiate a payment.
This URL can be seamlessly integrated into your payment flow — embedded into your payment page, or used to redirect customers to a hosted payment page managed by the platform.
The link is automatically deactivated once the customer opens the checkout page, ensuring it can’t be reused.
It’s especially useful for scenarios where merchants avoid handling sensitive data directly (e.g., to maintain PCI compliance).
# Get Complete Checkout Information
Source: https://docs.revolv3.com/api-reference/checkout/get-complete-checkout-information
/api-reference/swagger.json get /api/Checkout/{checkoutUid}
Retrieves **all available details** about a specific checkout session using its unique identifier.
This includes the customer information, transaction status, payment method used, transaction details.
It is typically used after a checkout has been completed, allowing the merchant to verify the result of the payment process.
This endpoint is useful for confirming success/failure, displaying confirmation messages, or reconciling records in your system based on the outcome of the hosted checkout.
# Add Customer Address
Source: https://docs.revolv3.com/api-reference/customers/add-customer-address
/api-reference/swagger.json post /api/Customers/{customerId}/address
Adds a **new billing or shipping address** to an existing customer profile.
The address can later be used for billing calculations, tax reporting, or to associate with subscriptions and invoices.
This endpoint is commonly used during onboarding or when a customer adds additional addresses to their profile.
Each customer can have multiple addresses, but **if a duplicate address/address type combination is submitted**, the request will be rejected with a `400 Bad Request` status.
Ensure address uniqueness (per type) before submitting to avoid validation errors.
# Create Customer
Source: https://docs.revolv3.com/api-reference/customers/create-customer
/api-reference/swagger.json post /api/Customers
Creates a **new customer** record within your merchant account.
You can provide customer details such as first name, last name, billing address, shipping address, and a Merchant Customer Ref ID (an external identifier you define).
Once created, the customer can be linked to subscriptions, payment methods, invoices, and other transactional entities.
This endpoint is typically used during onboarding or checkout flows to register the customer in the system before initiating payments.
A successful response includes the unique Customer ID assigned by the platform.
# Delete Customer
Source: https://docs.revolv3.com/api-reference/customers/delete-customer
/api-reference/swagger.json delete /api/Customers/{customerId}
Marks a **customer record as inactive**, preventing further transactions or modifications.
This soft-delete approach ensures that the customer is no longer active in your environment but preserves historical data (e.g., transactions, invoices) for reporting and compliance purposes.
**Personal data is not physically erased** by this operation. To request full data removal (e.g., for GDPR compliance), you must submit a request through the platform's dedicated support process.
Use this endpoint when a customer account needs to be closed or disabled operationally.
# Delete Customer Address
Source: https://docs.revolv3.com/api-reference/customers/delete-customer-address
/api-reference/swagger.json delete /api/Customers/{customerId}/address/{addressId}
Removes a **saved billing or shipping address** associated with a specific customer profile.
This is typically used when a customer no longer uses a particular address or wishes to replace it.
Only the specified address is removed — the customer profile and other addresses (if any) remain intact.
# Get Customer
Source: https://docs.revolv3.com/api-reference/customers/get-customer
/api-reference/swagger.json get /api/Customers/{customerId}
Retrieves the **full details of a specific customer** using their unique Customer ID.
The response includes personal information (first name, last name), billing and shipping addresses, merchant customer reference ID, and linked data.
This endpoint is useful for displaying customer profiles, validating identity before performing operations, or populating customer data in UI forms.
It can also be used to fetch up-to-date customer records during checkout or subscription management flows.
# Get Customers
Source: https://docs.revolv3.com/api-reference/customers/get-customers
/api-reference/swagger.json get /api/Customers
Retrieves a **list of customers** associated with your merchant account.
You can search for a specific customer using filters such as **Merchant Customer Ref ID**, **first name**, or **last name**.
The response includes key details for each matching customer — such as first name, last name, customer ID, and Merchant Customer Ref ID.
This endpoint is commonly used for listing customers in internal tools, verifying account existence, or syncing customer records with your system.
# Get Subscriptions by Customer
Source: https://docs.revolv3.com/api-reference/customers/get-subscriptions-by-customer
/api-reference/swagger.json get /api/Customers/{customerId}/subscriptions
Retrieves a **list of all subscriptions** linked to a specific customer, identified by their Customer ID.
This includes active, or cancelled subscriptions — each with details such as billing plan, billing cycle, status, and payment method.
The endpoint is typically used to display a customer's subscription history, manage their recurring payments, or determine eligibility for changes (e.g., upgrade, cancellation).
# Search Invoices for Customer
Source: https://docs.revolv3.com/api-reference/customers/search-invoices-for-customer
/api-reference/swagger.json get /api/Customers/{customerId}/invoices
Searches for **invoices associated with a specific customer**, using optional filters such as **Merchant Customer Ref ID**, **Merchant Invoice Ref ID**, **start date**, and **end date**.
The filter applies to the **billing date** of each invoice.
Results are returned in a paginated format using the **Page** and **PageSize** query parameters.
If not specified, page 1 is returned with up to 100 results.
The maximum supported **PageSize** is 100 entries per request.
Use this endpoint to retrieve a customer's invoice history, monitor billing activity, or generate reports for specific periods or identifiers.
Returns `404 Not Found` if the Customer ID does not exist, or `400 Bad Request` for invalid date inputs.
# Update Address
Source: https://docs.revolv3.com/api-reference/customers/update-address
/api-reference/swagger.json patch /api/Customers/{customerId}/address/{addressId}
Updates the **details of an existing customer address**, such as street, city, postal code, or country.
Only the fields provided in the request will be updated — others will remain unchanged.
This endpoint is commonly used when a customer changes residence, corrects an error in their address, or updates billing information for compliance or tax purposes.
# Update Customer
Source: https://docs.revolv3.com/api-reference/customers/update-customer
/api-reference/swagger.json patch /api/Customers/{customerId}
Updates the **details of an existing customer**, such as their first name, last name, or merchant customer reference ID.
Only the fields provided in the request will be updated — all other customer data remains unchanged.
This endpoint is typically used when customers change their names, correct a typo, or update their profile during checkout or in an admin panel.
# Get Invoice
Source: https://docs.revolv3.com/api-reference/invoices/get-invoice
/api-reference/swagger.json get /api/Invoices/{invoiceId}
Retrieves detailed information about a **specific invoice** using its unique invoice ID.
This endpoint returns invoice metadata, payment status, amount, associated payment method references, and timestamps related to invoice attempts.
It’s ideal when you already know the invoice ID and need to fetch its full details for display, audit, or troubleshooting purposes.
Supports use cases like viewing a transaction in the portal or validating an invoice after a payment operation.
Optionally, you can set **includeRawProcessorResponse = true** to include the raw response returned from the payment processor, which can help with advanced debugging or support cases.
# Get Invoices
Source: https://docs.revolv3.com/api-reference/invoices/get-invoices
/api-reference/swagger.json get /api/Invoices
Retrieves a **list of all invoices** across your merchant account, with optional filtering by **Merchant Customer Ref ID**, **Merchant Invoice Ref ID**, **start date**, and **end date**.
Date filters apply to the invoice’s **billing date**.
The endpoint supports pagination via **Page** and **PageSize** query parameters — with a maximum of **100 entries per page**. If not specified, the default is **page 1** with **100 results**.
Use this endpoint to generate invoice reports, build customer dashboards, or review billing activity over a selected period.
Returns `400 Bad Request` for invalid date input.
# Get Invoices V1
Source: https://docs.revolv3.com/api-reference/invoices/get-invoices-v1
/api-reference/swagger.json get /api/Invoices/v{version}
Returns a **detailed list of invoices** using the latest version of our invoice retrieval logic.
This endpoint provides comprehensive invoice information, including status, payment attempts, raw processor responses (if enabled), and additional filtering options available beyond the legacy version.
It supports flexible search by merchant customer reference, billing timestamps, and update timestamps.
Pagination is supported via **Page** and **PageSize** query parameters — with a maximum of **100 entries per page**. If not specified, the default is **page 1** with **100 results**.
Use this endpoint to power dashboards, reporting tools, or reconciliation processes requiring complete invoice details.
This is the **recommended endpoint** for retrieving invoices moving forward.
# One Time Payment Without Subscription
Source: https://docs.revolv3.com/api-reference/invoices/one-time-payment-without-subscription
/api-reference/swagger.json post /api/Invoices/payment
Processes a **one-time payment** for a customer without requiring an active subscription.
This endpoint is ideal for standalone transactions such as single purchases.
A one-time payment without a subscription allows you to both authorize and capture funds in a single transaction, as well as capture previously authorized amounts. You can also send a partial capture if needed.
You must provide the invoice details, and payment method.
The request supports credit cards, network tokens, ACH, Apple Pay, and Google Pay.
⚠️ **Deprecated:** This endpoint is still supported but is no longer recommended for new integrations.
Please use the newer endpoints Sale With Payment Method Details, Sale With Payment Method Id or Capture instead, which provides extended functionality and improved error handling.
# Refund Invoice
Source: https://docs.revolv3.com/api-reference/invoices/refund-invoice
/api-reference/swagger.json post /api/Invoices/{invoiceId}/refund
Initiates a **refund** for a previously paid invoice.
This endpoint allows full or partial refunds, depending on the amount specified in the request.
You must supply the unique `invoiceId` of the transaction to be refunded, along with the refund amount (for partial refund).
The system validates the refund against the original payment details and ensures it does not exceed the total invoice value.
Useful for customer-initiated cancellations, returns, or support-driven refund requests.
All refund attempts are tracked and reflected in the invoice history and reporting.
# Authorize Payment Method
Source: https://docs.revolv3.com/api-reference/paymentmethod/authorize-payment-method
/api-reference/swagger.json post /api/PaymentMethod/authorize
Performs a payment authorization for a specified amount on a stored payment method or provided card, without capturing the funds.
This is typically used to verify that the card or bank account is valid, has sufficient funds, and is accepted by the processor.
You define the authorization amount, and the system attempts to place a hold on the customer's account — which can later be captured or reversed.
This is useful for scenarios like booking flows, fraud screening, or pre-checkout validation, where upfront payment isn't required but authorization is needed.
Note: The authorization may appear as a pending transaction on the customer’s statement.
⚠️ **Deprecated:** This endpoint is still supported but is no longer recommended for new integrations.
Please use the newer endpoints Authorize With Payment Method or Authorize With Payment Method Id instead, which provides extended functionality and improved error handling.
# Create Payment Method
Source: https://docs.revolv3.com/api-reference/paymentmethod/create-payment-method
/api-reference/swagger.json post /api/PaymentMethod
Creates and stores a **new payment method** for a customer, such as a credit card, ACH account, or digital wallet token.
This endpoint accepts full payment method details and securely tokenizes them for future use.
It’s typically used during onboarding, checkout, or when a customer wants to add a new card or bank account to their profile.
The created payment method can later be used for subscriptions, or one-time payments.
# Delete Payment Method
Source: https://docs.revolv3.com/api-reference/paymentmethod/delete-payment-method
/api-reference/swagger.json delete /api/PaymentMethod/{paymentMethodId}
Marks a **stored payment method as inactive** using its unique identifier.
The method is no longer available for future charges, including subscriptions and one-time payments, but is **not physically deleted** from the system.
This approach allows for historical consistency in billing and audit logs, while preventing further use of the method. Typical use cases include expired cards, user-requested removal, or compliance-driven deactivation.
Before deactivating, ensure the payment method is not the primary one for any active subscriptions to avoid disruption.
# Get Payment Method
Source: https://docs.revolv3.com/api-reference/paymentmethod/get-payment-method
/api-reference/swagger.json get /api/PaymentMethod/{paymentMethodId}
Retrieves details about a **specific stored payment method**, using its unique identifier.
The response includes type (e.g., credit card, ACH), masked account details, expiration, and billing address.
This endpoint is commonly used to display payment method information in the UI (e.g., "Visa ending in 1234"), or confirm method existence before charging.
Useful in both customer-facing portals and internal admin tools for billing management.
# Reverse Authorization
Source: https://docs.revolv3.com/api-reference/paymentmethod/reverse-authorization
/api-reference/swagger.json post /api/PaymentMethod/reverse-auth
Cancels a **previously authorized** payment before it has been captured.
This is typically used to release a hold placed on the customer's account — for example, when an order is canceled or the final amount is still uncertain.
The endpoint requires the original `paymentMethodAuthorizationId`, and will void the existing authorization at the processor level.
It helps avoid unnecessary charges or confusion on the customer's statement and ensures accurate billing behavior.
Note: Authorizations can only be reversed if they haven't been captured yet.
# Update Payment Method
Source: https://docs.revolv3.com/api-reference/paymentmethod/update-payment-method
/api-reference/swagger.json patch /api/PaymentMethod/{paymentMethodId}
# Authorize With Payment Method Details
Source: https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-details
/api-reference/swagger.json post /api/Payments/authorization
Performs a **payment authorization** using raw payment method details (e.g., card number, expiration date, CVV, or bank account info), without capturing the funds immediately.
This is typically used when you want to place a hold on the customer’s account — for example, to confirm availability of funds before fulfillment or booking.
You must provide the full payment data along with invoice details.
The payment is validated with the processor, and if successful, an authorization is created and stored for later capture or reversal.
This endpoint is intended for **PCI-compliant merchants**, as it involves transmitting sensitive payment data directly.
The authorization can later be captured using the Capture endpoint or voided via Reverse Authorization.
# Authorize With Payment Method Id
Source: https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-id
/api-reference/swagger.json post /api/Payments/authorization/{paymentMethodId}
Performs a **payment authorization** using a previously stored payment method, referenced by its unique ID.
The funds are held on the customer’s account but **not captured** immediately.
This endpoint is typically used in multi-step checkout flows, bookings, or delayed fulfillment scenarios.
It improves security and UX by leveraging saved payment methods, eliminating the need to re-enter payment data.
The authorization can later be captured using the Capture endpoint or voided via Reverse Authorization.
Related Links:
# Capture
Source: https://docs.revolv3.com/api-reference/payments/capture
/api-reference/swagger.json post /api/Payments/capture/{paymentMethodAuthorizationId}
Captures funds from a **previously authorized transaction**, completing the payment.
Use this endpoint when you've already authorized a payment, and now want to finalize the charge.
You must provide the `paymentMethodAuthorizationId` - original authorization reference.
The amount captured can be equal to or less than the originally authorized amount, depending on business logic and processor rules.
Partial captures are supported in many cases.
Typical use cases include delayed fulfillment, pre-order models, or merchant-controlled capture flows.
# Sale With Payment Method Details
Source: https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-details
/api-reference/swagger.json post /api/Payments/sale
Processes a **direct sale transaction** using full payment method details (e.g., card number, expiry, CVV, ACH info).
This is a one-step charge operation — the payment is authorized and captured immediately.
You must provide customer and invoice details along with raw payment data.
This method is typically used by PCI-compliant merchants who collect and transmit sensitive payment data from their own secure front end.
Use this endpoint when a tokenized method is not yet available, or when the payment is initiated for a new customer.
⚠️ PCI DSS compliance is required to handle raw card or bank account data directly.
Quick Starts:
# Sale With Payment Method Id
Source: https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-id
/api-reference/swagger.json post /api/Payments/sale/{paymentMethodId}
Processes a **sale transaction** using a previously stored payment method, referenced by its unique ID.
This is a one-step payment operation that **authorizes and captures funds** in a single call.
You must provide the `paymentMethodId`, along with invoice, and amount details.
This endpoint is commonly used for charging returning customers, subscriptions, or quick-pay scenarios where the user has already saved a card, or ACH account. The payment can be either one-time or it can include data to define the initial transaction in a recurring or installment stream. This allows the networks to tie subsequent transactions back to the original approval, ensuring a seamless and efficient payment process.
It improves security and user experience by avoiding the need to re-enter payment data.
Quick Starts:
# Void
Source: https://docs.revolv3.com/api-reference/payments/void
/api-reference/swagger.json post /api/Payments/void/{invoiceId}
# Cancel Subscription
Source: https://docs.revolv3.com/api-reference/subscriptions/cancel-subscription
/api-reference/swagger.json post /api/Subscriptions/{subscriptionId}/cancel
Cancels an active subscription, stopping all future billing and scheduled invoices.
This endpoint allows for **controlled cancellation logic**, such as canceling immediately.
You must provide the `subscriptionId`.
This is commonly used in customer self-service flows, churn-prevention workflows, or manual support actions.
After cancellation, the subscription status is updated to `Cancelled` or `PendingCancellation`, but historical billing data remains accessible for reporting and audit.
# Create One Time Payment
Source: https://docs.revolv3.com/api-reference/subscriptions/create-one-time-payment
/api-reference/swagger.json post /api/Subscriptions/{subscriptionId}/payment
Creates and processes a **one-time payment under an existing subscription context**, outside of the regular billing schedule.
This is useful for charging a subscriber for additional services, setup fees, usage overages, or one-off adjustments without altering the subscription plan itself.
You must provide the `subscriptionId`, the amount and billing details.
The payment is **immediately authorized and captured**, and the transaction is linked to the subscription for reporting and tracking purposes.
This endpoint ensures flexibility in billing scenarios where extra charges are needed beyond the standard recurring invoice.
⚠️ **Deprecated:** This endpoint is still supported but is no longer recommended for new integrations.
Please use the newer endpoints Sale With Payment Method Details, Sale With Payment Method Id or Capture instead, which provides extended functionality and improved error handling.
# Create Subscription
Source: https://docs.revolv3.com/api-reference/subscriptions/create-subscription
/api-reference/swagger.json post /api/Subscriptions
Creates a **new subscription** for a customer, linking a recurring billing plan to their payment method.
You must provide details such as the customer, start date, and payment method.
Once created, the system will automatically generate invoices and process payments based on the defined billing interval.
Optional settings may include trial periods or metadata for internal tracking.
This endpoint is typically used during customer onboarding, upgrades, or checkout flows that involve recurring services.
# Create Subscription Billing Plan
Source: https://docs.revolv3.com/api-reference/subscriptions/create-subscription-billing-plan
/api-reference/swagger.json post /api/Subscriptions/{subscriptionId}/billing-plans
Creates a **new subscription billing plan** that defines the terms for recurring charges — including amount, frequency, and optional trial configuration.
You must provide details such as plan name and amount. Optional fields include billing plan CycleCount, billing plan ValueType, and billing plan StartCycleDelay.
This endpoint is typically used by admins when configuring product offerings, tiered plans, or specific billing options.
# Delete Subscription Billing Plan
Source: https://docs.revolv3.com/api-reference/subscriptions/delete-subscription-billing-plan
/api-reference/swagger.json delete /api/Subscriptions/{subscriptionId}/billing-plans/{subscriptionBillingPlanId}
Deletes a **subscription billing plan** that is no longer needed.
This operation is allowed only if the plan is **not currently associated with any active subscriptions**.
It’s typically used during cleanup, testing, or deprecation of old pricing tiers.
Attempting to delete a plan that is still in use will result in an error.
# Get Subscription
Source: https://docs.revolv3.com/api-reference/subscriptions/get-subscription
/api-reference/swagger.json get /api/Subscriptions/{subscriptionId}
Retrieves **detailed information about a specific subscription**, using its unique subscription ID.
The response includes customer reference, billing plan details, billing interval, next billing date, and associated payment method.
This endpoint is commonly used to display subscription data in customer dashboards, support portals, or admin tools.
# Get Subscriptions
Source: https://docs.revolv3.com/api-reference/subscriptions/get-subscriptions
/api-reference/swagger.json get /api/Subscriptions
Retrieves a list of **all subscriptions** under your merchant account.
This includes active and cancelled subscriptions — each returned with metadata such as customer reference, billing interval, billing plan details, and next billing date.
It’s typically used to display subscription summaries.
# Get Subscriptions By PAN
Source: https://docs.revolv3.com/api-reference/subscriptions/get-subscriptions-by-pan
/api-reference/swagger.json post /api/Subscriptions/pan-lookup
Searches for and returns **subscriptions associated with a specific PAN (Primary Account Number)** — the full card number.
This endpoint is useful for backend support or migration scenarios where subscriptions need to be located based on card information, especially across multiple customer profiles.
You must be PCI-compliant to use this endpoint, as it involves sensitive payment identifiers.
Use with caution and ensure appropriate access control is in place.
# Replace Subscription Primary Payment Method
Source: https://docs.revolv3.com/api-reference/subscriptions/replace-subscription-primary-payment-method
/api-reference/swagger.json put /api/Subscriptions/{subscriptionId}/payment-method
Replaces the **primary payment method** associated with an active subscription.
This operation is typically used when a customer updates their card, bank account, or switches to a different saved method for ongoing billing.
You must provide the `subscriptionId` and the new payment method details.
The new method will be used for all **future charges**, starting with the next billing cycle (or immediately, if a payment is due).
This endpoint helps ensure billing continuity in case of expired cards, failed payments, or customer-initiated updates.
# Update Subscription
Source: https://docs.revolv3.com/api-reference/subscriptions/update-subscription
/api-reference/swagger.json patch /api/Subscriptions/{subscriptionId}
Updates the configuration of an existing **active subscription**.
You can change properties such as the MerchantSubscriptionRefId, billing frequency, SubscriptionStatusType, SubscriptionCancelType, or next billing date without needing to cancel or recreate the subscription.
This endpoint is typically used when a customer upgrades or downgrades their plan, pauses billing, reschedules the next charge, or adjusts internal tracking fields.
Only the fields included in the request will be updated — all others remain unchanged.
Some updates may take effect immediately, while others (like plan changes) may apply from the next billing cycle, depending on configuration.
# Revolv3 Updates
Source: https://docs.revolv3.com/changelog
Revolv3 Product Updates
**October 15th, 2026**
v1.29.11.1
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Explicit Customer or Merchant Initiated Transaction Indicators | Transaction requests now accept optional fields that let merchants declare whether a transaction was initiated by the customer or the merchant, whether a stored credential is being used. When provided, these values are passed to the payment processor and shown in transaction details. When omitted, transactions are processed exactly as before, so existing integrations are not affected. |
### **API Reference Guide Updates**
| Changes | Description |
| - | - |
| Initiator and Stored Credential Fields | The API reference now describes the new optional initiator, stored credential fields available on transaction requests. |
**October 7th, 2026**
v1.29.11
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Real-Time Account Updater for Card Number Transactions | Merchants who process WorldPay transactions with full card numbers instead of processor tokens now receive Real-Time Account Updater results, and updated card details are saved automatically. |
| Full Card Number in Account Updater Responses for PCI DSS Level 1 Merchants | Merchants verified as PCI DSS Level 1 can now receive the full updated card number in account updater responses, in addition to the masked card details returned today. Merchants who are not enabled for this option continue to receive masked card details only. |
| Optional Invoice Reference on Authorization Requests | Authorization requests now accept an optional invoice reference. The value is saved, returned in the authorization response, and used as the order reference with the payment processor, making it easier to track each authorization separately. |
### **API Reference Guide Updates**
| Changes | Description |
| - | - |
| Invoice Reference Parameter on Authorization Endpoints | The API reference now describes the optional invoice reference parameter available on authorization endpoints. |
| Fixed API Reference Links | Resolved an issue where some links in the API reference returned a page not found error. |
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug Fixes and Stability Improvements | This release included various stability, reliability, and security fixes across payment processing, the Web SDK, and internal systems. |
**August 31th, 2026**
v1.29.9
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Apple Pay and Google Pay Decrypted Package Support Extended to WorldPay and Nuvei | Merchants who decrypt Apple Pay and Google Pay tokens on their own systems can now send that decrypted payment data for transactions processed through WorldPay and Nuvei, in addition to existing processor support. |
| Configurable Retry Behavior for Declined Network Token Transactions | Processor settings now include an option to control whether a transaction that fails with a network token is automatically retried using the card's primary account number. This is off by default for existing merchants. |
### **API Reference Guide Updates**
| Changes | Description |
| - | - |
| 3D Secure Pass Through Documentation | The API reference now documents 3D Secure pass through support for TSYS and Nuvei in addition to WorldPay, including correct guidance on cryptogram formatting per processor. |
| Subscription Start Date Clarification | The API reference now clarifies that the start date on subscription creation is evaluated using UTC time. |
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug Fixes and Stability Improvements | Various issues have been resolved to improve overall system stability and reliability. |
**March 16th, 2026**
v1.28.5
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Embedded Checkout Support | Checkout can now be embedded directly into merchant websites via iframe. This enhancement improves user experience and helps increase conversion by removing full-page redirects. |
| Merchant Invoice Reference Sent to Worldpay | Merchant Invoice Reference ID is now sent to Worldpay in the **Order ID** field. If not provided, the system defaults to using the Revolv3 Invoice ID. |
| Invoice Reference Mapping for EPX Transactions | Invoice and merchant reference IDs are now sent to EPX (`INVOICE_NBR` and `ORDER_NBR`), enabling easier transaction tracking and search by invoice number in EPX systems. |
### **Documentation Portal Updates**
| Changes | Description |
| - | - |
| Improved Developer Documentation | We have updated our developer guides with more detailed and comprehensive information to simplify integration and improve the overall developer experience. |
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug Fixes and Stability Improvements | Various minor issues have been resolved to improve overall system stability and reliability. |
**December 22nd, 2025**
v1.28.0
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Date Range Filter in Global Search | The Portal global search has been enhanced with a **date range filter**, allowing users to narrow search results by specific time periods. Preset options include **Today (default), Last 7 Days**, Last 30 Days, as well as a **Custom Range**. |
| Dynamic Transaction Descriptors for EPX | We have added support for **dynamic transaction descriptors** for the **EPX** processor. Merchants can now pass descriptor values per transaction via the API, providing greater flexibility and consistency with other supported processors. When enabled in the Portal, dynamic descriptors are automatically mapped to the appropriate EPX fields and applied across supported transaction types, including Sale, Authorization, and Capture. |
| \$0 Authorization (Account Verification) Support | We have added support for **\$0.00 authorization (account verification)** transactions (**Worldpay** and **EPX**), allowing merchants to validate customer account details without performing a financial charge. |
### **API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| 3D Secure Parameters Support in Payment API | We have extended the **Authorization** and **Sale** Payment API endpoints to support **3D Secure (3DS)** parameters. Merchants can now submit 3DS authentication data as part of payment requests. The list of endpoints: ▪ [Sale with Payment Method Details](https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-details) ▪ [Auth with Payment Method Details](https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-details) This enhancement enables seamless integration with external 3DS providers and supports compliant 3DS-enabled card payment flows. ⚠️ 3D Secure (3DS) parameters received via the API are now forwarded to the payment processor **only for Worldpay** transactions. |
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug fixes | We've resolved several bugs to improve the stability of the product. |
**November 5th, 2025**
v1.27.0
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Merchant Analytics Dashboard | A new **Analytics Dashboard** is now available in the Portal, providing merchants with key business insights and metrics. The dashboard displays various indicators for the **current month**, compared against the **previous period**, along with charts showing trends across current and historical data. |
### **API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| Processor Response Details in Payment API | Payment API responses now include two new parameters — `responseCode` and `responseMessage` — providing clear information from the payment processor about the latest invoice attempt status. The list of endpoints: ▪ [Sale with Payment Method Id](https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-id) ▪ [Sale with Payment Method Details](https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-details) ▪ [Auth with Payment Method Id](https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-id) ▪ [Auth with Payment Method Details](https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-details) ▪ [Capture](https://docs.revolv3.com/api-reference/payments/capture) ▪ [Create Subscription](https://docs.revolv3.com/api-reference/subscriptions/create-subscription) |
| Account Updater Details in Payment Responses | Payment API responses now include **Account Updater** information for supported processors (currently **Adyen** and **Worldpay**). Merchants can see when an account update occurred and get details of the updated card, including: ▪ **AccountUpdateDateTime** – the date and time when the update happened ▪ **AccountUpdaterMessage** – the message returned by the processor ▪ **binNumber**, **paymentLast4Digits**, and **paymentExpirationDate** – details of the new card, when available The list of endpoints: ▪ [Sale with Payment Method details](https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-details) ▪ [Sale with Payment Method Id](https://docs.revolv3.com/api-reference/payments/sale-with-payment-method-id) ▪ [Auth with Payment Method details](https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-details) ▪ [Auth with Payment Method Id](https://docs.revolv3.com/api-reference/payments/authorize-with-payment-method-id) ▪ [Capture](https://docs.revolv3.com/api-reference/payments/capture) ▪ [Refund Invoice](https://docs.revolv3.com/api-reference/invoices/refund-invoice) ▪ [Get Invoice](https://docs.revolv3.com/api-reference/invoices/get-invoices) ▪ [Get Invoices V1](https://docs.revolv3.com/api-reference/invoices/get-invoices-v1) |
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug fixes | We've resolved several bugs to improve the stability of the product. |
**October, 1th 2025**
v1.26.0
### **Technical Enhancements**
| Changes | Description |
| - | - |
| Bug fixes | We've resolved several bugs to improve the stability of the product. |
**September, 17th 2025**
v1.25.0
### **Core Functionality Updates**
| Changes | Description |
| - | - |
| Processing Method in Invoice Data Export | The **Invoice Data Export** report has been enhanced to include the **Processing Method** for each invoice. **Possible values**: ▪ **None** – for Capture transactions, refunds (ACH and credit card), and reversal authorizations. ▪ **ProcessorToken** – when a processor-specific token is used. ▪ **NetworkToken** – when a universal network token is used across processors. ▪ **Ach** – for transactions processed via ACH account number. ▪ **CreditCard** – for transactions processed with raw credit card data. |
**Aug, 28th 2025**
v1.24.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Trial Marking for Initial Recurring Transactions | We’ve added the ability for merchants to mark the **first recurring payment** as a **trial transaction**. **Key details**: ▪ A new portal setting lets merchants enable trial marking for supported processors. ▪ When enabled, the system automatically appends **“Trial”** to the transaction descriptor for the initial recurring payment. ▪ Works with both static and dynamic descriptors, while ensuring compliance with processor-specific descriptor length rules. ▪ Phase 1: available for **Worldpay** integration. This enhancement provides greater flexibility in handling recurring billing scenarios where the initial transaction should be clearly identified as a trial. |
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| Processor and MID Information in Payment Responses | We have enhanced payment API responses to include additional processor-related parameters: \* **paymentProcessor** – the name of the processor handling the transaction (e.g., WorldPay). \* **processorMerchantId** – the merchant account ID (MID) assigned by the processor (e.g., 10071676). These parameters are now available in responses for the following endpoints: \* Sale (with/without Payment Method details) \* Auth (with/without Payment Method details) \* Capture \* Create Subscription Merchants can now easily identify which processor and merchant processor account were used for each transaction, improving transparency and simplifying reconciliation across multiple processors. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability of the product. |
| Updated Inactivity Timeout | We have adjusted the portal’s user session timeout for increased security. Now, users will be automatically logged out after 15 minutes of inactivity (previously 60 minutes). |
**Aug 13th, 2025**
v1.23.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| **New Integration: BridgePay Now Available on the Portal** | We are pleased to announce the integration of **BridgePay** into our platform, providing merchants with a robust and versatile payment processing solution. **Key Features:** \* **Comprehensive Transaction Support:** Process a wide range of transactions, including authorizations, sales, refunds, and more. \* **Tokenization Capabilities:** Utilize both one-time and recurring tokenized transactions to enhance security and streamline payment processes. \* **Descriptor Flexibility:** Configure either static or dynamic descriptor to ensure clear transaction labeling on customer statements. \* **Dynamic Routing Participation:** Leverage BridgePay in dynamic routing setups to optimize approval rates and enhance transaction success. |
| **Subscription Support for Nuvei** | We have added support for **recurring and recycling billing** through Nuvei. Merchants can now create and manage subscription-based transactions using Nuvei as their payment processor. |
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| **New API Endpoint: Configure BridgePay for Merchants** | We have introduced a new API endpoint that enables merchants to configure **BridgePay** as a payment processor directly through the API. This addition streamlines the setup process, allowing for efficient integration and management of BridgePay within merchant accounts. |
| **Currency Support in Subscription Transactions** | We have extended subscription transactions to include a **currency parameter**. The system now: \* [Sends the specified currency to the processor](/api-reference/subscriptions/create-subscription) if supported. \* Returns a clear error message if the currency is not supported by the configured processor. \* Stores the currency in subscription records, invoices, and processor transactions. |
| **Flexible Billing Frequency for Subscriptions** | We’ve enhanced subscription settings by replacing the fixed `billingFrequencyType` values with a flexible interval-based configuration. Merchants can now [define billing cycles](/api-reference/subscriptions/create-subscription) using a combination of: \* **intervalCount** (numeric value) \* **intervalType** (days, weeks, months, or years) This allows for fully customizable recurring billing schedules — for example, every 28 days — and updates both the trial duration options and recurring logic accordingly. Existing subscriptions have been migrated to support the new format. |
| **Enhanced Bulk Invoice Retrieval** | We have introduced an improved [**Get Invoices**](/api-reference/invoices/get-invoices-v1) endpoint that allows merchants to retrieve multiple invoices in a single request (up to 100), with expanded filtering, sorting, and data details. **Key enhancements include:** \* Support for bulk invoice retrieval with advanced filters (by billing date, last update date, etc.) \* Additional sorting options and improved parameter handling \* Detailed payment information in the response, including payment type, token details, descriptor, and currency \* Ability to request raw processor response data for deeper insights The existing [**Get Invoices**](/api-reference/invoices/get-invoices) endpoint remains available, but the new version offers significantly more flexibility and richer data. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability of the product. |
| Updated Inactivity Timeout | We have adjusted the portal’s user session timeout for increased security. Now, users will be automatically logged out after 15 minutes of inactivity (previously 60 minutes). |
**Jul 18th, 2025**
v1.22.1
**Documentation Portal Updates**
| Changes | Description |
| :- | :- |
| New Documentation Added: ACH Direct Debit | A new article on ACH Direct Debit is now available in the Guides section. Merchants can explore how to use this payment method, transaction flow, and best practices. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Jul 3rd, 2025**
v1.22.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Merchant-Specific BIN Blocking Rules | Merchants can now configure BIN-based block rules tailored to each account. If a transaction includes a blocked BIN, our system returns a clear, branded decline response indicating it was blocked due to BIN rules. This enhances control and security for merchants. |
| Manage Email Notification Preferences | We’ve added a new “Notification Settings” section to the Portal, now available under the Settings menu. This feature gives users greater control over the types of email notifications they receive. **Key Capabilities:** \* Subscribe or unsubscribe from specific notification topics. \* Choose which team members should receive each type of notification. \* Toggle individual topics on or off based on your preferences. Changes made in the Portal take effect immediately, ensuring your communication preferences are always up to date. |
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| New API Endpoint: Configure JPMorgan (Paymentech) for Merchants | We have introduced a new API endpoint that enables merchants to configure JPMorgan (Paymentech) as a payment processor directly through the API. This addition streamlines the setup process, allowing for efficient integration and management of JPMorgan (Paymentech) within merchant accounts. |
| Combined Cardholder Name Field | To improve developer experience, our API now supports a combined `billingFullName` field alongside the existing `billingFirstName` and `billingLastName` parameters. Merchants can now choose one of two mutually exclusive formats: \* First/Last Name – using `billingFirstName` + `billingLastName` (existing method) \* Full Name – using `billingFullName` (new alternative) Exactly one naming format must be provided per request. This update simplifies integration for merchants who collect name data as a single string. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**May 19th, 2025**
v1.21.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| New Integration: PaymentLync Now Available on the Portal | We are pleased to announce the integration of PaymentLync into our platform, providing merchants with a robust and versatile payment processing solution. **Key Features:** \* Comprehensive Transaction Support: Process a wide range of transactions, including authorizations, sales, refunds, and more. \* Tokenization Capabilities: Utilize both one-time and recurring tokenized transactions to enhance security and streamline payment processes. \* Descriptor Flexibility: Configure either static or dynamic descriptor to ensure clear transaction labeling on customer statements. \* Dynamic Routing Participation: Leverage PaymentLync in dynamic routing setups to optimize approval rates and enhance transaction success. |
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| New API Endpoint: Configure PaymentLync for Merchants | We have introduced a new API endpoint that enables merchants to configure PaymentLync as a payment processor directly through the API. This addition streamlines the setup process, allowing for efficient integration and management of PaymentLync within merchant accounts. |
# Technical Enhancements
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**May 7th, 2025**
v1.20.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Enhanced TSYS Integration | We have enhanced our integration with TSYS to improve payment approval rates. By transmitting additional transaction details during payment processing, we aim to provide more comprehensive information to the processor, facilitating better authorization decisions. No action is required from merchants; these enhancements have been seamlessly applied to the system. |
| Support for Network Token Transactions with TSYS and Nuvei | We have expanded our payment processing capabilities to support transactions using network tokens with both TSYS and Nuvei. This enhancement enables merchants to process payments using tokens issued by card networks, offering increased security and potentially higher approval rates. |
| IP Whitelisting for Enhanced Security | Merchants now have the option to enhance their account security by whitelisting specific IP addresses. This feature allows merchants to restrict access to their accounts, ensuring that only requests originating from approved IP addresses are permitted. To set up IP whitelisting, merchants should contact our support team with the IP addresses they wish to authorize. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Mar 5th, 2025**
v1.18.1
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| New Option to Request Personal Data Clearing | We have introduced a new feature on the portal that allows merchants to initiate requests for clearing personal data. A dedicated "Clear Personal Data" page is now available (Operations). Users can now navigate to the form via a dedicated link on the portal to specify the details of the data they wish to delete. Once submitted, these requests will be processed accordingly. |
| Access to Customer Support Hub | We have introduced a new feature on our portal—a dedicated icon that provides merchants with direct access to the Customer Support Hub. Through this hub, users can submit various requests, provide feedback, and access additional support resources. |
**Documentation Portal Updates**
| Changes | Description |
| :- | :- |
| API Versioning Policy | We have introduced a API Versioning Policy to ensure a seamless experience for developers integrating with our API. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Feb 25th, 2025**
v1.18.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Expanding RBAC for Secure and Scalable Access Management | As part of our continuous security enhancements and alignment with PCI DSS 4.0, we are expanding the use of Role-Based Access Control (RBAC) across more infrastructure resources. |
| Enhanced Routing Rules for Recurring Transactions | We have expanded our transaction routing capabilities, allowing more flexibility in processing recurring payments. Now, the initial recurring transaction can be routed to one processor, while subsequent transactions can be directed to another, based on configurable routing rules. |
| Updated Integration with TSYS | We have refined our integration with TSYS to align with their latest recommendations and best practices. These improvements enhance stability, compatibility, and overall processing efficiency. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Feb 4th, 2025**
v1.17.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Default Order Processing Channel Selection for Merchants | Merchants can now select an Order Processing Channel when creating or editing their profiles. This channel represents the sales channel through which the shopper provides their card details and will be used as the default value sent to the processor unless explicitly specified in the payment request. Available options: E-Commerce, MOTO (Mail Order / Telephone Order). Currently, this feature is supported only for Worldpay, while for other processors, the E-Commerce value will always be used. For all merchants created before this release, the default value has been set to E-Commerce. |
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| Order Processing Channel | The `OrderProcessingChannel` parameter has been added to the structure of Authorization and Sale requests (Authorization and Capture in a single request). This parameter defines the sales channel through which the shopper provides their card details and allows merchants to specify it when initiating a transaction. Available options: ecommerce, moto. If not explicitly provided in the request, the default value set at the merchant level on the Revolv3 Portal will be used. Currently, this parameter is sent only to Worldpay, while for other processors, the default value remains E-Commerce. Updated end points: Authorize With Payment Method Details, Authorize With Payment Method Id, Sale With Payment Method Details, Sale With Payment Method Id. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Jan 27th, 2025**
v1.16.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Direct PAN Usage for Initial Transactions with Worldpay | Previously, during payment processing via Worldpay, we first requested a token and then executed the payment using the token. With this update, the Primary Account Number (PAN) is now directly utilized for the first transaction, streamlining the process and reducing latency for initial payments. |
| Configurable Retry Timing for Backup Processor Payments | We have introduced a feature that allows configuring the delay before the system retries a payment with the backup processor if the initial attempt with the primary processor fails. By default, the retry is immediate (0 minutes), but you can now set a delay of up to 60 minutes. This provides greater flexibility in managing transaction retries and optimizing payment workflows. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Nov 19th, 2024**
v1.15.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Introduction of Stateful Webhooks with Enhanced Features | We have transitioned from a stateless to a stateful webhook mechanism to align with industry best practices. This new implementation improves reliability, transparency, and efficiency when notifying external systems about events. **Key Features:** \* Stateful Webhooks: Each webhook now includes the state of the entity at the moment of generation, ensuring accurate context for external systems. \* Retry Mechanism: Supports progressive retries in case of transient failures, enhancing delivery reliability. \* Preserved Order: Webhooks are processed sequentially for each merchant, preventing disorder and ensuring consistent event streams. Processing halts and resumes as issues are resolved. \* Custom Configuration: Merchants can now define specific webhook types they wish to receive, reducing system load and unnecessary notifications. This update ensures a robust, scalable, and configurable webhook experience for merchants and their integrated systems. |
| Optimized EPX Transaction Processing | Transactions with EPX now process faster by using the PAN for the first payment when no token is available. Token retrieval happens in parallel, ensuring seamless processing for subsequent transactions. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Oct 7th, 2024**
v1.14.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Raw Processor Response | Optional parameter to return the raw processor response on a transaction - useful to find processor error codes. Data is stored after Nov 18th, 2024 |
| WorldPay Dynamic Descriptor | Allow the use of Dynamic Descriptor for WorldPay |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Aug 28th, 2024**
v1.13.1
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Invoice Export | A new UI feature that will export Invoices to a .csv file up to 15Mb in size based on dates |
| InvoiceId Lookup | A Invoice ID input box is added to the UI on the Invoices page to look up specific invoices |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Aug 12th, 2024**
v1.13.0
**Core Functionality Updates**
| Changes | Description |
| :- | :- |
| Secure Data Transfer for Payment Service Migration | A new mechanism has been implemented to allow merchants to securely retrieve data from our system. This secure data transfer is particularly beneficial when merchants transition to a different payment service or processor, ensuring that sensitive information is protected throughout the process. |
| Tokenization Retry | This feature introduces the ability to enable tokenization retry for merchants. Tokenization retry can be configured to automatically attempt tokenization again after a failure, ensuring higher success rates in capturing payment methods. Additionally, tokenization retry is designed to work seamlessly with multiple payment methods, which were introduced in the 1.13.0 release. |
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Jul 2nd, 2024**
v1.12.7
**Technical Enhancements**
| Changes | Description |
| :- | :- |
| International payments | The architecture has been prepared to support international payments, ensuring a seamless and reliable transaction experience for global users. |
| Framework update | The .NET framework has been updated to the newest version. This upgrade brings enhanced performance, improved security, and better support for modern development practices. |
| Bug fixes | We've resolved several bugs to improve the stability and performance of the product. |
**Jun 3rd, 2024**
v1.12.5
# Core Functionality Updates
| Changes | Description |
| :- | :- |
| Checkout feature | The Checkout feature provides the ability to use our page with a form to collect payments. Merchants can embed Checkout directly into their websites or redirect customers to a Revolv3 hosted checkout page. This feature ensures a seamless payment experience by securely handling customer payment information, supporting various payment methods, and complying with PCI DSS standards. |
**Documentation Portal Updates**
| Changes | Description |
| :- | :- |
| The new guide for the checkout are available | To assist merchants with the integration process, we have introduced the Checkout Guide. This comprehensive guide provides step-by-step instructions on how to integrate with either the hosted checkout page or the embedded payment page. It covers all aspects of the integration, from initial setup and configuration to customizing the payment form and handling responses. |
**May 13th, 2024**
v1.12.3
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| The BIN number is returned in endpoint responses | The information about the credit card BIN number is now returned in the responses of the following endpoints: Invoices and PaymentMethod |
**Apr 29th, 2024**
v1.12.0
**API Reference Guide Updates**
| Changes | Description |
| :- | :- |
| Update Payment Method Billing Address endpoint accepts Billing Address object | It is now allowed to Update the billing address associated with an existing payment method by supplying a billing address object. Previously, it was only possible to supply an existing billing address ID. |
| Create Subscription response enhancements | The following enhancements were made to the Create Subscription endpoint response to provide more information and make the result of the call more transparent: A “message” parameter was introduced to return information about the first payment transaction result. The subscription object will always be returned in the response (previously, it was not returned in the case of the first payment transaction failure).Account Updater Details in Payment Responses |
# Changelog
Source: https://docs.revolv3.com/changelog/index
# API Reference
Source: https://docs.revolv3.com/docs/api-reference/api-reference
High-level overview of API endpoint groups. Understand what each group does and when to use it, then dive into the OpenAPI spec for detailed documentation.
> API Reference — quick guide to endpoint groups\
> This page gives you a high-level overview. For complete request/response schemas, parameters, and examples, see the [OpenAPI/Swagger spec](/api-reference/).
## Quick Start
**Base URL**: Use the environment-specific base URL shown in the OpenAPI/Swagger spec:
* **Sandbox**: `api-sandbox.revolv3.com` (for testing)
* **Production**: `api.revolv3.com` (for live transactions)
**Authentication**: Include your static API token in the `x-revolv3-token` header on every request.
**Content Type**: `application/json` for all requests.
**Errors**: Check HTTP status codes. Error responses include an internal error code and a human-readable message to help you debug.
## Endpoint Groups Overview
Here's what each group of endpoints does and when you'd use them:
### Authentication & Keys
**What it's for**: Managing API keys and authentication tokens for your account.
**When to use**:
* Getting your API keys for authentication
* Rotating or managing API credentials
* Setting up authentication for your integration
**Examples**:
* `POST /auth/token` — Generate authentication tokens
* `GET /auth/keys` — Retrieve your API keys
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**: [Authentication Guide](/docs/authentication-security/merchant-access-token)
***
### Customers
**What it's for**: Managing customer records in Revolv3. Customers are optional but useful for tracking all of a customer's payments, subscriptions, and payment methods together.
**When to use**:
* Creating customer profiles before subscriptions
* Linking multiple payments to the same customer
* Managing customer information separately from payments
* Building a customer management system
**Examples**:
* `POST /customers` — Create a new customer
* `GET /customers/{id}` — Get customer details and their payment history
* `PATCH /customers/{id}` — Update customer information
**Note**: Customers are optional—you can process payments without creating customer records. But they're helpful for subscriptions and tracking.
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**: [Customer Guide](/docs/core-concepts/customer/customer)
***
### Payment Methods
**What it's for**: Storing customer payment credentials securely (credit cards, bank accounts) so you can charge them again without asking for their details every time. This uses tokenization for security.
**When to use**:
* Saving a customer's card for faster checkout next time
* Setting up subscriptions (need a stored payment method)
* One-click purchases for returning customers
* Avoiding PCI compliance requirements (Revolv3 handles security)
**Examples**:
* `POST /payment-methods` — Store a payment method and get a token
* `GET /payment-methods/{id}` — Retrieve stored payment method details
* `POST /payment-methods/{id}/verify` — Verify a payment method before using it
**Error codes**: [API Response Codes](/docs/error-codes/error-responses), [Decline Codes](/docs/error-codes/decline-codes)
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**: [Payment Methods Guide](/docs/core-concepts/paymentmethod/paymentmethod-guide)
***
### Payments
**What it's for**: Processing one-time payments, authorizing funds (without charging), and capturing authorized payments. This is your main endpoint for charging customers.
**When to use**:
* E-commerce checkout (one-time purchases)
* Authorizing funds before you know the final amount (hotels, restaurants)
* Capturing previously authorized payments
* Immediate charges where you know the exact amount
**Examples**:
* `POST /payments/sale` — Charge a customer immediately (most common)
* `POST /payments/authorization` — Reserve funds without charging (for hotels, pre-orders)
* `POST /payments/{id}/capture` — Actually charge previously authorized funds
* `POST /payments/{id}/void` — Cancel an authorization
**Error codes**: [API Response Codes](/docs/error-codes/error-responses), [Decline Codes](/docs/error-codes/decline-codes)
**Related webhooks**: [Webhooks Guide](/docs/webhook-events/webhook) — payment and invoice lifecycle events
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**:
* [Make a Payment](/docs/getting-started/make-a-payment)
* [Authorizations & Captures](/docs/integration-flows/authorizations-captures)
***
### Invoices
**What it's for**: Managing invoices, which are billing documents that represent what you're charging for. Invoices drive payment attempts and track the status of charges.
**When to use**:
* Creating invoices before processing payments
* Checking payment status and invoice details
* Tracking what's been paid and what's pending
* Managing receivables and billing records
**Examples**:
* `POST /invoices` — Create an invoice
* `GET /invoices` — List invoices (with filters)
* `GET /invoices/{id}` — Get invoice details and payment status
* `GET /invoices/{id}/attempts` — See all payment attempts for an invoice
**Note**: When you process a payment, Revolv3 automatically creates an invoice. You can also create invoices separately if needed.
**Error codes**: [API Response Codes](/docs/error-codes/error-responses), [Decline Codes](/docs/error-codes/decline-codes)
**Related webhooks**: [Webhooks Guide](/docs/webhook-events/webhook) — e.g. InvoicePaid, InvoiceFailed
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**:
* [Invoice Status](/docs/core-concepts/invoice/invoice-status)
* [Get Invoices API](/docs/core-concepts/invoice/get-invoices-api)
***
### Refunds
**What it's for**: Issuing refunds to customers—returning money for previous payments. Supports both full and partial refunds.
**When to use**:
* Customer returns a product
* Service wasn't delivered as promised
* Customer cancels and is eligible for refund
* Partial refunds for damaged items or partial service
* Handling customer disputes
**Examples**:
* `POST /invoices/{id}/refund` — Issue a refund (full or partial)
* `GET /refunds/{id}` — Get refund status and details
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Related webhooks**: [Webhooks Guide](/docs/webhook-events/webhook) — e.g. RefundProcessed
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**: [Processing Refunds](/docs/integration-flows/refunds)
***
### Subscriptions
**What it's for**: Setting up recurring billing—automatically charging customers at regular intervals (weekly, monthly, yearly, etc.). Perfect for SaaS products, memberships, and subscription services.
**When to use**:
* Monthly software subscriptions
* Membership services (gyms, clubs, streaming)
* Recurring service billing
* Installment plans ("buy now, pay later")
**Examples**:
* `POST /subscriptions` — Create a subscription with billing plan
* `GET /subscriptions/{id}` — Get subscription details and next billing date
* `PATCH /subscriptions/{id}` — Update subscription (change plan, billing frequency, etc.)
* `POST /subscriptions/{id}/cancel` — Cancel a subscription
**Error codes**: [API Response Codes](/docs/error-codes/error-responses), [Decline Codes](/docs/error-codes/decline-codes)
**Related webhooks**: [Webhooks Guide](/docs/webhook-events/webhook) — subscription and invoice lifecycle events
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**:
* [Create a Subscription](/docs/core-concepts/subscription/create-subscription)
* [Canceling Subscriptions](/docs/core-concepts/subscription/canceling-a-subscription)
***
### Checkout (Hosted / Embedded)
**What it's for**: Creating hosted payment pages or embedded checkout forms. Revolv3 handles the payment form UI and security, so you don't have to build your own.
**When to use**:
* You want Revolv3 to handle the payment form (less development work)
* You need a PCI-compliant checkout without handling card data yourself
* Quick integration without building custom payment forms
* Embedded checkout in your application
**Examples**:
* `POST /checkout/sessions` — Create a checkout session
* `GET /checkout/sessions/{id}` — Get checkout session status
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**:
* [Checkout Guide](/docs/checkout/checkout)
* [Hosted Page](/docs/checkout/hosted-page)
* [Embedded Checkout](/docs/checkout/embedded)
***
### Processors & Merchant Configuration
Processor credentials and merchant configuration are typically set up for you when your account is created. These settings aren't something you manage through the API day to day.
To update processors, merchant settings, or related configuration, contact Revolv3.
**Learn more**: [Merchant Settings](/docs/core-concepts/merchants/merchant-setting)
***
### Reports & Reconciliation
**What it's for**: Generating reports and reconciliation files to match your Revolv3 transactions with your accounting records and bank statements.
**When to use**:
* Daily/weekly/monthly reconciliation
* Exporting transaction data for accounting
* Generating settlement reports
* Matching payments with bank deposits
* Financial reporting and analysis
**Examples**:
* `POST /reports` — Generate a report (transactions, settlements, etc.)
* `GET /reports/{id}` — Get report status and download link
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Endpoints**: [OpenAPI spec](/api-reference/)
**Learn more**: [Invoice Export](/docs/core-concepts/invoice/invoice-export)
***
### Files & Attachments
**What it's for**: Uploading and managing supporting documents (receipts, invoices, contracts) that are associated with payments or customers.
**When to use**:
* Attaching receipts to transactions
* Storing customer documents
* Uploading proof of delivery or service
* Managing supporting documentation for disputes
**Examples**:
* `POST /files` — Upload a file
* `GET /files/{id}` — Download a file
**Note**: This is optional—most integrations don't need file uploads unless you have specific requirements.
**Error codes**: [API Response Codes](/docs/error-codes/error-responses)
**Endpoints**: [OpenAPI spec](/api-reference/)
***
## Common Integration Patterns
### E-Commerce Checkout Flow
1. **Payment Methods** → Store customer's card (optional, for faster checkout)
2. **Payments** → Charge the customer (`POST /payments/sale`)
3. **Invoices** → Check payment status (`GET /invoices/{id}`)
4. **Refunds** → Issue refund if customer returns item (`POST /invoices/{id}/refund`)
### Subscription Service Flow
1. **Customers** → Create customer record (optional)
2. **Payment Methods** → Store payment method for recurring charges
3. **Subscriptions** → Create subscription with billing plan
4. **Invoices** → Monitor subscription payments via webhooks
5. **Subscriptions** → Cancel if needed (`POST /subscriptions/{id}/cancel`)
### Hotel/Restaurant Flow (Authorization & Capture)
1. **Payments** → Authorize funds at check-in (`POST /payments/authorization`)
2. **Payments** → Capture actual amount at checkout (`POST /payments/{id}/capture`)
3. **Refunds** → Refund if customer cancels before capture
## Where to Go Next
* [**OpenAPI/Swagger Spec**](/api-reference/) — Complete API documentation with request/response schemas, parameters, and examples
* [**Error Codes & Troubleshooting**](/docs/error-codes/error-responses) — Understand error responses and how to handle them
* [**Authentication**](/docs/authentication-security/merchant-access-token) — Learn about API tokens, required headers, and security best practices
* [**Getting Started**](/docs/getting-started/getting-started) — Step-by-step guide to your first integration
* [**Core Concepts**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Deep dive into payment methods, invoices, subscriptions, and more
***
# Revolv3 Appendix
Source: https://docs.revolv3.com/docs/appendix/appendix-revolv3
Concise reference: contacts, glossary, common resources, and quick operational notes.
> Revolv3 Appendix — quick operational reference and glossary\
> A compact page for on-call engineers and integrators. Use linked full docs for deep dives.
***
> Quick reference
>
> * **API reference:** OpenAPI/Swagger spec for endpoints and payloads.
> * **Changelog:** Release notes and breaking changes.
> * **Support:** Log into the Revolv3 portal (production or sandbox) and use the **help icon** to submit a ticket. Include timestamps, request IDs, and sample payloads.
***
### Glossary
#### Quick Reference (Short)
* **Merchant** — account that owns configuration and processor credentials.
* **Customer** — optional stored customer record; nullable on API calls.
* **PaymentMethod** — vaulted card/ACH/token used for charges.
* **Invoice** — billing document that drives payment attempts.
* **Attempt** — single processing attempt for an invoice or payment action.
* **Subscription** — recurring billing profile that generates invoices.
* **Dynamic descriptor** — transaction descriptor shown on customer statements.
* **Network tokenization** — network token used instead of PAN.
#### Payment Industry Terms Explained
**Authorization** A two-step payment process where you first "authorize" (reserve) funds without actually charging the customer. Think of it like putting a hotel room on hold—the money is reserved, but not taken yet. You then "capture" the funds later when you're ready to charge. This is useful for scenarios like hotel bookings (authorize at check-in, capture at checkout) or pre-orders (authorize when ordered, capture when shipped).
**Capture** The second step in the authorization process. After you've authorized funds, you "capture" them to actually charge the customer. Authorizations typically expire after 7 days, so you need to capture within that window. If you don't capture, the hold is released and the customer's money becomes available again.
**ACH (Automated Clearing House)** A system for transferring money directly between bank accounts. Unlike credit cards (which are instant), ACH transfers are batch-processed and can take 1-5 business days to complete. ACH is commonly used for recurring bills, subscriptions, or large transactions where the delay is acceptable. It's also typically cheaper than credit card processing fees.
**Network Transaction ID** A unique identifier assigned by the card network (Visa, Mastercard, American Express, etc.) for each transaction. This is different from Revolv3's invoice ID—it's the network's own tracking number. You'll need this for disputes, chargebacks, reconciliation with bank statements, and customer support. Always store this ID when processing payments.
**Tokenization** The process of replacing sensitive payment information (like a full credit card number) with a secure token (like a `paymentMethodId`). Instead of storing card numbers in your database (which is a security risk), you store the token and use it for future charges. This is much more secure and helps you comply with payment industry security standards (PCI DSS). Revolv3 handles tokenization automatically—when you process a payment, you get back a `paymentMethodId` you can use instead of the full card details.
**Payment Method** A stored payment credential (credit card, debit card, bank account, etc.) that can be reused for multiple transactions. In Revolv3, when you process a payment, you can optionally save the payment method and get back a `paymentMethodId`. Later, you can charge that customer again by just referencing the ID instead of asking for their card details again. This improves security and customer experience.
**Invoice vs Payment** These terms are often used interchangeably, but in Revolv3 they have specific meanings:
* **Invoice**: A billing document that represents what you're charging the customer for. It has an amount, a due date, and can have multiple payment attempts.
* **Payment**: The actual act of moving money. An invoice can have multiple payment attempts (if the first one fails, you might try again).
Think of an invoice like a bill you send, and a payment as the actual money transfer.
**Processor (Payment Processor)** A company that handles the technical side of moving money between banks. Examples include WorldPay, Adyen, and BridgePay. When you send a payment request to Revolv3, we route it to one of these processors, which then communicates with the card networks and banks. You typically don't interact with processors directly—Revolv3 handles that for you.
**Settlement** The process of actually moving money from the customer's account to your merchant account. When a payment is "authorized," the money is held but not moved yet. "Settlement" is when the funds are actually transferred. For credit cards, settlement typically happens 1-3 business days after authorization. For ACH, it can take 1-5 business days.
**Chargeback** When a customer disputes a charge with their bank (claiming fraud, unauthorized charge, or that they never received the product). The bank takes the money back from you and you have a chance to provide evidence to fight it. Chargebacks are expensive and time-consuming, so it's important to have good records (like `networkTransactionId`) and clear customer communication to prevent them.
**3DS (3D Secure)** An extra security layer for online payments. When a customer uses a card that requires 3DS, they're redirected to their bank's website to enter a password or confirm via SMS. This adds friction to checkout but reduces fraud and chargebacks. Some cards require it, some don't—Revolv3 handles this automatically when needed.
**Account Updater** A service that automatically updates expired or replaced credit cards in your stored payment methods. For example, if a customer's card expires or they get a new card number, Account Updater can update your records so recurring payments don't fail. Not all processors support this, but when available, Revolv3 uses it automatically to keep your payment methods current.
**Dynamic Descriptor** The text that appears on a customer's credit card or bank statement describing the charge. Instead of just showing "REVOLV3" or your processor's name, you can customize it to show something like "ACME STORE - ORDER #12345" so customers can easily identify the charge. This reduces confusion and support calls.
***
### Common integration notes
* Customer is intentionally nullable — omit it for anonymous or externally-managed customer flows.
* Merchant settings provide invoice-level fallbacks; set only the values you rely on.
* Use payment method verification (card/ACH) for reliable recurring billing.
# Authentication
Source: https://docs.revolv3.com/docs/authentication-security/merchant-access-token
Learn how to obtain and use your static token (`x-revolv3-token`) to authenticate with the Revolv3 API, including environment setup, required headers, examples, and legacy guidance.
## Authentication Overview
Revolv3 authenticates API requests using the `x-revolv3-token` header. The value sent in that header is your **Developer Static Token**.
For current integrations, this is the recommended authentication method.
Some existing merchants still use legacy authentication flows. Those flows are not recommended for new implementations. If you maintain a legacy setup and need details or migration guidance, contact Revolv3 support through the portal **help icon**.
## Where to Find Your Static Token
Create and manage static tokens in the Revolv3 portal under:
**Settings -> Integration Profile -> Developer Static Tokens**
Use the portal that matches your environment:
| Environment | Portal | API Base URL |
| - | - | - |
| Sandbox | `portal-sandbox.revolv3.com` | `https://api-sandbox.revolv3.com` |
| Production | `portal.revolv3.com` | `https://api.revolv3.com` |
> Sandbox and production credentials are separate. Do not use a sandbox token in production or a production token in sandbox.
### Get Your Token from the Portal
1. Sign in to the correct portal
2. Go to **Settings -> Integration Profile**
3. Find **Developer Static Tokens**
4. Create a token or copy an existing token
5. Store it securely

If you do not have access or cannot find the token, log into the portal and use the **help icon** to contact Revolv3 support.
## Required Headers
Include these headers on authenticated API requests:
| Header | Value | Notes |
| - | - | - |
| `x-revolv3-token` | Your static token | Required. Primary authentication credential. |
| `Content-Type` | `application/json` | Required for requests with JSON bodies. |
| `Accept` | `application/json` | Recommended so the API returns JSON responses. |
Headers such as `Host` and `Content-Length` are normally set automatically by your HTTP client.
## Example Request
Replace `YOUR_SANDBOX_STATIC_TOKEN` with your actual token. When moving to production, switch both the token and the API host.
```bash theme={null}
curl --location 'https://api-sandbox.revolv3.com/api/payments/sale' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-revolv3-token: YOUR_SANDBOX_STATIC_TOKEN' \
--data '{
"Invoice": {
"Amount": { "Value": 10.00 }
},
"PaymentMethod": {
"CreditCard": {
"PaymentAccountNumber": "4111111111111111",
"ExpirationDate": "1230",
"SecurityCode": "123"
}
}
}'
```
## Postman Example
In Postman, add the token in the **Headers** tab:

1. Add `x-revolv3-token` with your static token as the value
2. Add `Content-Type: application/json`
3. Optionally add `Accept: application/json`
## Legacy Authentication
Some older integrations use a legacy bearer-token flow instead of static tokens.
* This flow is deprecated
* New integrations should not use it
* Existing legacy integrations should contact Revolv3 support for details or migration guidance
## Security Best Practices
* Store tokens in environment variables or a secrets manager
* Never embed tokens in frontend or mobile code
* Never commit tokens to source control
* Never log full token values
* Keep separate sandbox and production credentials
* Rotate tokens using a staged deployment process
For broader credential-handling guidance, see [Security Best Practices](/docs/authentication-security/security-best-practices).
## Common Authentication Errors
### 401 Unauthorized
Common causes:
* Missing `x-revolv3-token`
* Invalid token value
* Sandbox token used against production, or vice versa
### "Attempted to perform an unauthorized operation"
This usually means the credential was accepted, but it does not have permission for the requested operation.
### 415 Unsupported Media Type
This usually means `Content-Type: application/json` is missing or incorrect on a JSON request.
When contacting support, include:
* request timestamp
* target environment
* request path
* server-side request headers
* redacted request body
## Next Steps
* [**Getting Started with Revolv3**](/docs/getting-started/getting-started) -> Start your first integration flow
* [**Make a Payment**](/docs/getting-started/make-a-payment) -> Use your token in a real API request
* [**Security Best Practices**](/docs/authentication-security/security-best-practices) -> Protect credentials in production
***
# Security Best Practices
Source: https://docs.revolv3.com/docs/authentication-security/security-best-practices
Essential security guidance for API integrations. Learn how to safely handle API tokens, protect sensitive data, and avoid common security pitfalls.
## Why Security Matters
When integrating with payment APIs, security isn't optional—it's critical. A compromised API token can give attackers full access to your account, allowing them to process payments, access customer data, and cause significant financial damage.
This guide covers essential security practices for server-to-server integrations with Revolv3. Follow these recommendations to keep your integration secure.
## Critical Rule: Never Expose Your Token
**`Never expose your x-revolv3-token (or any API key) in:`**
* Browser/client-side JavaScript
* Mobile app code (can be extracted from app bundles)
* URLs or query parameters (can be logged, cached, or leaked via referer headers)
* Logs, error messages, or debugging output
* Public repositories or version control
* Third-party analytics or monitoring tools
**Why this matters:**
* Client-side code can be inspected by anyone
* Tokens in URLs get logged by servers, proxies, and browsers
* Exposed tokens let attackers act as your server with full account access
* Once exposed, tokens can be used until you rotate them
## The Correct Pattern: Server-Side Integration
Always make API calls from your backend server, never from the browser or mobile app directly.
**How it works:**
1. **Store secrets server-side**: Keep your API token in environment variables or a secrets manager
2. **Make API calls from your backend**: Your server makes requests to Revolv3
3. **Return only needed data**: Send back to clients only the information they need (never the token)
**Example flow:**
```
Browser → Your Backend (with token) → Revolv3 API → Your Backend → Browser
```
The token never leaves your server.
## Secure Token Storage
### Use a Secrets Manager
Store your API tokens in a managed secrets store:
* **AWS**: Secrets Manager or Parameter Store
* **Azure**: Key Vault
* **Google Cloud**: Secret Manager
* **HashiCorp**: Vault
* **Other**: Any secure secrets management solution
### Environment Variables (Development Only)
For local development, you can use environment variables, but:
* Use them only for development
* Never commit `.env` files to version control
* Add `.env` to `.gitignore`
* Use a secrets manager for production
### What NOT to Do
* Hardcode tokens in source code
* Store tokens in configuration files that get committed
* Put tokens in database fields that aren't encrypted
* Share tokens via email, Slack, or other unsecured channels
## Secure Transport
### Always Use HTTPS
* **Always use HTTPS** (TLS 1.2 or higher) for all API requests
* **Enforce HSTS** (HTTP Strict Transport Security) on your servers
* **Never use HTTP** for any requests containing tokens or sensitive data
### Secure Headers
* Use the `x-revolv3-token` header (never put tokens in URLs)
* Require strong CORS policies if you have proxy endpoints
* Validate and sanitize all input before sending to Revolv3
## Logging and Monitoring
### What to Log
**Safe to log:**
* Request timestamps
* Endpoint names
* Response status codes
* Invoice IDs, customer IDs (non-sensitive identifiers)
* Last 4 characters of tokens (for identification): `tok_****1234`
**Never log:**
* Full API tokens
* Credit card numbers
* CVV codes
* Bank account numbers
* Full customer PII (personally identifiable information)
### Masking Sensitive Data
When you must log sensitive information for debugging:
* Show only the last 4 characters: `****1234`
* Hash tokens: `sha256(token)`
* Redact PII: `John D***` instead of `John Doe`
### Monitoring and Alerts
Set up monitoring for:
* **Unusual activity**: Requests from unexpected IP addresses
* **High volume**: Sudden spikes in API calls
* **Failed authentications**: Multiple 401 errors
* **Key rotation events**: When tokens are created, rotated, or revoked
Alert on suspicious patterns and enforce rate limits per token.
## Webhook Security
If you're receiving webhooks from Revolv3:
### Validate Webhook Signatures
* Always validate webhook signatures using the shared webhook secret
* Reject events that fail signature verification
* Check timestamp tolerance (reject events that are too old)
### Prevent Replay Attacks
* Use idempotency keys to deduplicate events
* Track event IDs to prevent processing the same event twice
* Implement timestamp validation (reject events outside a reasonable time window)
## Key Rotation
### When to Rotate
Rotate your API tokens:
* **Periodically**: Every 90-180 days as a best practice
* **After exposure**: Immediately if you suspect a token was compromised
* **After employee changes**: When someone with token access leaves
* **After security incidents**: Following any security breach
### How to Rotate Safely
1. **Create a new token** in the Revolv3 portal
2. **Update your secrets manager** with the new token
3. **Deploy to staging/sandbox** and test thoroughly
4. **Deploy to production** during low-traffic periods
5. **Monitor for errors** after deployment
6. **Revoke the old token** once you've confirmed the new one works
> **Tip**: Keep the old token active for 24-48 hours after rotation in case you need to roll back.
## Troubleshooting Security Issues
### If Your Token is Compromised
1. **Rotate immediately**: Create a new token and revoke the old one
2. **Search logs**: Check for unauthorized usage of the compromised token
3. **Review access**: Check what operations were performed with the token
4. **Notify stakeholders**: Inform your team and Revolv3 support
5. **Rotate downstream tokens**: If you have other tokens that might be affected, rotate those too
### If Webhooks Fail Signature Verification
1. **Check clock drift**: Ensure your server's clock is synchronized (use NTP)
2. **Verify shared secret**: Confirm you're using the correct webhook secret
3. **Check header parsing**: Ensure you're reading the signature header correctly
4. **Review timestamp tolerance**: Make sure your time window isn't too strict
## Compliance Considerations
* **PCI DSS**: If you handle card data, ensure you're PCI compliant
* **GDPR**: If processing EU customer data, follow GDPR requirements
* **Data retention**: Keep audit logs per your compliance needs
* **PII handling**: Redact or encrypt PII in logs per your privacy requirements
## Summary: Quick Security Checklist
* Never expose tokens in client-side code
* Store tokens in a secrets manager (not in code)
* Always use HTTPS for API requests
* Make API calls from your backend server only
* Rotate tokens periodically and after exposure
* Log only non-sensitive metadata
* Validate webhook signatures
* Monitor for unusual activity
* Use separate tokens for sandbox and production
## Next Steps
* [**Merchant Access Token**](/docs/authentication-security/merchant-access-token) — Learn how to get and use your API token
* [**Authentication**](/docs/authentication-security/merchant-access-token) — See token setup, required headers, and authentication troubleshooting
* [**Token FAQ**](/docs/authentication-security/token-faq) — Answers to common questions about tokens
***
# Token FAQ
Source: https://docs.revolv3.com/docs/authentication-security/token-faq
Common questions about payment tokens, network tokens, processor tokens, and how Revolv3 handles tokenization. Clear explanations for developers.
## Understanding Payment Tokens
When processing payments, you'll encounter different types of tokens. This FAQ explains what they are, how they differ, and when you need to care about them.
## What are Network Tokens?
**Network tokens** are card-brand tokens issued by Visa, Mastercard, American Express, or other card networks. They replace the PAN (Primary Account Number—the full card number) with a secure token.
**Key characteristics:**
* **Processor-independent**: Can be used with different payment processors
* **More secure**: Don't expose the actual card number
* **Better longevity**: Automatically update when cards are replaced or expire
* **Higher approval rates**: Card networks prefer network tokens
**Why they matter**: Network tokens help improve security and payment success rates. Revolv3 uses them automatically when available.
## What are Processor Tokens?
**Processor tokens** are tokens created by a specific payment processor (like WorldPay, Adyen, or Nuvei). They can only be used with that specific processor.
**Key characteristics:**
* **Processor-specific**: Only work with the processor that created them
* **Direct routing**: Useful when you need processor-specific features
* **Performance**: Can be faster for repeat transactions with the same processor
**When to use them**: If you're routing directly to a specific processor or need processor-specific features, processor tokens can be useful.
## Which Tokens Does Revolv3 Create and Store?
Revolv3 is smart about tokens—we capture and store multiple token types to maximize flexibility and success rates:
* **PAN** (Primary Account Number): The actual card number (stored securely as a fallback where required)
* **Processor tokens**: Tokens from specific processors (WorldPay, Adyen, etc.)
* **Network tokens**: Tokens from card networks (Visa, Mastercard, etc.)
**Why store multiple types?**
* **Flexibility**: Can route to different processors as needed
* **Resilience**: If one processor is down, can use another
* **Optimization**: Choose the best token for each transaction based on success rates and costs
* **Fallback**: Always have a backup if one token type fails
Think of it like having multiple keys to the same door—if one doesn't work, you can try another.
## Do I Need Processor Tokens if Revolv3 Creates Its Own Token?
**Short answer**: Yes, it's helpful to keep processor tokens alongside Revolv3's tokens.
**Why**: Different tokens work better in different situations:
* **Revolv3 tokens**: Work across multiple processors, great for flexibility
* **Processor tokens**: Optimized for specific processors, can improve performance
* **Network tokens**: Preferred by card networks, improve approval rates
Revolv3 automatically manages all of these for you. You don't need to do anything special—we store the right tokens and use them automatically to optimize your payment success rates.
## What is the "Revolv3 Token" / Payment Method ID?
The **Revolv3 token** (also called a `paymentMethodId`) is Revolv3's internal representation of a payment method. It's what you'll use in your API calls to reference a stored payment method.
**What it contains:**
* May include the PAN (encrypted and secured)
* Processor tokens (from various processors)
* Network tokens (from card networks)
* Additional security data (cryptograms, PAR data, etc.)
**How you use it:**
Instead of sending full card details every time, you send the `paymentMethodId`:
```json theme={null}
{
"paymentMethodId": 6061,
"Invoice": {
"Amount": { "value": 10.00 }
}
}
```
**Why it's useful:**
* **Security**: You never handle full card numbers after the first transaction
* **Convenience**: Simpler API calls
* **Compliance**: Reduces your PCI compliance scope
* **Performance**: Revolv3 optimizes routing based on stored token data
## Implementation Notes
### What Should You Store?
**Store only what you need:**
* ✅ Store the `paymentMethodId` that Revolv3 returns
* ✅ Store your own customer reference IDs
* ❌ Don't store full card numbers or CVV codes
* ❌ Don't store processor tokens unless you have a specific need
**Compliance**: Keep token storage aligned with your compliance obligations (PCI DSS, GDPR, etc.).
### Use API Responses as Source of Truth
The token fields returned by Revolv3's API are what you should use. Don't try to create or modify tokens yourself—let Revolv3 handle that.
### For Recurring Billing
For subscriptions and recurring payments:
* ✅ Store the `paymentMethodId` from the first successful payment
* ✅ Use it for all future charges
* ✅ Revolv3 automatically updates tokens when cards expire or are replaced (via Account Updater)
This gives you the best success rates for recurring billing.
## Common Questions
**Q: Do I need to understand all these token types?**
A: Not really. Revolv3 handles tokenization automatically. Just store the `paymentMethodId` we give you and use it for future transactions.
**Q: What if a token expires?**
A: Revolv3's Account Updater service automatically updates expired tokens. You don't need to do anything.
**Q: Can I use processor tokens directly?**
A: You can, but it's usually better to use Revolv3's `paymentMethodId` so we can optimize routing and handle fallbacks.
**Q: Are network tokens more secure?**
A: Yes, they're more secure than storing PANs and they automatically update when cards are replaced.
## Next Steps
* **[Payment Methods Guide](/docs/core-concepts/paymentmethod/paymentmethod-guide)** — Learn how to store and use payment methods
* **[Account Updater](/docs/core-concepts/paymentmethod/account-updater)** — Understand how cards are automatically updated
* **[Security Best Practices](/docs/authentication-security/security-best-practices)** — Learn how to keep tokens secure
***
# Certification & Go-Live Checklist
Source: https://docs.revolv3.com/docs/certification-go-live/checklist
Pre-launch requirements, mandatory test cases, production enablement process, and contact points for Revolv3 certification and go-live.
Use this checklist before requesting production access. Completing certification (when required) and these steps helps ensure a smooth go-live.
## Pre-Launch Requirements
Before you request production enablement, confirm:
* **Credentials**: Sandbox integration is working with your sandbox API key and you understand how to switch to production credentials. See [Authentication](/docs/authentication-security/merchant-access-token) and [Production vs Sandbox](/docs/getting-started/production-vs-sandbox).
* **Merchant and processor setup**: Merchant settings, processor credentials, and any feature toggles (e.g. network tokenization) are configured as needed for production. See [Merchant Settings](/docs/core-concepts/merchants/merchant-setting).
* **Webhooks**: Webhook endpoints are configured, signature verification is implemented, and handlers respond with 2xx only after processing. See [Webhooks Guide](/docs/webhook-events/webhook) and [Creating a Webhook](/docs/webhook-events/creating-a-webhook).
* **Idempotency**: Payment and refund requests use idempotency keys or otherwise avoid duplicate charges on retries. See [Webhooks](/docs/webhook-events/webhook) and your integration flows.
* **TLS and security**: You use TLS 1.2+ and follow [Security Best Practices](/docs/authentication-security/security-best-practices).
## Mandatory Test Cases
When certification is required, Revolv3 sends test cases to the merchant based on their implementation and specific use cases. Your **onboarding manager** will provide the exact test cases and instructions when you are ready for certification—Revolv3 does not publish a single fixed list, since requirements vary by integration.
## Production Enablement Process
1. **Complete sandbox testing**: Test the flows you need for go-live. When certification is required, your onboarding manager will provide the specific test cases for your implementation.
2. **Complete certification (if required)**: Run through the test cases and any readiness review your onboarding manager provides. Use the contact points below to request or schedule certification.
3. **Request production access**: Contact Revolv3 (see below) to request production enablement. Include correlation IDs and sample payloads when asking for certification or go-live support.
4. **Receive production credentials**: Production API key, portal access, and any processor-specific credentials. Keep these separate from sandbox.
5. **Switch endpoints and keys**: Update your integration to use production base URL and API key. See [Production vs Sandbox](/docs/getting-started/production-vs-sandbox) for endpoints and [Production Environment Limitations](/docs/getting-started/production-limitations) for rate limits.
## Contact Points for Certification and Go-Live
For certification questions, production enablement, and go-live support:
* **Support**: Log into the Revolv3 portal ([production](https://portal.revolv3.com) or [sandbox](https://portal-sandbox.revolv3.com)) and use the **help icon** to submit a support ticket. Include timestamps, request IDs, correlation IDs, and sample request/response payloads when reporting issues or requesting certification support.
* **Appendix and escalation**: [Revolv3 Appendix](/docs/appendix/appendix-revolv3) lists contacts, glossary, and quick operational notes.
Your onboarding manager will share the certification playbook and any readiness or go-live appointment details when you are ready.
# Revolv3 Checkout Integration
Source: https://docs.revolv3.com/docs/checkout/checkout
Learn about Revolv3's secure checkout options. Choose between hosted pages or embedded checkout to collect payments without handling sensitive card data yourself.
## What is Revolv3 Checkout?
**Revolv3 Checkout** lets you collect payments through a secure, pre-built payment form hosted by Revolv3. Instead of building your own payment form and handling sensitive card data, you redirect customers to Revolv3's secure checkout page or embed it in your site.
**Why use checkout instead of building your own form:**
* **Less development work**: Revolv3 handles the payment form UI
* **Better security**: You never handle card data—Revolv3 does
* **PCI compliance**: Revolv3 handles PCI compliance requirements
* **Optimized UX**: Payment forms are optimized for conversion
* **Multiple payment methods**: Support for cards, ACH, and digital wallets
**When to use checkout:**
* You want a quick integration without building payment forms
* You prefer not to handle sensitive payment data
* You want a pre-built, optimized checkout experience
* You need to support multiple payment methods easily
## Two Integration Options
Revolv3 offers two ways to use checkout:
### 1. Hosted Checkout Page
**What it is**: Customers are redirected to a Revolv3-hosted payment page on a separate URL.
**How it works**:
1. You create a checkout session via API
2. Revolv3 returns a checkout URL
3. You redirect the customer to that URL
4. Customer completes payment on Revolv3's page
5. Customer is redirected back to your site
**Best for**:
* Quick integration
* When you want Revolv3 to handle the entire checkout experience
* Mobile-friendly redirects
**Learn more**: [Hosted Page Guide](/docs/checkout/hosted-page)
### 2. Embedded Checkout
**What it is**: Checkout is embedded directly in your website using an iframe.
**How it works**:
1. You create a checkout session via API
2. Revolv3 returns a checkout URL
3. You embed that URL in an iframe on your page
4. Customer completes payment without leaving your site
5. Your page receives a message when payment completes
**Best for**:
* Keeping customers on your site
* Seamless checkout experience
* When you want more control over the page layout
**Learn more**: [Embedded Checkout Guide](/docs/checkout/embedded)
## Feature Overview
Revolv3's Checkout integration provides:
✔ **Clear order details** — Customers see exactly what they're paying for before completing payment
✔ **Multiple payment methods** — Support for credit cards, debit cards, ACH, and digital wallets
✔ **Optimized UI/UX** — Payment forms are designed for all devices and optimized for conversion
✔ **Secure by default** — Revolv3 handles all security and PCI compliance
✔ **Two integration options** — Choose hosted page or embedded based on your needs
## Prerequisites
Before integrating checkout, ensure you have:
1. ✅ **Active Revolv3 account** — You need a merchant account set up
2. ✅ **Configured payment processor** — At least one processor (WorldPay, Adyen, etc.) must be configured
3. ✅ **Developer API key** — Your static token for API authentication
4. ✅ **Trusted hostnames configured** — Your website domain must be registered in Revolv3 portal
## Configuring Trusted Hostnames
To use Revolv3's Checkout feature, you must register your website's hostname in the Revolv3 portal. This ensures only authorized websites can create checkout sessions.
### Steps to Configure Trusted Hostnames
1. **Log in to the Revolv3 Portal**:
* Production: [portal.revolv3.com](https://portal.revolv3.com)
* Sandbox: [portal-sandbox.revolv3.com](https://portal-sandbox.revolv3.com)
2. **Navigate to settings**:
* Go to **Merchant Settings → Integration Profile**
3. **Find Trusted Checkout Hostnames section**:
* Scroll down to the **Trusted Checkout Hostnames** section
4. **Add your hostname**:
* Add the hostname (domain) from which checkout requests will be made
* Ensure it matches your website's domain exactly
### Example
If your website URL is:
```
https://mysite.com
```
Then register the hostname as:
```
mysite.com
```
**Important**:
* The hostname must match the domain making the API request
* Include the hostname in the **Trusted Checkout Hostnames** list
* You can add multiple hostnames if you have multiple domains

## Choosing Your Integration Method
After configuring trusted hostnames, choose which integration method works best for you:
### Option 1: Hosted Checkout Page
**Best for**: Quick integration, redirect-based flow
**How it works**: Customer is redirected to a Revolv3-hosted payment page
**Learn more**: [Hosted Page Guide](/docs/checkout/hosted-page)
### Option 2: Embedded Checkout
**Best for**: Keeping customers on your site, seamless experience
**How it works**: Checkout is embedded in your website using an iframe
**Learn more**: [Embedded Checkout Guide](/docs/checkout/embedded)
## Next Steps
* **[Hosted Page](/docs/checkout/hosted-page)** — Learn how to redirect customers to Revolv3's payment page
* **[Embedded Checkout](/docs/checkout/embedded)** — Learn how to embed checkout in your website
* **[Checkout Line Items](/docs/checkout/checkout-line-items-value-types)** — Understand how to structure checkout items and pricing
***
# Revolv3 Web SDK
Source: https://docs.revolv3.com/docs/checkout/web-sdk
A step-by-step guide for integrating hosted card fields and payment operations.
## 1. Overview
The Revolv3 Web SDK lets you collect credit card details on your own checkout page without the raw card number, expiry, or CVV ever touching your JavaScript. Card inputs render inside a cross-origin iframe hosted by Revolv3; your page only ever sees tokenized results and field-level state (empty/complete/valid/error), never the underlying values.
The recommended path is `tokenize` in the browser, then charge from your server with the Payments API. Persist `paymentMethodId` on the shopper's server session. That id is sequential, and nothing on the payment method identifies the checkout, so do not treat a later id posted by the page as proof it was tokenized here.
`sale` and `authorize` charge from the browser instead. Those run inside the hosted iframe, because that is where the raw card data lives. `saleWithPaymentMethod` and `authorizeWithPaymentMethod` charge an already saved id from the page. Prefer the server-side charge after `tokenize`.

Pin `0.0.5`. Do not use `/latest` in production. `0.0.4` is still published and was not overwritten. Prefer the ESM build and the named export `init`. The same URL is used for sandbox and production. `environment` selects the API and hosted-fields origins.
```html theme={null}
```
ESM integrity hash for that file: `sha384-lHMTgK3Br1/THcR+jGWiJVPr6KVatjfpyT9a1xDfXcbfDXlfTkYIkO6qoDhJKDVx`. Use it with Subresource Integrity when your tooling supports SRI for module imports.
If you cannot use ES modules, load the UMD build instead. It exposes `Revolv3WebSdk.init` (not `Revolv3.init`):
```html theme={null}
```
The examples on this page assume the ESM `init` import above.
## 2. Quick Start
### Step 1 — Mint a session and payment key (your backend)
Before any client-side code runs, your backend — authenticated the same way it already authenticates to the rest of the Revolv3 API — must call two Revolv3 endpoints.
**1. Register a session for this checkout attempt.** Call this from your backend with the same static key you use for the rest of the Revolv3 API. Sandbox host: `https://api-sandbox.revolv3.com`. Production host: `https://api.revolv3.com`.
```
POST /api/web-sdk/auth/order-session
```
```js theme={null}
// request body
{
sessionId: 'a string your backend generates, ≤500 chars', // Revolv3 does not mint this for you
amount: 49.99,
currency: 'USD', // a supported currency code
}
```
```js theme={null}
// response
{
sessionId: '...',
statusType: 'Pending',
expiresAt: '2026-07-27T18:00:00Z', // 30 minutes after creation, by default
}
```
`statusType` is `Pending`, `Processing`, `Completed`, `Failed`, or `Expired`. A session that has already been used returns `Completed`. That value used to be `Paid`. `Completed` means the session was used, not that the payment was approved. Use the sale or authorization result for approval or decline.
Do not send `customerId` on this request. It is not stored on the payment method. Stamp the checkout with `merchantPaymentMethodRefId` on `tokenize` instead.
The `amount`/`currency` you register here is what actually gets charged later. A browser-side `sale` or `authorize` cannot override it.
**2. Mint a one-time payment key, immediately before each submit attempt:**
```
POST /api/web-sdk/auth/ott
```
```js theme={null}
// request body
{ clientId: 'a client identifier, ≤500 chars', sessionId: '...' }
```
```js theme={null}
// response
{ token: '...', expiresIn: 60, expirationTime: '2026-07-27T17:31:00Z' }
```
`clientId` is your Revolv3 client id, not a browser publishable key. This endpoint is server-only (no CORS).
Send `X-Forwarded-For` set to the shopper's IP. The API requires that header and rate-limits on the first address in it (10 requests per 60 seconds per shopper IP, by default). Set it on your server. Do not forward a value the browser supplied.
The token expires \~60 seconds after issue by default and is **single-use**. It is consumed when a payment call using it is accepted, so mint a new one for every attempt. The example in §2 Step 5 fetches it immediately before `tokenize`.
**If a payment attempt fails**, the session moves to a `Failed` status and can't be used for another attempt as-is. Call `POST /api/web-sdk/auth/order-sessions/{sessionId}/reset` first (plural `order-sessions`; this only works while the session is `Failed` or `Expired`), then mint a new payment key and retry.
**Allowlist the checkout hostname** before fields will mount. In the Revolv3 portal: Merchant settings → Integration Profile → Trusted Checkout Hostnames. Enter the hostname only, with no scheme and no port. `localhost` and `127.0.0.1` are different values. `localhost:5173` does not match.
### Step 2 — Add a mount point
```html theme={null}
```
`create()` replaces this element's children with a single iframe containing all four card inputs, so it should be an otherwise-empty container sized by your page's CSS.
### Step 3 — Initialize and mount
```js theme={null}
const hostedFields = init({
sessionId: sessionId, // from step 1
environment: "sandbox", // or "prod" — this alone selects both the iframe and API endpoints
});
await hostedFields.create({
selector: '#fields-container',
styles: {
'--revolv3-border-focus-color': '#6366f1',
},
});
```
`create()` rejects after 15 seconds if the iframe never finishes its setup handshake, so a genuinely broken network fails fast rather than hanging forever.
### Step 4 — Listen for state
```js theme={null}
hostedFields.on('change', function (event) {
// event.field, event.state.isValid, event.state.error && event.state.error.code
});
```
### Step 5 — Submit
```js theme={null}
submitButton.addEventListener("click", async function () {
const paymentKey = await getPaymentKey(sessionId); // fresh key per attempt
try {
const result = await hostedFields.tokenize(paymentKey, {
billingAddress: {
addressLine1: "100 Main St",
city: "Santa Ana",
state: "CA",
postalCode: "92701",
country: "US",
email: "buyer@example.com",
},
// Optional. Mint this on your server. Do not reuse the public sessionId. Max 100 chars.
merchantPaymentMethodRefId: "your-checkout-ref",
});
// POST result.paymentMethodId to your server for this shopper, then charge that stored id.
} catch (error) {
// error is a plain error object — see §8
}
});
```
To charge from the browser instead, call `sale` and include `merchantInvoiceRefId`, or `authorize` and include `merchantPaymentMethodRefId`. See §6.
### Step 6 — Verify server-side
`tokenize` is not a charge. It does not fire a payment webhook. Persist `paymentMethodId` on your server and charge that stored id with the Payments API.
For a browser `sale` or `authorize`, treat the resolved result as informational only. There is no dedicated status-check endpoint under the web-sdk API for your backend to poll by `sessionId`. Configure a webhook per the [webhook events](/docs/webhook-events/webhook) guide and treat that as the source of truth, rather than the client-side promise result.
The two events relevant to a browser `sale` or `authorize`:
* `InvoiceStatusChanged` — fires on transitions of the overall invoice status (the same `invoiceStatus` values from §6).
* `InvoiceAttemptStatusChanged` — fires when a specific payment attempt's status changes (the same `invoiceAttemptStatus` values from §6).
Each delivery is a JSON body (`InvoiceId`, `InvoiceStatus`, `Subtotal`, `Total`, `NetworkTransactionId`, `EventDateTime`, `EventType`, `RevolvMerchantId`, etc.) signed with HMAC-SHA256 in an `x-revolv3-signature` header — verify that signature before trusting the payload, respond `200` immediately and process asynchronously, and handle the delivery idempotently since webhooks can be redelivered.
## 3. Configuration Reference
### The object passed to `init()`
| Field | Type | Required | Description |
| - | - | - | - |
| `sessionId` | string | yes | Session identifier minted by your backend (§2, step 1). Sent on every request and re-checked by both sides of the iframe boundary. |
| `environment` | string | yes | Exactly `'sandbox'` or `'prod'`. Determines which iframe **and** which API the SDK talks to — see below. |
That's the whole config object — there is no merchant identifier and no origin URL to supply. `environment` alone resolves both the hosted-fields iframe URL and the API origin internally; an unrecognized value throws rather than silently defaulting to one or the other. Both environments ship in every build, so a single published bundle serves sandbox and prod.
### The object passed to `create()`
| Field | Type | Required | Description |
| - | - | - | - |
| `selector` | string | yes | CSS selector for the mount container. Must resolve to exactly one element already in the DOM when `create()` is called, or it throws `Container not found: `. |
| `styles` | object | no | CSS custom-property overrides, as plain `{ '--revolv3-...': 'value' }` pairs — see §4 Styling. |
| `fonts` | array | no | Custom web fonts to load into the hosted fields — see §4 Custom Fonts. |
## 4. Hosted Fields
### Field types
One iframe renders all four inputs together — there is no per-field mount API. `selector` targets a single container; the hosted-fields app fills it with a form containing:
| Field identifier (`event.field`) | `autocomplete` | Notes |
| - | - | - |
| `cardholderName` | `cc-name` | Free text, max 80 chars. |
| `paymentAccountNumber` | `cc-number` | Numeric keypad on mobile, 8–31 raw chars incl. spaces. |
| `expirationDate` | `cc-exp` | Displayed and typed as `MM / YY`. |
| `securityCode` | `cc-csc` | 3–4 digits. |
Layout is responsive: expiry and CVV sit side-by-side above 420px width and stack to one column below it, automatically.
### Styling
Every visual property is a CSS custom property scoped to the iframe document — you set values, never selectors, by passing plain string keys in the `styles` object. Unrecognized property names and values that fail a basic safety check (see §9) are dropped silently, not applied and not thrown back to your page.
| CSS custom property | Default |
| - | - |
| `--revolv3-font-family` | system font stack |
| `--revolv3-color` | `#1a1a2e` |
| `--revolv3-font-size` | `15px` |
| `--revolv3-font-style` | `normal` |
| `--revolv3-font-variant` | `normal` |
| `--revolv3-font-weight` | `400` |
| `--revolv3-line-height` | `1.5` |
| `--revolv3-letter-spacing` | `normal` |
| `--revolv3-border-focus-color` | `#6366f1` |
| `--revolv3-border-error-color` | `#dc2626` |
| `--revolv3-placeholder-color` | `#9ca3af` |
| `--revolv3-selection-background` | `rgba(99,102,241,.12)` |
| `--revolv3-selection-color` | `inherit` |
| `--revolv3-autofill-background` | `#ffffff` |
| `--revolv3-autofill-color` | `inherit` |
| `--revolv3-background` | `#ffffff` |
| `--revolv3-border` | `1px solid #d1d5db` |
| `--revolv3-border-radius` | `4px` |
| `--revolv3-padding` | `12px 14px` |
| `--revolv3-icon-color` | `#9ca3af` |
| `--revolv3-hover-border` | `#d1d5db` |
| `--revolv3-disabled-opacity` | `0.6` |
| `--revolv3-opacity` | `1` |
| `--revolv3-shadow-focus` | `0 0 0 3px rgba(99,102,241,.12)` |
| `--revolv3-shadow-error` | `0 0 0 3px rgba(220,38,38,.12)` |
| `--revolv3-label-font-size` | `14px` |
| `--revolv3-error-font-size` | `13px` |
| `--revolv3-layout-gap` | `8px` |
| `--revolv3-field-gap` | `6px` |
```js theme={null}
await hostedFields.create({
selector: '#fields-container',
styles: {
'--revolv3-font-family': "'Inter', sans-serif",
'--revolv3-border-focus-color': '#0ea5e9',
'--revolv3-border-error-color': '#dc2626',
},
});
```
Values are re-applied every time `create()` completes its handshake; there's no separate "update styles" call — remount (`destroy()` then `create()` again) to change styling after the fact.
### Custom Fonts
If your brand font isn't a system font, load it into the hosted fields via `fonts` and then reference it from `--revolv3-font-family`:
```js theme={null}
await hostedFields.create({
selector: '#fields-container',
fonts: [
{ family: 'Inter', src: 'https://fonts.gstatic.com/s/inter/v.../file.woff2' },
],
styles: {
'--revolv3-font-family': "'Inter', sans-serif",
},
});
```
Each entry is `{ family, src }`. Constraints, enforced silently (an entry that fails any of these is just dropped — no error is thrown or surfaced to your code, only a `console.warn` inside the iframe):
* Up to 8 fonts per `create()` call.
* `src` must be an absolute **HTTPS** URL ending in `.woff2`, `.woff`, `.ttf`, or `.otf`.
* The font's host must be **either** `fonts.gstatic.com` **or the same origin as your page**. A self-hosted font file must therefore be served from your own domain, and that response needs an `Access-Control-Allow-Origin` header permitting the hosted-fields iframe's origin, or the browser will block the cross-origin font load even though the URL passed the SDK's own check.
* Requires the browser to support the `FontFace` API — on browsers that don't, `fonts` is silently ignored rather than breaking the rest of `create()`.
## 5. Events
Subscribe with `hostedFields.on(eventName, callback)`, unsubscribe with `hostedFields.off(eventName, callback)`.
| Event name | Fires when | Payload |
| - | - | - |
| `'ready'` | The iframe has finished setup — also resolves `create()`'s promise. | `{ state }` |
| `'change'` | Any field's value changes. | `{ field, state }` |
| `'focus'` | A field gains focus. | `{ field, state }` |
| `'blur'` | A field loses focus. | `{ field, state }` |
| `'submitStart'` | `tokenize`/`sale`/`authorize`/`saleWithPaymentMethod`/`authorizeWithPaymentMethod` was called. | `{ operation }` |
| `'submitComplete'` | The same operation finished — **always fires**, whether it succeeded or failed. | `{ operation }` |
A `state` object looks like this:
```js theme={null}
{
isEmpty: false,
isComplete: true, // user finished typing — independent of correctness
isValid: true,
error: undefined, // or { code: 'invalid_number', message: 'Enter a valid card number.' }
}
```
> `submitStart`/`submitComplete` report nothing about success or failure — they exist purely to drive UI like a global spinner around the call. Whether the operation succeeded must come from the resolved value or thrown error of the `tokenize`/`sale`/`authorize` call itself, not from these events. In particular, a **200-level response can still represent a declined payment** (see `invoiceAttemptStatus` in §6) — `submitComplete` fires the same way either way.
> Errors are intentionally suppressed while a field is still plausibly mid-entry: `state.error` stays absent until a field is either complete or has been blurred. A `change` listener wired up to show inline errors won't show anything for a half-typed card number, by design.
## 6. Payment Operations
These three operations collect a fresh card and are handled inside the hosted iframe.
| Call | Use when | Request |
| - | - | - |
| `hostedFields.tokenize(paymentKey, request)` | Save a card, then charge it from your server. This is the recommended path. Not a charge, so there is no payment webhook. | `merchantPaymentMethodRefId` is optional (string, ≤100). `billingAddress` is optional. `tokenize` does not validate this object before sending. |
| `hostedFields.sale(paymentKey, request)` | Charge the card immediately from the browser. | `merchantInvoiceRefId` is required (string, ≤100). `merchantPaymentMethodRefId` is optional (string, ≤100). |
| `hostedFields.authorize(paymentKey, request)` | Reserve funds from the browser, capture later. | `merchantPaymentMethodRefId` is required (string, ≤100). |
`billingAddress` is optional on all three. See §8. `0.0.5` checks the request in the browser before `sale` and `authorize` are sent, even if you omit `request` (that is treated as `{}`). A missing required id is rejected in the page and does not call the API. `tokenize` does not run that check.
Mint `merchantPaymentMethodRefId` on your server. Do not reuse the public `sessionId` (that value is already on the page, and it can be up to 500 characters). Same-card reuse can return an existing payment method whose ref is from the first tokenize of that card.
**Result shapes** (what the promise resolves to):
```js theme={null}
// tokenize()
{
paymentMethodId: 98765,
billingAddressId: 111,
billingAddress: { /* echoed back */ },
billingFirstName: 'Jane',
billingLastName: 'Doe',
merchantPaymentMethodRefId: 'your-own-ref-id', // echoes what you sent
paymentMethodAchDetails: null,
paymentMethodCreditCardDetails: {
binNumber: '424242',
paymentLast4Digit: '4242',
paymentExpirationDate: '12/29',
accountUpdateMessage: null,
accountUpdateDateTime: null,
accountUpdateCode: null,
},
}
// sale()
{
customerId: null, // set when the payment method is tied to a customer
invoiceId: 2,
merchantInvoiceRefId: 'your-own-ref-id',
merchantPaymentMethodRefId: null, // present only if you sent one
networkTransactionId: '...',
invoiceStatus: '...',
invoiceAttemptStatus: '...', // <- read this for approved/declined, not HTTP status
message: '...',
amount: { currency: 'USD', value: 100 },
paymentMethodId: 98765,
paymentMethodTypeId: 1,
paymentProcessor: '...',
processorMerchantId: '...',
rawResponse: '...',
paymentMethodCreditCardDetails: { /* same shape as tokenize's */ },
responseMessage: '...',
responseCode: '...',
processorResponseDateTime: null,
authCode: null,
processorTransactionId: null,
revolv3ResponseCode: null,
revolv3ResponseMessage: null,
}
// authorize() — a differently-shaped result, not the same as sale()'s
{
networkTransactionId: '...',
paymentMethodAuthorizationId: 555, // the id an eventual capture would reference
paymentMethod: {
paymentMethodId: 98765,
billingAddressId: 111,
billingAddress: { /* ... */ },
billingFirstName: 'Jane',
billingLastName: 'Doe',
merchantPaymentMethodRefId: 'your-own-ref-id',
paymentMethodCreditCardDetails: { /* ... */ },
},
paymentProcessor: null,
processorMerchantId: null,
responseMessage: '...',
responseCode: '...',
rawResponse: null,
message: null,
processorResponseDateTime: null,
authCode: null,
processorTransactionId: null,
revolv3ResponseCode: null,
revolv3ResponseMessage: null,
}
```
`invoiceStatus` and `invoiceAttemptStatus` are returned by `sale` and `saleWithPaymentMethod` only. `tokenize` returns a payment method. `authorize` and `authorizeWithPaymentMethod` return an authorization, not an invoice. `invoiceStatus` is the invoice's overall lifecycle state. `invoiceAttemptStatus` is the outcome of this specific charge attempt:
| invoiceAttemptStatus | Meaning |
| - | - |
| Success | Approved. |
| RetrySuccess | Approved on a retry. |
| Fail | Declined. |
| RetryFail | Declined on a retry. |
| Pending, RetryPending | Still resolving. Treat as not yet final. |
| ConnectivityIssue, RetryConnectivityIssue | Couldn't reach the processor. |
| invoiceStatus | Meaning |
| - | - |
| Paid, MerchantPaid | Settled. |
| Pending, OneTimePaymentPending, BatchPending, CapturePending, RecurringPending, MultiCardsPending, RetryPending | Some stage of in progress. |
| Failed | Did not settle. |
| Void, MerchantCancelled | Cancelled. |
| Refund, PartialRefund, RefundPending, RefundDeclined, RefundFailed, RefundVoid, PartialRefundVoid | Refund-related. |
| Recycle, Noncollectable | Collections-related. |
### Concurrency & timeouts
Only **one payment operation can be in flight at a time** per SDK instance. Calling `tokenize`/`sale`/`authorize`/`saleWithPaymentMethod`/`authorizeWithPaymentMethod` while a previous call hasn't resolved yet rejects immediately with `" already in progress"` — it does not queue. Disable your submit button between `submitStart` and `submitComplete` to avoid this in normal use. This is also enforced server-side, independently — see §9.
Each call auto-rejects with `" timed out."` if no response arrives within **30 seconds**.
## 7. Saved Payment Methods
`saleWithPaymentMethod` and `authorizeWithPaymentMethod` charge or authorize an **already-tokenized** card by payment method id. Because there's no raw card data involved, these calls go **directly from your page to the Revolv3 API** — they don't involve the iframe at all, which is a different trust model from §6.
```js theme={null}
await hostedFields.saleWithPaymentMethod(paymentKey, {
paymentMethodId: 12345, // required, integer
merchantInvoiceRefId: 'your-own-invoice-ref', // required, string, ≤100 chars
});
await hostedFields.authorizeWithPaymentMethod(paymentKey, {
paymentMethodId: 12345, // required, integer — no reference id required here
});
```
**Result shapes.** `saleWithPaymentMethod()` returns the same sale object as `sale()` in §6, including `customerId`. `paymentMethodCreditCardDetails` is filled when the saved method is a credit card (masked BIN, last 4, and expiry from the method on file). It is null for other payment method types.
`authorizeWithPaymentMethod()` returns the same nested authorization as `authorize()` in §6: `networkTransactionId`, `paymentMethodAuthorizationId`, `paymentMethod`, and the processor fields. It does not include `customerId`, `invoiceId`, `invoiceStatus`, or `invoiceAttemptStatus`.
These two calls still participate in the same `submitStart`/`submitComplete`/single-in-flight/timeout behavior as §6.
## 8. Validation & Error Handling
### Field-level errors
An error's `code` is stable and safe to branch on; `message` is an overridable English default, not a contract.
| Code | Meaning |
| - | - |
| `'empty'` | Field has no value. |
| `'invalid_cardholder_name'` | Name too short. |
| `'invalid_number'` | Card number fails format/length/Luhn check. |
| `'invalid_security_code'` | CVV wrong length. |
| `'invalid_expiry_date'` | Expiry not in `MM / YY` format or an invalid month. |
| `'expired_card'` | Expiry is validly formatted but in the past. |
Validation rules applied live inside the iframe:
| Field | Rule |
| - | - |
| Card number | Digits only after stripping whitespace; 8–25 digits; passes a Luhn check. |
| Expiry | `MM / YY` format, month 1–12, not in the past relative to the current month/year. |
| Security code | 3–4 characters. |
| Cardholder name | Trimmed length ≥ 2. |
Incomplete hosted fields block `tokenize`, `sale`, and `authorize`, which run inside the iframe. `saleWithPaymentMethod` and `authorizeWithPaymentMethod` do not read the hosted fields, so an empty card form does not block them.
### Request-level validation
`0.0.5` checks `sale`, `authorize`, `saleWithPaymentMethod`, and `authorizeWithPaymentMethod` before sending. A failed check throws `ErrorResponse`: `message` is the constraint messages joined by `"; "`, and `errors` is a list of `{ property, message }`. It does not call the API. `statusCode` and `details` are empty on that failure.
`tokenize` does not run this check. `merchantPaymentMethodRefId` on `tokenize` is optional and is sent as-is. The server accepts at most 100 characters.
`merchantPaymentMethodRefId` is required on `authorize`. `merchantInvoiceRefId` is required on `sale`. Each is a string of at most 100 characters.
### `billingAddress` (optional)
Accepted on `tokenize`, `sale`, and `authorize` only. The saved-card calls do not take a billing address.
`tokenize` forwards `billingAddress` unchanged. `sale` and `authorize` validate it when you send it. Omit the object to skip those checks. When you send it, it must be an object, `addressLine1` is required, and the other fields are optional and are checked only if you set them.
| Field | Rule |
| - | - |
| `addressLine1` | Required. At most 3000 characters. |
| `addressLine2` | At most 3000 characters. |
| `city` | At most 3000 characters. |
| `state` | At most 2 characters. |
| `postalCode` | 2–10 characters. |
| `phoneNumber` | 7–20 characters. |
| `email` | Valid email. |
| `country` | ISO 3166-1 alpha-2. |
### Error shape
Every rejected payment call throws a plain error-like object:
```js theme={null}
{
message: 'Card was declined',
statusCode: 402, // optional
details: '...', // optional
}
```
```js theme={null}
try {
await hostedFields.sale(paymentKey, request);
} catch (error) {
console.error(error.message, error.statusCode, error.details);
}
```
## 9. Security Model
* Raw PAN, expiry, and CVV are read, formatted, and validated entirely inside the hosted-fields iframe. Your page never receives these values in any event payload or result — only tokenized/masked results (payment method id, last-4, BIN).
* The iframe is loaded with a locked-down sandbox (scripts, forms, and same-origin allowed; nothing else) and sends no referrer.
* Every cross-window message is checked on both sides. Your page only accepts messages from the iframe origin resolved for the chosen `environment`, whose `event.source` is the exact iframe window the SDK created, and whose session id matches the current session. The iframe applies the equivalent origin and session checks against the calling page before acting on anything.
* On mount, the iframe calls a Revolv3 endpoint to verify that the session and origin are authorized before revealing the card form at all — a failed check hides the fields and rejects `create()`'s promise with the iframe's error message, instead of silently resolving.
* Style values are filtered twice: only recognized CSS custom property names are considered, and values are rejected if empty, over 256 characters, or contain `url(`, `@import`, `expression(`, `javascript:`, or a backtick — a basic CSS-injection guard. Rejected values are dropped silently rather than surfaced as an error your code can catch.
* Custom fonts (§4) go through their own allowlist — HTTPS only, a fixed set of font file extensions, and a host restricted to Google Fonts or your page origin — independent of the style-value guard above.
* **The charge amount is locked in server-side, not client-supplied.** `amount`/`currency` are set once when your backend registers the order session (§2, step 1) and are read from that stored session on every payment call — nothing the browser sends can change what's charged.
* **The "one payment operation at a time" behavior described in §6 is also enforced server-side**, independently of the SDK's own in-memory guard: each order session can only move from its `Pending` status to `Processing` once. A second concurrent attempt against the same session is rejected by the server even if the client-side guard were somehow bypassed. A failed attempt leaves the session in a `Failed` status that must be explicitly reset (§2, step 1) before another attempt is possible.
* **The payment key is single-use** — the server invalidates it the moment a payment call using it is accepted, independent of the client-side "already in progress" check.
* The domain-verification call the iframe makes on mount sends only `{ sessionId, origin }` — no client identifier at all. That's consistent with the backend: the owning account is resolved entirely from the order session record (established under your backend's authenticated identity in §2, step 1).
## 10. Full Example
```html theme={null}
```
```html theme={null}
```
## Next Steps
* **[Webhook Events](/docs/webhook-events/webhook)** — Treat webhooks as the source of truth for browser `sale` and `authorize` outcomes
* **[Creating a Webhook](/docs/webhook-events/creating-a-webhook)** — Configure webhook delivery for invoice and attempt status changes
* **[Payment Methods](/docs/core-concepts/paymentmethod/paymentmethod-guide)** — Work with the `paymentMethodId` returned from `tokenize`
* **[Authorizations & Captures](/docs/integration-flows/authorizations-captures)** — Capture funds after a browser `authorize`
* **[Checkout Overview](/docs/checkout/checkout)** — Compare hosted page and embedded checkout options
# Core Concepts & Data Models Overview
Source: https://docs.revolv3.com/docs/core-concepts/core-concepts-overview
High-level overview of Revolv3 entities: Merchant, Customer, PaymentMethod, Invoice, Attempt, Subscription. Learn how they relate and where to find detailed guides.
This page introduces the main entities in the Revolv3 API and how they fit together. Use it as a map before you read the detailed guides for each concept.
## Entities at a Glance
| Entity | Role | Learn more |
| - | - | - |
| **Merchant** | Your Revolv3 account and its settings (processors, defaults, order channels). | [Merchant Settings](/docs/core-concepts/merchants/merchant-setting), [Order Processing Channels](/docs/core-concepts/merchants/order-processing-channels) |
| **Customer** | Optional record for a payer; links payments, subscriptions, and payment methods. | [Customer](/docs/core-concepts/customer/customer) |
| **PaymentMethod** | Stored payment credentials (card, ACH, etc.) used to charge a customer. | [Payment Method Guide](/docs/core-concepts/paymentmethod/paymentmethod-guide), [ACH Direct Debit](/docs/core-concepts/paymentmethod/ach-direct-debit) |
| **Invoice** | Billing document for a charge; holds amount, line items, and state. | [Invoice Status](/docs/core-concepts/invoice/invoice-status), [Get Invoices API](/docs/core-concepts/invoice/get-invoices-api) |
| **Attempt** | A single try to pay an invoice (e.g. one card charge or one ACH pull). One invoice can have multiple attempts. | [Get Invoice Details](/docs/core-concepts/invoice/get-details-of-invoice-attempts) |
| **Subscription** | Recurring billing plan; creates invoices on a schedule and optionally links to a customer and payment method. | [Create a Subscription](/docs/core-concepts/subscription/create-subscription), [Billing Plans](/docs/core-concepts/subscription/billing-plans) |
For status values and enums used across these entities, see [Statuses & enums](/docs/core-concepts/status-enum).
# Customer
Source: https://docs.revolv3.com/docs/core-concepts/customer/customer
Learn when and why to use customer records in Revolv3. Understand how customers work, when they're optional, and how to use them effectively.
## What is a Customer?
A **Customer** in Revolv3 is an optional record that represents a person or business that makes payments through your platform. Think of it like a contact in your CRM—it stores information about the customer and links together all their payments, subscriptions, and payment methods.
**Key point**: Customers are **optional** in Revolv3. You can process payments without creating customer records if you prefer to manage customer data in your own system.
## When to Use Customer Records
### Use Customers When:
* **You want to track customer history**: See all payments, subscriptions, and transactions for a specific customer in one place
* **You're building subscriptions**: Subscriptions are easier to manage when linked to customer records
* **You want Revolv3 to manage customer data**: Let Revolv3 store and organize customer information for you
* **You need customer lookups**: Quickly find all transactions for a specific customer
* **You're building a customer portal**: Customers can view their payment history, subscriptions, etc.
### Don't Use Customers When:
* **You manage customers elsewhere**: If you have your own CRM or customer database
* **One-time anonymous payments**: Guest checkout where you don't need to track the customer
* **You want minimal data in Revolv3**: Keep customer data in your own system only
* **Simple integrations**: One-time payments where customer tracking isn't needed
## How Customers Work
### Customer Records Are Optional
**You can:**
* Create customer records and link payments to them
* Process payments without customer records (set `customer` to `null`)
* Mix both approaches (some payments with customers, some without)
**Example without customer:**
```json theme={null}
{
"Invoice": {
"Amount": { "value": 10.00 }
},
"customer": null // No customer record
}
```
**Example with customer:**
```json theme={null}
{
"Invoice": {
"Amount": { "value": 10.00 }
},
"customer": {
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com"
}
}
```
### What Gets Stored
When you create a customer, Revolv3 stores:
* **Basic info**: Name, email, phone
* **Addresses**: Billing and shipping addresses
* **Payment methods**: Cards and bank accounts linked to this customer
* **Subscriptions**: All subscriptions for this customer
* **Payment history**: All invoices and transactions
* **Metadata**: Custom data you want to store
### Automatic Customer Creation
Revolv3 can automatically create customer records when you process payments.
## Best Practices
2. **Store only what you need**: Don't store sensitive PII unless necessary and compliant
3. **Keep it optional**: Remember customers are optional—don't create them if you don't need them
4. **Update when needed**: Keep customer information current (email, address, etc.)
## Privacy and Compliance
When storing customer data:
* **Validate and sanitize**: Clean data before sending to Revolv3
* **Respect privacy laws**: Follow GDPR, CCPA, and other applicable regulations
* **Use retention policies**: Delete customer data when no longer needed
* **Don't store unauthorized PII**: Only store data you're authorized to collect
## API Usage Notes
* **Customers API**: Use the Customers API to create, retrieve, update, and delete customers
* **Include in payments**: You can include customer data in payment requests, or reference an existing `customerId`
* **Anonymous flows**: For guest checkout or tokenized flows, omit the customer object entirely
## Common Questions
**Q: Do I have to create customers?** A: No, customers are optional. You can process payments without customer records.
**Q: Can I update customer information?** A: Yes, use the Customers API to update customer records.
**Q: What if I manage customers in my own system?** A: You can skip customer records entirely and manage everything in your system.
**Q: Can one customer have multiple payment methods?** A: Yes, customers can have multiple payment methods.
**Q: What happens if I don't provide a customer?** A: The payment processes normally, but no customer record is created. This is fine for one-time payments.
## Next Steps
* [**Create a Subscription**](/docs/core-concepts/subscription/create-subscription) — Learn how customers work with subscriptions
* [**Payment Methods**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Understand how payment methods link to customers
* [**API Reference**](/api-reference/) — See the full Customers API documentation
***
# Forward 3D Secure Parameters to Processors
Source: https://docs.revolv3.com/docs/core-concepts/invoice/3ds-pass
Learn how to include 3D Secure (3DS) authentication results in payment requests. Covers Worldpay and TSYS merchant-supplied 3DS pass-through.
## What is 3D Secure (3DS)?
**3D Secure** (also called "3DS") is an extra security layer for online card payments. When required, customers authenticate directly with their bank.
**Why it matters:**
* Reduces fraud
* Helps with liability shift on supported processors and flows (processor/network dependent)
* Required in some regions (e.g., PSD2)
* May improve approval rates
Revolv3 supports **merchant-supplied 3DS data** on Sale and Authorize when your payment routes to a supported processor.
> [!WARNING]
>
> **Important:** behavior differs by processor. **Worldpay** accepts merchant-supplied 3DS pass-through from your MPI (Merchant Plug-in); Revolv3 sends Worldpay **3DS Data Only** today — not a hosted challenge. **TSYS** accepts **data-only 3DS pass-through only** — risk/data share with the issuer, **no cardholder challenge**, **no full authentication**, and **no liability shift**. Configure your MPI (for example PAAY) for **data-only** before sending `threeDS` to a TSYS merchant.
## 3DS Version Support
Revolv3 supports **EMV 3DS 2.x pass-through only**.
3DS 1.x pass-through is **not supported**.
## Processor Support
| Processor | Supported | Flow |
| - | - | - |
| **Worldpay** | Yes | Merchant-supplied 3DS pass-through (Base64 `cavv`). Revolv3 sends Worldpay **3DS Data Only** today — not a hosted challenge. |
| **TSYS** | Yes | **Data-only** pass-through only |
| **Nuvei** | Yes | External MPI pass-through |
| **Other processors** | No | `threeDS` may be ignored |
If the request routes to an unsupported processor, `threeDS` is not forwarded.
## TSYS: Data-Only 3DS Only
For TSYS authorizations, Revolv3 supports **data-only** 3DS pass-through. This is **not** full 3DS:
* No cardholder challenge step through Revolv3.
* No full authentication or **liability shift** (Visa ECI **`07`**, not `05`).
* Revolv3 does **not** accept **`eci`** on the Payment API for TSYS — the platform maps the data-only path internally.
**Configure your MPI for data-only** before enabling TSYS pass-through:
* Use **challenge indicator `06`** (no challenge / data share) where your provider supports it.
* Expect **ECI `07`** on Visa from the MPI — do **not** send full-auth results (ECI `05`, authentication status `Y`) unless you have confirmed full TSYS 3DS support with Revolv3.
* Your MPI returns `cavv`, `dsTransactionId`, and `threeDsVersion` from the data-only exchange.
* If your MPI returns Base64 `cavv`, convert it to **40-character hex** before calling Revolv3. Revolv3 does **not** convert for you.
> [!NOTE]
>
> **Full 3DS on TSYS** (ECI `05`/`06`, liability shift) is **not available** in production today.
## The `threeDS` Object
Include the `threeDS` object in your payment request:
```json theme={null}
{
"threeDS": {
"cavv": "",
"dsTransactionId": "",
"threeDsVersion": "2.1.0"
}
}
```
Do **not** send `eci` on Revolv3 Payment API requests. It is not supported on the `threeDS` object and is ignored if sent.
### Field Reference
| Field | Description | Required | Max length | Worldpay | TSYS |
| - | - | - | - | - | - |
| `cavv` | Authentication cryptogram from your MPI | Required if `threeDS` is sent | 40 | **Base64** | **40-char hex** (Visa / Amex / Discover) |
| `dsTransactionId` | Directory Server Transaction ID (EMV 3DS 2.x) | Recommended | 36 | UUID from MPI | UUID from MPI |
| `threeDsVersion` | Protocol version (`2.1.0`, `2.2.0`, `2.3.0`) | Required | — | Same | Same |
| `xid` | Legacy 3DS 1.x transaction id | Optional | 40 | Rare for 2.x | **Usually omit** for 2.x. Do **not** put `dsTransactionId` here |
| `eci` | Electronic Commerce Indicator | — | — | Not on Revolv3 DTO | **Not supported** — do not send |
**Note:**\
`dsTransactionId` is the Directory Server *Transaction* ID (transaction-level identifier), not a Directory Server ID. On Worldpay, Revolv3 forwards `dsTransactionId` for Mastercard only — still send it for every brand when your MPI returns it.
***
## Example Requests
### Worldpay (Base64 `cavv`)
```json theme={null}
{
"paymentMethod": {
"creditCard": {
"paymentAccountNumber": "4111111111111111",
"expirationDate": "0330",
"securityCode": "737"
}
},
"threeDS": {
"cavv": "AAABBIIFmAAAAAAAAAAAAAAAAAA",
"dsTransactionId": "550e8400-e29b-41d4-a716-446655440000",
"threeDsVersion": "2.1.0"
},
"invoice": {
"amount": {
"value": 1.03,
"currency": "USD"
}
}
}
```
### Nuvei (Base64 `cavv`)
Nuvei expects the same Base64 `cavv` shape as Worldpay. Send values in the encoding your MPI returns for that authentication.
### TSYS (Data-Only, Hex `cavv`)
```json theme={null}
{
"paymentMethod": {
"creditCard": {
"paymentAccountNumber": "4111111111111111",
"expirationDate": "0330",
"securityCode": "737"
}
},
"threeDS": {
"cavv": "0099010349105700000007D08402307500000000",
"dsTransactionId": "3a0d7238-79ff-4a2b-9d39-550c3527da28",
"threeDsVersion": "2.2.0"
},
"invoice": {
"amount": {
"value": 1.03,
"currency": "USD"
}
}
}
```
Use real values from your MPI in production. If PAAY (or another provider) returns Base64 `cavv`, convert to 40-character hex before calling Revolv3. Do not include `eci` or `xid` unless you have a true legacy XID.
***
## Troubleshooting
| Symptom | Likely cause | What to do |
| - | - | - |
| TSYS **`19` / RE ENTER** | Base64 `cavv` or UUID in `xid` | Use 40-char **hex** `cavv`; omit `xid` for 2.x |
| TSYS **`82` / INCORRECT CVV** with good CVV | **Full-auth** MPI data (ECI `05`, status `Y`) sent to **data-only** TSYS path | Reconfigure MPI for **data-only** (indicator `06`, ECI `07`). Control test: same card **without** `threeDS` |
| Decline only when `threeDS` present | Wrong encoding or wrong flow type | See rows above |
| Invalid Base64 `cavv` | Malformed Base64 | **Worldpay / Nuvei only** — fix Base64 or see sandbox padding note below |
| Missing `threeDsVersion` | Required field omitted | Include `2.1.0`, `2.2.0`, or `2.3.0` |
| Unsupported `threeDsVersion` | Version outside supported range | Use `2.1.0`–`2.3.0` |
### Worldpay Sandbox Note (Base64 Padding)
Some Worldpay sandbox scenarios may reject `cavv` values that include trailing base64 padding (`=`).
Example:
```text theme={null}
AAABBIIFmAAAAAAAAAAAAAAAAAA= may fail
AAABBIIFmAAAAAAAAAAAAAAAAAA may succeed
```
Only remove trailing `=` padding if required. Do not modify any other characters. This applies to **Worldpay** only, not TSYS or Nuvei.
***
## Best Practices
* Match **MPI configuration to processor**: Worldpay and TSYS both use merchant-supplied pass-through today; **TSYS requires data-only** MPI setup.
* **Encoding:** Base64 `cavv` for Worldpay and Nuvei; **hex `cavv`** for TSYS Visa/Amex/Discover.
* **EMV 3DS 2.x:** put the directory-server UUID in `dsTransactionId` only — leave `xid` empty unless you have a true legacy XID.
* **Do not send `eci`** on Revolv3 Payment API requests for TSYS.
* Only include fields your MPI returned (plus any required encoding conversion for TSYS).
* Ensure `threeDsVersion` matches the authentication that produced `cavv`.
* Test on the **same processor family** you use in production.
* If TSYS sales fail **without** `threeDS` but fail **with** full-auth MPI data, switch MPI to **data-only** (ECI `07`).
***
## Common Questions
#### Can I use the same `threeDS` object for Worldpay and TSYS?
No. Worldpay uses Base64 `cavv` on a merchant-supplied **3DS Data Only** path. TSYS requires **hex** `cavv` and **data-only** MPI results only.
#### Do I send a different `threeDS` object for Visa vs Mastercard on Worldpay?
No. Use the same object for every brand. Send `cavv`, `dsTransactionId`, and `threeDsVersion` when your MPI returns them. On Worldpay, Revolv3 forwards `dsTransactionId` for Mastercard only.
#### Is Worldpay full 3DS / liability shift?
Not with today's mapping. Revolv3 passes your MPI `cavv` on a Worldpay **3DS Data Only** path — not a hosted challenge and not full authentication / liability shift.
#### Where does the Directory Server UUID go?
In `dsTransactionId`. Do not put it in `xid`. Send it for every brand when your MPI returns it.
#### Should I send `eci: "05"` for TSYS?
No. Revolv3 does not accept `eci` for TSYS data-only pass-through. Sending full-auth ECI from your MPI while Revolv3 uses the data-only TSYS path can cause declines (for example **`82` / INCORRECT CVV**).
#### Will I get liability shift on TSYS?
Not with data-only pass-through. Liability shift requires full 3DS support, which is not available in production on TSYS today.
#### Can I reuse a Worldpay `threeDS` payload on Nuvei?
Usually yes for `cavv` encoding (both expect Base64), but confirm `threeDsVersion` and `dsTransactionId` match what your MPI returned for that authentication.
***
## Next Steps
* [**Make a Payment**](/docs/getting-started/make-a-payment) — See how to structure payment requests
* [**Sale with Payment Method Details**](/api-reference/payments/sale-with-payment-method-details) — API reference for sale requests with `threeDS`
* [**Authorize with Payment Method Details**](/api-reference/payments/authorize-with-payment-method-details) — API reference for authorization requests with `threeDS`
* [**Error Responses**](/docs/error-codes/error-responses) — Learn how to handle API and processor errors
***
# Dynamic Descriptor Guide
Source: https://docs.revolv3.com/docs/core-concepts/invoice/dynamic-descriptor-guide
Customize what appears on customer credit card statements using dynamic descriptors. Reduce chargebacks and improve customer recognition of charges.
## What is a Statement Descriptor?
A **statement descriptor** (also called a "merchant descriptor") is the text that appears on a customer's credit card or bank statement describing the charge. It's what customers see when they review their statements.
**Why it matters:**
* **Customer recognition**: Customers can easily identify your charges
* **Reduces chargebacks**: Clear descriptors reduce "I don't recognize this charge" disputes
* **Brand awareness**: Customers see your business name
* **Support**: Easier for customers to find charges when contacting support
**Example**: Instead of seeing "REVOLV3" or a processor name, customers see "ACME STORE - ORDER #12345" which is much clearer.
## Static vs Dynamic Descriptors
### Static Descriptor
A **static descriptor** is the same for all transactions. It's simple to set up but less flexible.
**When to use:**
* Single product or service
* No need for transaction-specific information
* Simple setup preferred
**Example**: All charges show "ACME STORE"
### Dynamic Descriptor
A **dynamic descriptor** can be customized for each transaction, showing specific information like order numbers, product names, or locations.
**When to use:**
* Multiple products or services
* Want to show order numbers or transaction details
* Need location-specific information (for multi-location businesses)
* Payment facilitator (showing sub-merchant information)
**Example**: Charges show "ACME STORE - ORDER #12345" or "ACME STORE OAKLAND"
## Important: Configuration Required
> [!WARNING]
>
> **Special configuration is required** to use static or dynamic descriptors. Contact Revolv3 Support to enable this feature for your account.
You cannot use dynamic descriptors without Revolv3 enabling it first. Contact support to:
* Enable descriptor customization
* Configure which processors support it
* Set up any required merchant settings
## Static Descriptor
### What It Is
A **static descriptor** shows the same text on every customer statement. It's the simplest option.
### Processor Support
> [!NOTE]
>
> **Important clarification**: Every payment processor supports static descriptors in some form, since statements must show something. Usually this is your legal or DBA (Doing Business As) name, which can be configured with the processor directly.
>
> Revolv3 also provides the ability to configure static descriptors through our portal, but this is only available for certain processors.
**Static descriptors can be configured in the Revolv3 Portal for:**
* WorldPay
* Nuvei
* Adyen
* Paymentech
* PaymentLync
For other processors, configure static descriptors directly with the processor.
### How to Set Up
1. Contact Revolv3 Support to enable static descriptors
2. Configure in the Revolv3 Portal (Merchant Settings)
3. Set your business name or DBA name
4. All future transactions will use this descriptor
## Dynamic Descriptor
### What It Is
A **dynamic descriptor** lets you customize the statement text for each transaction. You can include:
* Order numbers
* Product names
* Location information
* Sub-merchant information (for payment facilitators)
### Why Use Dynamic Descriptors
**Benefits:**
* **Better customer recognition**: "ACME STORE - ORDER #12345" is clearer than just "ACME STORE"
* **Reduced chargebacks**: Customers can easily identify charges
* **Support efficiency**: Customers can reference order numbers when calling support
* **Multi-location businesses**: Show which location processed the charge
**Example scenarios:**
* E-commerce: "STORE - ORDER #12345"
* Restaurant: "RESTAURANT - LOCATION OAKLAND"
* Subscription: "SERVICE - MONTHLY PLAN"
* Payment facilitator: "MARKETPLACE - SELLER NAME"
### Dynamic Descriptor Object
Include this object in your API request to set a dynamic descriptor:
```bash bash theme={null}
{
"DynamicDescriptor": {
"SubMerchantId": "98765",
"SubMerchantName": "Test",
"SubMerchantPhone": "408-555-1212",
"CountryCode": "US",
"City": "Oakland"
}
}
```
### Dynamic Descriptor Fields
All fields are optional. Include only what you need.
| Field | Description | Example |
| - | - | - |
| `SubMerchantId` | Your internal merchant/sub-merchant ID. Sent to the card network. | `"98765"` |
| `SubMerchantName` | The merchant name as displayed on the customer's statement. This is what customers see. | `"ACME STORE"` or `"ACME - ORDER #123"` |
| `SubMerchantPhone` | Contact information (phone or email) displayed on the statement. | `"408-555-1212"` or `"support@acme.com"` |
| `CountryCode` | Country code (ISO format). | `"US"`, `"CA"`, `"GB"` |
| `City` | City name where the transaction occurred. | `"Oakland"`, `"San Francisco"` |
### Character Limits
* **Total length**: Usually limited to 22-25 characters (varies by processor)
* **Best practice**: Keep it short and clear
* **What gets truncated**: If too long, processors may truncate the descriptor
**Tips for good descriptors:**
* Use abbreviations if needed: "ACME" instead of "ACME STORE INC"
* Include key info: Order number or location
* Test what customers see: Make a test purchase and check your statement
## Endpoints Supporting Dynamic Descriptor
You can include `DynamicDescriptor` in these endpoints:
* `POST /api/payments/sale` - One-time payment
* `POST /api/payments/sale/{paymentMethodId}` - Payment with stored method
* `POST /api/payments/capture/{paymentMethodAuthorizationId}` - Capture authorized payment
* `POST /api/payments/authorization` - Authorize payment
* `POST /api/payments/authorization/{paymentMethodId}` - Authorize with stored method
> **Note**: The endpoint `/api/invoices/payment` is obsolete and should not be used.
## Processor Support for Dynamic Descriptors
Dynamic descriptors are supported by:
* WorldPay
* Nuvei
* Paymentech (JPMorgan)
* PaymentLync
* EPX
* BridgePay
Dynamic descriptors are **not** supported for:
* Adyen
* TSYS
**What this means:**
* If your request includes `DynamicDescriptor` and you're using a supported processor, the descriptor will be used
* If you're using an unsupported processor, the descriptor will be ignored (no error, it just won't be used)
* Check with Revolv3 which processors you're using
## Real-World Examples
### Example 1: E-Commerce with Order Numbers
**Goal**: Show order number on statement
**Request**:
```json theme={null}
{
"DynamicDescriptor": {
"SubMerchantName": "ACME - ORDER #12345"
},
"Invoice": {
"MerchantInvoiceRefId": "12345",
"Amount": { "value": 99.99 }
}
}
```
**Customer sees**: "ACME - ORDER #12345" on their statement
### Example 2: Multi-Location Business
**Goal**: Show which location processed the charge
**Request**:
```json theme={null}
{
"DynamicDescriptor": {
"SubMerchantName": "ACME STORE",
"City": "Oakland"
}
}
```
**Customer sees**: "ACME STORE OAKLAND" (format may vary by processor)
### Example 3: Payment Facilitator
**Goal**: Show sub-merchant information
**Request**:
```json theme={null}
{
"DynamicDescriptor": {
"SubMerchantId": "SELLER-123",
"SubMerchantName": "MARKETPLACE - SELLER",
"SubMerchantPhone": "support@marketplace.com"
}
}
```
**Customer sees**: Marketplace and seller information
## Best Practices
1. **Keep it short**: Descriptors are limited to \~22-25 characters
2. **Be descriptive**: Include order numbers or key identifiers
3. **Test it**: Make a test purchase and check what appears on the statement
4. **Be consistent**: Use the same format across transactions
5. **Include contact info**: Add phone or email so customers can reach you
6. **Consider your brand**: Use your recognizable business name
## Common Questions
**Q: Do I need to enable this feature?**
A: Yes, contact Revolv3 Support to enable dynamic descriptors for your account.
**Q: Will it work with all processors?**
A: No, only certain processors support dynamic descriptors. Check with Revolv3 which processors you're using.
**Q: What if my descriptor is too long?**
A: Processors will truncate it. Keep it under 22-25 characters to be safe.
**Q: Can I use both static and dynamic?**
A: Typically you use one or the other. Dynamic overrides static when provided.
**Q: What if I don't provide a descriptor?**
A: The processor's default descriptor will be used (usually your legal/DBA name).
## Next Steps
* **[Make a Payment](/docs/getting-started/make-a-payment)** — See how to include descriptors in payment requests
* **[Authorizations & Captures](/docs/integration-flows/authorizations-captures)** — Use descriptors with authorization/capture flows
* Contact Revolv3 Support to enable dynamic descriptors for your account
***
# Get Invoice Details
Source: https://docs.revolv3.com/docs/core-concepts/invoice/get-details-of-invoice-attempts
Retrieve detailed information about a specific invoice, including all payment attempts, full payment method details, and processor responses.
## What is Get Invoice Details?
The **Get Invoice Details** endpoint returns complete information about a specific invoice, including:
* All payment attempts (every try, not just the latest)
* Full payment method information
* Invoice line items
* Processor responses and transaction IDs
* Customer information (if linked)
**When to use it:**
* Customer support: Looking up a specific invoice
* Debugging: Understanding why a payment failed
* Reconciliation: Getting all transaction details
* Reporting: Detailed invoice information for accounting
* After getting invoice list: Get details for specific invoices
> **Tip**: Use [Get Invoices](/docs/core-concepts/invoice/get-invoices-api) to get a list, then use this endpoint to get details for specific invoices.
## API Endpoint
```
GET {{Api Root}}/api/Invoices/{invoiceId}
```
Replace:
* `{{Api Root}}` with `api.revolv3.com` (production) or `api-sandbox.revolv3.com` (sandbox)
* `{invoiceId}` with the actual invoice ID (e.g., `302756`)
### Example Request
```bash theme={null}
GET {{Api Root}}/api/Invoices/302756
```
## Understanding Invoice Attempts
An **invoice attempt** is each time Revolv3 tries to process the payment. An invoice can have multiple attempts if:
* The first attempt failed and Revolv3 retried
* The payment was recycled (for subscriptions)
**To find the latest attempt**: Check the `invoiceAttemptDate` in the `invoiceAttempts` array—the most recent date is the latest attempt.
## Sample Response
```json theme={null}
{
"InvoiceId": 302756,
"ParentInvoiceId": null,
"CustomerId": null,
"MerchantInvoiceRefId": "ABC309500654810",
"PaymentMethod": {
"PaymentMethodId": 6469,
"BillingAddressId": 7551,
"BillingFirstName": "Joe",
"BillingLastName": "Smith",
"MerchantPaymentMethodRefId": null,
"BillingAddress": {
"AddressId": 7551,
"AddressLine1": "381 Forest Ave. Suite C",
"AddressLine2": null,
"City": "Laguna Beach",
"State": "CA",
"PostalCode": "92651",
"PhoneNumber": null,
"Email": null,
"Country": "US"
},
"PaymentMethodAchDetails": null,
"PaymentMethodCreditCardDetails": {
"BinNumber": "444433",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "0330"
}
},
"InvoiceStatus": "Paid",
"Subtotal": 1.03,
"Tax": 0.0,
"Total": 1.03,
"BillingDate": "9/17/2024",
"MerchantLegalName": "Revolv3",
"MerchantCustomerRefId": null,
"CustomerFirstName": null,
"CustomerLastName": null,
"SubscriptionId": null,
"InstallmentId": null,
"EligibilityFailReason": null,
"MerchantSubscriptionRefId": null,
"NetworkTransactionId": "197066166170419",
"InvoiceLineItems": [],
"InvoiceAttempts": [
{
"InvoiceAttemptId": 139859,
"Amount": 1.03,
"InvoiceAttemptStatus": "Success",
"InvoiceAttemptDate": "2024-09-17T18:40:38.107",
"PaymentProcessor": "WorldPay",
"ProcessorTransactionId": "83995072261509527",
"ResponseCode": "000",
"ResponseMessage": "Approved",
"PaymentMethod": {
"PaymentMethodId": 6469,
"BillingAddressId": 7551,
"BillingAddress": {
"AddressId": 7551,
"AddressLine1": "381 Forest Ave. Suite C",
"AddressLine2": null,
"City": "Laguna Beach",
"State": "CA",
"PostalCode": "92651",
"PhoneNumber": null,
"Email": null,
"Country": "US"
},
"BillingFirstName": "Joe",
"BillingLastName": "Smith",
"MerchantPaymentMethodRefId": null,
"PaymentMethodAchDetails": null,
"PaymentMethodCreditCardDetails": {
"BinNumber": "444433",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "0330"
}
},
"EligibilityCheckOrderCode": null
}
]
}
```
## Understanding the Response
### Invoice-Level Fields
| Field | Description |
| - | - |
| `invoiceId` | Revolv3's unique identifier for this invoice |
| `parentInvoiceId` | If this is a refund, links to the original invoice |
| `customerId` | Customer ID if linked to a customer record |
| `merchantInvoiceRefId` | Your internal invoice/order reference ID |
| `invoiceStatus` | Current invoice status (`Paid`, `Pending`, `Noncollectable`, etc.) |
| `subtotal` | Invoice amount before tax |
| `tax` | Tax amount |
| `total` | Total invoice amount |
| `billingDate` | Date the invoice was billed |
| `networkTransactionId` | Transaction ID from the card network (important for disputes) |
| `subscriptionId` | Subscription ID if this invoice is from a subscription |
| `installmentId` | Installment ID if this is part of an installment plan |
### Invoice Attempts Array
The `invoiceAttempts` array contains all payment attempts for this invoice. Each attempt includes:
| Field | Description |
| - | - |
| `invoiceAttemptId` | Unique ID for this specific attempt |
| `amount` | Amount attempted in this try |
| `invoiceAttemptStatus` | Result: `Success`, `Fail`, `Pending`, etc. |
| `invoiceAttemptDate` | When this attempt was made (use this to find the latest) |
| `paymentProcessor` | Which processor handled this attempt (WorldPay, Adyen, etc.) |
| `processorTransactionId` | Transaction ID from the processor |
| `responseCode` | Processor's response code (e.g., "000" = approved) |
| `responseMessage` | Processor's response message (e.g., "Approved", "Declined") |
| `paymentMethod` | Payment method used for this attempt |
### Finding the Latest Attempt
To find the most recent payment attempt:
1. Look at the `invoiceAttempts` array
2. Find the attempt with the latest `invoiceAttemptDate`
3. Check its `invoiceAttemptStatus` to see if it succeeded or failed
**Example**: If you have 3 attempts with dates:
* 2024-09-17T18:40:38 (Success) ← Latest
* 2024-09-17T18:40:35 (Fail)
* 2024-09-17T18:40:30 (Fail)
The latest attempt succeeded.
## Real-World Use Cases
### Use Case 1: Customer Support
**Scenario**: Customer says "I was charged twice"
**Solution**:
1. Look up invoice by `merchantInvoiceRefId` (their order number)
2. Check `invoiceAttempts` array
3. See if there are multiple successful attempts
4. If yes, one might be a duplicate—process a refund
### Use Case 2: Debugging Failed Payment
**Scenario**: Payment failed, need to know why
**Solution**:
1. Get invoice details
2. Look at the latest attempt in `invoiceAttempts`
3. Check `invoiceAttemptStatus` (probably "Fail")
4. Check `responseMessage` for the reason (e.g., "Insufficient Funds")
5. Use this information to help the customer
### Use Case 3: Reconciliation
**Scenario**: Matching Revolv3 invoices with bank deposits
**Solution**:
1. Get invoice details
2. Use `networkTransactionId` to match with bank statements
3. Use `processorTransactionId` for processor-specific reconciliation
4. Verify amounts match (`total` field)
### Use Case 4: Subscription Payment History
**Scenario**: Customer wants to see all their subscription payments
**Solution**:
1. Get invoices filtered by `subscriptionId`
2. For each invoice, get details to show full payment history
3. Display all attempts so customer can see retries
## Best Practices
1. **Store invoice IDs**: When you create an invoice, save the `invoiceId` for later lookups
2. **Check latest attempt**: Always look at the most recent attempt for current status
3. **Store transaction IDs**: Save `networkTransactionId` and `processorTransactionId` for reconciliation
4. **Handle multiple attempts**: Your code should handle invoices with multiple attempts
5. **Use for debugging**: This endpoint is great for troubleshooting payment issues
## Common Questions
**Q: How do I know which attempt is the latest?** A: Sort the `invoiceAttempts` array by `invoiceAttemptDate` (most recent first). The first one is the latest.
**Q: Can an invoice have multiple successful attempts?** A: Typically no—once an invoice is paid, further attempts usually don't happen.
**Q: What if there are no attempts?** A: The invoice might be pending or the payment hasn't been processed yet. Check the `invoiceStatus`.
**Q: How do I get processor-specific details?** A: Check the `processorTransactionId` and `responseCode`/`responseMessage` in the attempt. For raw processor responses, see [Processor Raw Response](/docs/core-concepts/invoice/processor-raw-response).
## Next Steps
* [**Get Invoices API**](/docs/core-concepts/invoice/get-invoices-api) — Get a list of invoices
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand invoice statuses
* [**Processor Raw Response**](/docs/core-concepts/invoice/processor-raw-response) — Get full processor response details
***
# Get Invoices API
Source: https://docs.revolv3.com/docs/core-concepts/invoice/get-invoices-api
Learn how to retrieve a list of invoices with filtering and pagination. Understand when to use this endpoint and how to get detailed invoice information.
## What is the Get Invoices API?
The **Get Invoices API** retrieves a list of invoices from your account. Use it to:
* View all your invoices
* Filter invoices by date, status, or other criteria
* Paginate through large lists of invoices
* Get a summary of invoice information
**When to use it:**
* Building a dashboard or reporting system
* Reconciling payments with your accounting system
* Looking up invoices for customer support
* Generating reports or exports
* Monitoring payment activity
> **Note**: This endpoint returns summary information. For detailed invoice information including payment attempts, use [Get Invoice Details](/docs/core-concepts/invoice/get-details-of-invoice-attempts).
## API Endpoint
```
GET {{Api Root}}/api/Invoices/v1
```
Replace `{{Api Root}}` with:
* **Production**: `api.revolv3.com`
* **Sandbox**: `api-sandbox.revolv3.com`
## Request Parameters
All parameters are optional. Use these main parameters to filter or paginate the results.
| Parameter | Type | Description | Default |
| - | - | - | - |
| `billingStartDate` | String | Filter invoices issued on or after this date. Format: `YYYY-MM-DD` (e.g., `2024-01-05`) | None (all invoices) |
| `billingEndDate` | String | Filter invoices issued on or before this date. Format: `YYYY-MM-DD` (e.g., `2024-12-12`) | None (all invoices) |
| `page` | Integer | Page number to retrieve (starts at 1) | 1 |
| `pageSize` | Integer | Number of invoices per page (maximum: 100) | 100 |
### Understanding Date Filters
* **Date format**: Use `YYYY-MM-DD` format (e.g., `2024-01-05`)
* **Time zone**: Dates are based on `billingDate` in UTC
* **Inclusive**: `BillingStartDate` and `BillingEndDate` are inclusive (invoices on those dates are included)
### Understanding Pagination
* **Page numbers**: Start at 1 (not 0)
* **Page size**: Maximum 100 invoices per page
* **Default**: 100 invoices per page if not specified
* **Total pages**: Calculate based on total invoices and page size
## Example Requests
### Get All Invoices (First Page)
```bash theme={null}
GET {{Api Root}}/api/Invoices/v1
```
Returns the first 100 invoices (default page size).
### Filter by Date Range
```bash theme={null}
GET {{Api Root}}/api/Invoices?startDate=2024-01-05&endDate=2024-12-12
```
Returns invoices between January 5, 2024 and December 12, 2024.
### Paginated Request
```bash theme={null}
GET {{Api Root}}/api/Invoices?startDate=2024-01-05&endDate=2024-12-12&page=2&pageSize=10
```
Returns page 2 with 10 invoices per page, filtered by date range.
## Response Format
The API returns a JSON array of invoice objects. Each object contains summary information about the invoice.
### Sample Response
```json theme={null}
[
{
"InvoiceId": 388815,
"CustomerId": null,
"MerchantInvoiceRefId": "1234-5678-9101",
"BinNumber": "444433",
"Last4Digit": "1111",
"InvoiceStatus": "Paid",
"Subtotal": 150.0,
"Tax": 0.0,
"Total": 150.0,
"BillingDate": "12-15-2024",
"MerchantLegalName": "Test Merchant",
"MerchantCustomerRefId": null,
"CustomerFirstName": null,
"CustomerLastName": null
}
]
```
This example shows a single invoice object; in real responses, the array can contain multiple invoices.
### Response Main Fields
| Field | Type | Description |
| - | - | - |
| `invoiceId` | Integer | Revolv3's unique identifier for this invoice |
| `customerId` | Integer \| null | Customer ID if linked to a customer record |
| `merchantInvoiceRefId` | String \| null | Your internal invoice/order reference ID |
| `binNumber` | String | First 6 digits of the payment method (identifies the bank) |
| `last4Digit` | String | Last 4 digits of the payment method (safe to display) |
| `invoiceStatus` | String | Current status: `Paid`, `Pending`, `Noncollectable`, `Refund`, etc. |
| `subtotal` | Number | Invoice amount before tax |
| `tax` | Number | Tax amount |
| `total` | Number | Total invoice amount (subtotal + tax) |
| `billingDate` | String | Date the invoice was billed (format: MM-DD-YYYY) |
| `merchantLegalName` | String | Your merchant's legal name |
| `merchantCustomerRefId` | String \| null | Your internal customer reference ID |
| `customerFirstName` | String \| null | Customer's first name (if available) |
| `customerLastName` | String \| null | Customer's last name (if available) |
## Sorting
Results could be automatically sorted by: `BillingDate, LastUpdateDate, InvoiceId`
## Getting Detailed Invoice Information
This endpoint returns summary information. For detailed information including:
* Payment attempts (all tries, not just the latest)
* Full payment method details
* Invoice line items
* Processor responses
Use the [Get Invoice Details](/docs/core-concepts/invoice/get-details-of-invoice-attempts) endpoint:
```
GET {{Api Root}}/api/Invoices/{invoiceId}
```
Replace `{invoiceId}` with the invoice ID from the list response.
## Real-World Use Cases
### Use Case 1: Dashboard Display
**Scenario**: Show recent invoices on a dashboard
**Solution**:
```bash theme={null}
GET {{Api Root}}/api/Invoices/v1?page=1&pageSize=10
```
Returns the 10 most recent invoices (sorted by date, newest first).
### Use Case 2: Monthly Reconciliation
**Scenario**: Get all paid invoices for a specific month
**Solution**:
```bash theme={null}
GET {{Api Root}}/api/Invoices?startDate=2024-01-01&endDate=2024-01-31
```
### Use Case 3: Customer Support Lookup
**Scenario**: Find an invoice by customer's order ID
**Solution**:
1. Get invoices (you may need to paginate)
2. Filter in your code by `merchantInvoiceRefId`
3. Or use the invoice details endpoint if you have the invoice ID
### Use Case 4: Export for Accounting
**Scenario**: Export all invoices for a quarter
**Solution**:
1. Use date filters to get the quarter's invoices
2. Paginate through all results
3. Export to your accounting system
## Best Practices
1. **Use date filters**: Always filter by date range when possible to reduce response size
2. **Paginate large lists**: Don't try to get all invoices at once—use pagination
3. **Cache results**: If you're displaying invoices in a UI, cache the results
4. **Get details when needed**: Use the list for overview, details endpoint for specifics
5. **Handle empty results**: Your code should handle cases where no invoices match filters
## Common Questions
**Q: How do I get all invoices?** A: Don't specify any filters, but use pagination to get them in chunks. The default page size is 100.
**Q: What's the maximum page size?** A: 100 invoices per page. Use this for bulk operations, but smaller pages (25-50) are better for UI display.
**Q: How do I know if there are more pages?** A: If you get a full page (e.g., 25 invoices when pageSize=25), there might be more. Request the next page to check.
## Next Steps
* [**Get Invoice Details**](/docs/core-concepts/invoice/get-details-of-invoice-attempts) — Get detailed information about a specific invoice
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand what each invoice status means
* [**Invoice Export**](/docs/core-concepts/invoice/invoice-export) — Export invoices to CSV for reporting
***
# Invoice Export
Source: https://docs.revolv3.com/docs/core-concepts/invoice/invoice-export
Export invoices to CSV for reporting, accounting, and reconciliation. Learn how to use the invoice export feature in the Revolv3 portal.
## What is Invoice Export?
The **Invoice Export** feature lets you download a list of invoices as a CSV file. This is useful for:
* **Accounting**: Import invoices into your accounting software
* **Reporting**: Analyze payment data in Excel or Google Sheets
* **Reconciliation**: Match Revolv3 invoices with bank statements
* **Backup**: Keep local copies of invoice data
* **Analysis**: Perform custom analysis on payment data
**When to use it:**
* Monthly or quarterly reconciliation
* Generating financial reports
* Importing data into accounting systems
* Creating custom reports not available in the portal
* Archiving invoice data
> **Note**: Invoice Export is available through the Revolv3 Portal web interface. For programmatic access, use the [Get Invoices API](/docs/core-concepts/invoice/get-invoices-api).
## How to Export Invoices
### Step 1: Navigate to Invoice Export
1. Log in to the [Revolv3 Portal](https://portal.revolv3.com) (or [Sandbox Portal](https://portal-sandbox.revolv3.com) for testing)
2. Go to the **Operations** menu
3. Click **Invoice Export** in the navigation panel
### Step 2: Select Date Range
1. Use the date picker to specify the **start date** and **end date**
2. Choose the date range that covers the invoices you want to export
3. Make sure the range isn't too large
**Tip**: For large date ranges, export in smaller chunks (e.g., monthly) to avoid hitting file size limits.
### Step 3: Run the Export
1. Click the **"Run Report"** button
2. The system will process your request
3. A CSV file will be generated with all invoices in your date range
### Step 4: Download the File
1. Once the report is ready, you'll see a download option
2. Click to download the CSV file
3. Save it to your computer

## File Format
The exported file is in **CSV (Comma-Separated Values)** format, which can be opened in:
* Microsoft Excel
* Google Sheets
* Any text editor
* Most accounting software (with import)
**What's included:**
* Invoice IDs
* Amounts and dates
* Payment status
* Customer information (if available)
* Payment method details
* Transaction IDs
* Etc.
## Limitations and Considerations
### Date Range Considerations
* **Large ranges**: May take longer to process and generate larger files
* **Small ranges**: Faster processing, smaller files, easier to manage
* **Best practice**: Export monthly or quarterly for easier management
### Data Considerations
* **Real-time data**: Export reflects data at the time you run it
* **Historical data**: Includes all invoices in the date range, even if status changed later
* **Updates**: If you need updated data, run a new export
## Real-World Use Cases
### Use Case 1: Monthly Reconciliation
**Scenario**: Match your Revolv3 invoices with bank deposits each month
**Solution**:
1. Export invoices for the month
2. Import into Excel
3. Match with bank statement using transaction IDs
4. Identify any discrepancies
### Use Case 2: Accounting Import
**Scenario**: Import invoices into QuickBooks or other accounting software
**Solution**:
1. Export invoices for the period
2. Format the CSV to match your accounting software's import format
3. Import into your accounting system
4. Verify the import
### Use Case 3: Customer Analysis
**Scenario**: Analyze which customers pay on time, which payment methods are most successful, etc.
**Solution**:
1. Export invoices with customer information
2. Analyze in Excel
3. Identify patterns and trends
4. Use insights to improve your business
## Best Practices
1. **Export regularly**: Set a schedule (monthly, quarterly) for exports
2. **Keep backups**: Save exported files for your records
3. **Use appropriate date ranges**: Not too large (hits limits), not too small (too many files)
4. **Verify data**: Spot-check exported data against the portal
5. **Secure storage**: CSV files contain sensitive data—store them securely
## Alternative: Using the API
If you need programmatic access or more control:
* Use the [Get Invoices API](/docs/core-concepts/invoice/get-invoices-api) to fetch invoices
* Export to CSV in your own code
* Schedule automated exports
* Customize the data format
**When to use API instead:**
* Automated exports on a schedule
* Custom data formatting
* Integration with other systems
* More control over what data is included
## Common Questions
**Q: How often can I export?** A: As often as you need. There's no limit on how many times you can export.
**Q: Can I export specific invoices?** A: The portal export uses date ranges. For specific invoices, use the API or filter in Excel after export.
**Q: What if my file is too large?** A: Reduce the date range and export in smaller chunks (e.g., monthly instead of yearly).
**Q: Can I schedule automatic exports?** A: Not through the portal, but you can use the API to build automated exports.
**Q: What format is the CSV?** A: Standard CSV format with comma separators. Can be opened in Excel, Google Sheets, or any CSV reader.
## Next Steps
* [**Get Invoices API**](/docs/core-concepts/invoice/get-invoices-api) — Programmatic access to invoice data
* [**Get Invoice Details**](/docs/core-concepts/invoice/get-details-of-invoice-attempts) — Get detailed information about specific invoices
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand invoice statuses in your export
***
# Network Processing Types
Source: https://docs.revolv3.com/docs/core-concepts/invoice/network-processing-types
Understand how to classify transactions as initial, recurring, installment, or card-on-file payments. Learn why this matters and how it affects payment processing.
## What Are Network Processing Types?
**Network processing types** tell card networks (Visa, Mastercard, etc.) how to classify your transaction. This classification affects:
* **Fraud prevention**: Networks use this to detect suspicious patterns
* **Compliance**: Required for recurring payments and subscriptions
* **Success rates**: Proper classification can improve approval rates
* **Fees**: Some transaction types have different fee structures
**Why it matters**: Card networks have different rules and fraud detection for one-time purchases vs. recurring payments. Properly classifying transactions helps with compliance and can improve your payment success rates.
## Understanding Transaction Types
### Initial vs. Subsequent Transactions
**Initial transactions** are the first payment in a series:
* First payment in a subscription
* First payment in an installment plan
* One-time purchases
**Subsequent transactions** are follow-up payments:
* Monthly subscription charges (after the first)
* Installment payments (after the first)
* Recurring billing
**Why the distinction matters**: Card networks treat initial and subsequent payments differently for fraud detection and compliance. Initial payments require more authentication, while subsequent payments can be streamlined.
### Card-on-file transactions
A **card on file** payment uses a stored card credential. These payments are separate from a fixed subscription or installment series.
* **Cardholder-initiated (CIT)**: the cardholder is taking part in the payment. That includes the payment where they agree to store the card, and a later checkout with a card that is already saved.
* **Merchant-initiated (MIT)**: you charge a stored card later, without the cardholder taking part, under a prior agreement. Use this for unscheduled charges such as a balance top-up or a usage-based fee.
Scheduled subscription and installment payments still use `recurring` and `installment`.
## Network Processing Object
Include this object in your API request to specify the transaction type:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "recurring",
"originalNetworkTransactionId": "483299310358831"
}
}
```
### Processing Type Values
| Value | Integer | Who starts the payment | Credential | Use when | Do not use for |
| - | - | - | - | - | - |
| `initialRecurring` | `1` | - | - | First payment in a subscription or recurring billing series | Subsequent payments in the subscription. Use `recurring`. Not an installment plan or an unscheduled card-on-file charge. |
| `recurring` | `2` | - | - | Subsequent payments in a subscription (monthly, weekly, etc.) | The first payment in the subscription. Use `initialRecurring`. Not installment payments or unscheduled card-on-file charges. |
| `initialInstallment` | `3` | - | - | First payment in an installment plan ("buy now, pay later") | Subsequent payments in the installment plan. Use `installment`. Not a subscription or an unscheduled card-on-file charge. |
| `installment` | `4` | - | - | Subsequent payments in an installment plan | The first payment in the installment plan. Use `initialInstallment`. Not subscription payments or unscheduled card-on-file charges. |
| `initialCOF` | `7` | Cardholder | Stored on this payment | The cardholder pays and agrees to store the card for later unscheduled charges | The first payment of a subscription or installment plan. Use `initialRecurring` or `initialInstallment`. |
| `merchantInitiatedCOF` | `8` | Merchant | Already stored | The merchant charges a saved card without the cardholder, such as a top-up or a usage-based fee | Scheduled series payments. Use `recurring` or `installment`. |
| `cardholderInitiatedCOF` | `9` | Cardholder | Already stored | A returning cardholder pays with a saved card, such as one-click checkout | A charge the merchant starts without the cardholder |
**You can use either the string value** (e.g., `"recurring"`) **or the integer** (e.g., `2`). Both work the same way. String values are case-insensitive.
A value outside this table returns HTTP 400. The message names `processingType` and the allowed values.
`initialCOF`, `cardholderInitiatedCOF`, and `merchantInitiatedCOF` are supported on sale and authorization requests. They are not applied to subscriptions that Revolv3 bills for you, or to capture, refund, or void requests.
> [!NOTE]
>
> These three values are passed through to Worldpay. On other processors, Revolv3 accepts, stores, and returns the value you sent, and builds the processor request the same way it does for a payment sent without `processingType`.
### Original Network Transaction ID
The `originalNetworkTransactionId` links a later payment to an earlier network transaction. It is the `networkTransactionId` from that earlier payment.
Send it when you have it for:
* `recurring` payments (reference the first payment in the series)
* `installment` payments (reference the first payment in the series)
* `merchantInitiatedCOF` (reference the original stored-credential payment)
It is optional for `initialCOF` and `cardholderInitiatedCOF`. If you send it, Revolv3 stores it and passes it on.
**When to omit**:
* For `initialRecurring`, `initialInstallment`, or `initialCOF`, when there is no earlier network transaction
* For a one-time purchase that does not include `networkProcessing`
> **Note**: A `recurring` or `installment` payment without `originalNetworkTransactionId` can still be processed, but it may not be linked to the original transaction. A `merchantInitiatedCOF` payment without that ID is still sent as `merchantInitiatedCOF`. It is not converted into a one-time payment. Visa and Discover often require the original network transaction ID on a later stored-credential charge, so leaving it out can increase declines on those brands.
## When to Use Each Type
### One-Time Purchase
Use this when the cardholder pays once and you are not storing the card for later charges. **Don't include NetworkProcessing**:
```json theme={null}
{
"Invoice": {
"Amount": { "value": 10.00 }
}
// No NetworkProcessing needed for one-time purchases
}
```
### Subscription - First Payment
**Use `initialRecurring`**:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialRecurring",
"originalNetworkTransactionId": null // No original transaction yet
},
"Invoice": {
"Amount": { "value": 29.99 }
}
}
```
### Subscription - Monthly Charge
**Use `recurring` with original transaction ID**:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "recurring",
"originalNetworkTransactionId": "483299310358831" // From first payment
},
"Invoice": {
"Amount": { "value": 29.99 }
}
}
```
### Installment Plan - First Payment
**Use `initialInstallment`**:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialInstallment",
"originalNetworkTransactionId": null
},
"Invoice": {
"Amount": { "value": 100.00 }
}
}
```
### Installment Plan - Subsequent Payment
**Use `installment` with original transaction ID**:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "installment",
"originalNetworkTransactionId": "483299310358831" // From first payment
},
"Invoice": {
"Amount": { "value": 100.00 }
}
}
```
### Store a Card for Later Unscheduled Charges
**Use `initialCOF`** when the cardholder pays and agrees to store the card. This is not the first payment of a subscription or installment plan.
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialCOF",
"originalNetworkTransactionId": null
},
"Invoice": {
"Amount": { "value": 20.00 }
}
}
```
Save the `networkTransactionId` from the response. You send it later on `merchantInitiatedCOF` charges.
### Returning Customer, Saved Card
**Use `cardholderInitiatedCOF`** when the cardholder checks out with a card you already have on file. `originalNetworkTransactionId` is optional.
```json theme={null}
{
"NetworkProcessing": {
"processingType": "cardholderInitiatedCOF",
"originalNetworkTransactionId": null
},
"Invoice": {
"Amount": { "value": 45.00 }
}
}
```
### Merchant-Initiated Charge on a Saved Card
**Use `merchantInitiatedCOF`** for an unscheduled charge you start yourself, such as a wallet top-up. Include the network transaction ID from the original stored-credential payment when you have it.
```json theme={null}
{
"NetworkProcessing": {
"processingType": "merchantInitiatedCOF",
"originalNetworkTransactionId": "483299310358831"
},
"Invoice": {
"Amount": { "value": 15.00 }
}
}
```
## How to Get the Original Network Transaction ID
You'll receive `networkTransactionId` in the response from these endpoints:
* `POST /api/payments/sale` - One-time payment
* `POST /api/payments/sale/{paymentMethodId}` - Payment with stored method
* `POST /api/payments/authorization` - Authorize payment
* `POST /api/payments/authorization/{paymentMethodId}` - Authorize with stored method
* `POST /api/subscriptions` - Create subscription
**Example response**:
```json theme={null}
{
"networkTransactionId": "483299310358831", // ⭐ Save this for recurring payments
"invoiceId": 12345,
"invoiceStatus": "Paid"
}
```
You can also find it by getting invoice details:
* `GET /api/Invoices/{invoiceId}` - Returns `networkTransactionId` in the response
> **Important**: Each payment gets its own `networkTransactionId`. For recurring, installment, and merchant-initiated card-on-file payments, use the `networkTransactionId` from the **original payment** on later charges in that series.
Sale and authorization responses return the `processingType` you sent. Webhooks for those transactions include the same value.
## Important Limitations
> [!WARNING]
>
> **Please note:**
>
> * Processing types are **only applicable for card payments** (not ACH)
> * Processing types and original network transaction IDs work **only for Visa, Mastercard, and Discover** transactions
> * If the card brand for the original transaction doesn't match the current transaction, errors might occur (e.g., original was Visa, current is Mastercard)
**What this means:**
* ✅ Use for credit/debit cards
* ❌ Don't use for ACH payments
* ✅ Works for Visa, Mastercard, Discover
* ⚠️ May not work for American Express or other card brands
* ⚠️ Card brand must match between original and subsequent transactions
## Endpoints That Support Network Processing
You can include `NetworkProcessing` in these endpoints:
* `POST /api/payments/sale` - One-time payment
* `POST /api/payments/sale/{paymentMethodId}` - Payment with stored method
* `POST /api/payments/authorization` - Authorize payment
* `POST /api/payments/authorization/{paymentMethodId}` - Authorize with stored method
* `POST /api/subscriptions` - Create subscription (only `originalNetworkTransactionId` can be defined in the `paymentMethods` object)
`initialCOF`, `cardholderInitiatedCOF`, and `merchantInitiatedCOF` apply to the sale and authorization endpoints above. Do not send them on subscription, capture, refund, or void requests.
## Processor Support
This feature works with these processors:
* WorldPay
* Adyen
* Nuvei
* TSYS
* EPX
* JPMorgan (Paymentech)
* Paymentlync
* BridgePay
**What this means**: If your request includes `NetworkProcessing` and you're using a supported processor, the information will be passed to the processor. If you're using an unsupported processor, the object will be ignored (no error, it just won't be used).
`initialCOF`, `cardholderInitiatedCOF`, and `merchantInitiatedCOF` are passed through on Worldpay today. On the other processors in this list, the value is still accepted, stored, and returned, but the processor request is built as a one-time payment.
## Real-World Examples
### Example 1: Monthly Subscription
**First payment** (when customer signs up):
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialRecurring",
"originalNetworkTransactionId": null
}
}
```
**Response includes**: `"networkTransactionId": "483299310358831"`
**Second payment** (next month):
```json theme={null}
{
"NetworkProcessing": {
"processingType": "recurring",
"originalNetworkTransactionId": "483299310358831" // From first payment
}
}
```
### Example 2: Buy Now, Pay Later (4 Payments)
**First payment**:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialInstallment",
"originalNetworkTransactionId": null
}
}
```
**Response includes**: `"networkTransactionId": "123456789012345"`
**Subsequent payments** (months 2, 3, 4):
```json theme={null}
{
"NetworkProcessing": {
"processingType": "installment",
"originalNetworkTransactionId": "123456789012345" // From first payment
}
}
```
### Example 3: Usage-Based Charge on a Stored Card
The cardholder pays once and agrees to store the card:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "initialCOF",
"originalNetworkTransactionId": null
}
}
```
**Response includes**: `"networkTransactionId": "483299310358831"`
Later, you charge that saved card for usage, without the cardholder taking part:
```json theme={null}
{
"NetworkProcessing": {
"processingType": "merchantInitiatedCOF",
"originalNetworkTransactionId": "483299310358831"
}
}
```
If that same cardholder comes back and checks out with the saved card, send `cardholderInitiatedCOF` instead.
## Best Practices
1. **Store network transaction IDs**: When you get a `networkTransactionId` from the first payment, save it for later recurring, installment, and `merchantInitiatedCOF` charges
2. **Use the right type**: Match the processing type to who starts the payment and whether the card is being stored now or is already on file
3. **Link properly**: Include `originalNetworkTransactionId` for `recurring`, `installment`, and `merchantInitiatedCOF` payments when you have it
4. **Check processor support**: The card-on-file values are passed through on Worldpay. On other processors the value is stored and returned, and the processor request is built as a one-time payment
5. **Match card brands**: Ensure the card brand matches between original and subsequent transactions
## Common Questions
**Q: Do I have to use network processing types?**
A: No, they're optional. But using them correctly can improve success rates and compliance, especially for subscriptions.
**Q: What if I don't have the original network transaction ID?**
A: You can still process the payment, but it may not be properly linked in the card network's system. Try to get and store it from the first payment.
**Q: Can I use this for ACH payments?**
A: No, this feature is only for card payments (credit/debit cards).
**Q: What if I use the wrong type?**
A: The payment will still process, but it may not be classified correctly by the card network, which could affect fraud detection or compliance.
**Q: Which value do I use for a saved card?**
A: Use `initialCOF` on the payment where the cardholder agrees to store the card. Use `cardholderInitiatedCOF` when that cardholder later pays with the saved card. Use `merchantInitiatedCOF` when you charge the saved card yourself, outside a fixed schedule. Keep using `recurring` or `installment` for scheduled series payments.
**Q: What if I don't have a network transaction ID for a merchant-initiated card-on-file charge?**
A: You can still send `merchantInitiatedCOF`. Revolv3 does not convert that request into a one-time payment. Include the original network transaction ID when you have it. Visa and Discover often require it, and leaving it out can increase declines on those brands.
**Q: Do the card-on-file values work on every processor?**
A: They are passed through on Worldpay. On other processors, Revolv3 accepts, stores, and returns the value, and sends the processor request as a one-time payment.
## Next Steps
* **[Create a Subscription](/docs/core-concepts/subscription/create-subscription)** — See how processing types work with subscriptions
* **[Make a Payment](/docs/getting-started/make-a-payment)** — Learn how to include network processing in payment requests
* **[Get Invoice Details](/docs/core-concepts/invoice/get-details-of-invoice-attempts)** — Find network transaction IDs in invoice responses
***
# Processor Raw Response
Source: https://docs.revolv3.com/docs/core-concepts/invoice/processor-raw-response
Learn how to retrieve detailed raw responses from payment processors for debugging, auditing, and accessing processor-specific codes and messages.
## What is Processor Raw Response?
The **processor raw response** is the complete, unprocessed response from the payment processor (WorldPay, Adyen, Nuvei, etc.). It contains detailed information that's not included in Revolv3's simplified response, including:
* Processor-specific transaction IDs
* Detailed fraud check results
* AVS (Address Verification System) results
* Processor-specific error codes
* Additional metadata and flags
**When to use it:**
* **Debugging**: Understanding exactly what the processor returned
* **Auditing**: Keeping detailed records of processor responses
* **Processor-specific logic**: When you need processor-specific codes or data
* **Support**: Providing detailed information when contacting support
* **Reconciliation**: Matching with processor reports using processor transaction IDs
> **Note**: Raw responses are optional and increase response size. Only request them when you need the detailed information.
## Important: Raw Response Format
The `rawResponse` is returned as an **escaped JSON string**, not a JSON object. This means it looks "ugly" with backslashes:
```json theme={null}
"rawResponse": "{\"cnpTxnId\":84083493722313344,\"orderId\":\"319214\",\"response\":\"000\"...}"
```
**You must parse it** in your code to use it effectively.
## Enabling Raw Processor Responses
To include the raw processor response, add this parameter to your request:
```json theme={null}
{
"includeRawProcessorResponse": true
}
```
### In Payment Requests
Add it to payment-related endpoints:
* `POST {{Api Root}}/api/payments/sale`
* `POST {{Api Root}}/api/payments/sale/{paymentMethodId}`
* `POST {{Api Root}}/api/payments/authorization`
* `POST {{Api Root}}/api/payments/capture/{paymentMethodAuthorizationId}`
### In Invoice Retrieval
Add it as a query parameter:
```
GET {{Api Root}}/api/Invoices/{invoiceId}?includeRawProcessorResponse=true
```
Replace `{{Api Root}}` with `api.revolv3.com` (production) or `api-sandbox.revolv3.com` (sandbox).
## Example: Payment with Raw Response
### Request
```json theme={null}
{
"IncludeRawProcessorResponse": true,
"NetworkProcessing": {
"ProcessingType": "initialInstallment",
"OriginalNetworkTransactionId": null
},
"CustomerId": null,
"PaymentMethod": {
"BillingAddress": {
"AddressLine1": "100 Main St",
"City": "Los Angeles",
"State": "CA",
"PostalCode": "90210",
"Country": "USA"
},
"BillingFirstName": "John",
"BillingLastName": "Doe",
"CreditCard": {
"PaymentAccountNumber": "4444333322221111",
"ExpirationDate": "1130",
"SecurityCode": "214"
}
},
"Invoice": {
"MerchantInvoiceRefId": "ABC12345DProbVs1",
"Amount": {
"Value": 0.13
}
}
}
```
### Response (Success)
The `rawResponse` field contains the escaped JSON string:
```json theme={null}
{
"CustomerId": null,
"InvoiceId": 319214,
"MerchantInvoiceRefId": "ABC12345DProbVs1",
"NetworkTransactionId": "241815930449764",
"InvoiceStatus": "Paid",
"InvoiceAttemptStatus": "Success",
"Message": "Approved",
"Amount": {
"Currency": "USD",
"Value": 0.13
},
"PaymentMethodId": 12310,
"RawResponse": "{\"cnpTxnId\":84083493722313344,\"orderId\":\"319214\",\"response\":\"000\",\"responseTime\":\"2024-11-19T19:12:16\",\"message\":\"Approved\",\"cardSuffix\":\"1111\",\"authCode\":\"123457\",\"fraudResult\":{\"avsResult\":\"00\"}...}"
}
```
### Parsing the Raw Response
**Before parsing** (escaped string):
```json theme={null}
"RawResponse": "{\"cnpTxnId\":84083493722313344,\"response\":\"000\"...}"
```
**After parsing** (structured object):
```json theme={null}
{
"CnpTxnId": "84083493722313344",
"OrderId": "319214",
"Response": "000",
"ResponseTime": "2024-11-19T19:12:16",
"Message": "Approved",
"CardSuffix": "1111",
"AuthCode": "123457",
"FraudResult": {
"AvsResult": "00"
}
}
```
### Response (Failure)
For a failed transaction, the raw response includes the decline reason:
```json theme={null}
{
"InvoiceStatus": "Noncollectable",
"InvoiceAttemptStatus": "Fail",
"Message": "Insufficient Funds",
"RawResponse": "{\"cnpTxnId\":83997868055145032,\"orderId\":\"474126\",\"response\":\"110\",\"message\":\"Insufficient Funds\"...}"
}
```
**After parsing**, you can see `"response": "110"` which corresponds to "Insufficient Funds" in WorldPay's documentation.
## How to Parse Raw Responses
### JavaScript/Node.js
```javascript theme={null}
const response = await makePaymentRequest();
const rawResponse = JSON.parse(response.rawResponse);
console.log(rawResponse.response); // "000"
console.log(rawResponse.message); // "Approved"
```
### Python
```python theme={null}
import json
response = make_payment_request()
raw_response = json.loads(response['rawResponse'])
print(raw_response['response']) # "000"
print(raw_response['message']) # "Approved"
```
### C\#
```csharp theme={null}
var response = await MakePaymentRequest();
var rawResponse = JsonSerializer.Deserialize(response.RawResponse);
var responseCode = rawResponse["response"].ToString(); // "000"
```
## Understanding Processor Response Fields
**Processor-specific**: Each processor has its own field names and codes. Refer to your processor's documentation for specific meanings.
## When to Use Raw Responses
### Use Raw Responses When:
* **Debugging payment issues**: Need to see exactly what the processor returned
* **Processor-specific logic**: Building logic based on processor codes
* **Detailed auditing**: Need complete records for compliance
* **Reconciliation**: Matching with processor reports using processor transaction IDs
* **Support requests**: Providing detailed information to Revolv3 support
### Don't Use Raw Responses When:
* **Simple integrations**: Revolv3's simplified response is usually enough
* **Performance sensitive**: Raw responses increase response size
* **You don't need the details**: If `invoiceAttemptStatus` are sufficient
## Best Practices
1. **Always parse**: Treat `rawResponse` as a string and parse it—don't try to use it as an object
2. **Handle parsing errors**: Wrap parsing in try/catch—malformed JSON can break your code
3. **Use sparingly**: Only request when needed—it increases response size
4. **Fallback to simplified**: If parsing fails, use Revolv3's fields as a fallback
## Processor-Specific Codes
Each processor has its own response codes. Common examples:
### WorldPay
* `"000"`: Approved
* `"110"`: Insufficient Funds
* `"200"`: Generic Decline
### Adyen
* `"Authorised"`: Approved
* `"Refused"`: Declined
* Various refusal reasons
**Refer to your processor's documentation** for complete code lists and meanings.
## Common Questions
**Q: Do I have to parse the raw response?** A: Yes, it's returned as an escaped JSON string. You must parse it to use the data.
**Q: What if parsing fails?** A: Log the raw string and use Revolv3's fields as a fallback. Check processor documentation for format changes.
**Q: Should I always request raw responses?** A: No, only when you need the detailed information. It increases response size and processing time.
**Q: Can I use raw responses for all processors?** A: Yes, but the format and fields vary by processor. Check your processor's documentation for specifics.
**Q: Is raw response data sensitive?** A: It may contain transaction details.
## Next Steps
* [**Get Invoice Details**](/docs/core-concepts/invoice/get-details-of-invoice-attempts) — See how to get raw responses for existing invoices
* [**Error Responses**](/docs/error-codes/error-responses) — Understand how to handle API errors
* [**Make a Payment**](/docs/getting-started/make-a-payment) — See how to include raw response in payment requests
***
# Merchant Settings
Source: https://docs.revolv3.com/docs/core-concepts/merchants/merchant-setting
Understand merchant-level settings that affect how payments are processed. Learn about defaults, processor configuration, and feature toggles.
## What are Merchant Settings?
**Merchant Settings** are account-level configuration options that control how Revolv3 processes payments for your merchant account. They provide defaults and enable/disable features across all your transactions.
**Why they matter:**
* **Set defaults**: Values used when you don't specify them in API requests
* **Enable features**: Turn on/off features like network tokenization, ACH Verification Service, etc.
* **Configure behavior**: Control how payments are processed, retried, and handled
* **Security**: Configure trusted domains, etc.
## Key Settings Overview
### Order Processing Channel (Merchant Details section)
**What it is**: Defines how the transaction is being processed (e-commerce, mail order, etc.)
**Default behavior**: Used as a fallback when an invoice doesn't specify `orderProcessingChannel`
**When you need it**: Typically only if you have processor-specific requirements
**Options**: `ECOMMERCE` (default), `MOTO` (Mail Order/Telephone Order)
### Payment Processor
**What it is**: Which payment processor (WorldPay, Adyen, Nuvei, etc.) handles transactions by default
**Why it matters**: Determines which processor is used
**Configure in**: Merchant Settings in the portal
### Dynamic Descriptor
**What it is**: Default text that appears on customer credit card statements
**Default behavior**: Applied to all transactions unless overridden on individual invoices
**Example**: "ACME STORE" appears on all customer statements
**Learn more**: [Dynamic Descriptor Guide](/docs/core-concepts/invoice/dynamic-descriptor-guide)
### Trusted Hostnames / Checkout Origins
**What it is**: Domains allowed to create checkout sessions and load hosted/embedded checkout
**Why it matters**: Security feature—only authorized domains can use checkout
**Configure in**: Merchant Settings → Integration Profile → Trusted Checkout Hostnames
**Learn more**: [Checkout Guide](/docs/checkout/checkout)
## Processor Settings
Processor configuration determines which processor(s) handle your transactions:
**What's configured**:
* Processor credentials (API keys, merchant IDs)
* Merchant codes
* Descriptor defaults
* Processor-specific toggles (like Account Updater)
**Where to configure**: Merchant dashboard (Settings → Merchant Settings → Processor Settings)
**Note**: Processor-specific IDs and configuration screens are managed
## Feature Toggles
### Network Tokenization
**What it does**: When enabled, credit card details are tokenized. The resulting network token is retained for future transactions.
**Why enable it**:
* Better security
* Higher approval rates
* Cards stay current automatically
**How to enable**: Merchant Settings → Network Tokenization
**Also requires**: Enable token usage in processor configuration
### Eligibility Check
**What it does**: Performs additional verification before processing payments
**When to use**: Useful for validating subscription continuity in your system
**How it works**: Revolv3 checks eligibility before processing payment
**Configure in**: Merchant Settings → Eligibility Check
### ACH Verification Service
**What it does**: Selects which ACH verification provider to use (GIACT or WorldPay)
**Why it matters**: Different providers have different verification capabilities
**Options**: GIACT or WorldPay (only one can be active)
**Configure in**: Merchant Settings → ACH Verification Service
**Learn more**: [Test ACH Verification](/docs/testing-sandbox/test-ach-for-validate-person)
### Recurring Strategies
**What it does**: Defines how recurring payments are handled (scheduling, retry logic, etc.)
**Includes**:
* When to retry failed payments
* How many times to retry
* Retry timing (immediate, after 1 day, after 3 days, etc.)
**Prerequisite**: Configure a payment processor before adding a recurring strategy
**Configure in**: Merchant Settings → Recurring Strategies
### Recycle Strategies
**What it does**: Handles automatic retries for failed card payments
**How it works**:
* Revolv3 attempts up to **15 retries** for failed card/debit transactions
* Only applies to **soft declines** (hard declines are not retried)
* **One-time payments and ACH are not recycled**
**Behavior**: Follows the configured recurring strategy rules
**Configure in**: Merchant Settings → Recycle Strategies
**Learn more**: [Subscription Status and Recycling](/docs/integration-flows/subscription-status-recycling)
### Shopify Store Domains
**What it does**: Manages connected Shopify store domains
**When to use**: If you're integrating with Shopify
**Configure in**: Merchant Settings → Shopify Store Domains
## How Settings Work as Fallbacks
### Invoice-Level Overrides
Many merchant settings act as **fallbacks** when you don't specify values in API requests.
**Example**: If you don't set `orderProcessingChannel` on an invoice, Revolv3 uses the merchant setting value.
**Benefits**:
* Simpler API requests (don't need to specify everything)
* Consistent defaults across all transactions
* Easy to change defaults without updating code
### Example: Order Processing Channel
**Merchant setting**: `orderProcessingChannel: "ECOMMERCE"`
**Invoice request** (without specifying channel):
```json theme={null}
{
"Invoice": {
"Amount": { "value": 10.00 }
}
// No orderProcessingChannel specified
}
```
**Result**: Invoice uses "ECOMMERCE" from merchant settings
**Invoice request** (with channel specified):
```json theme={null}
{
"Invoice": {
"Amount": { "value": 10.00 },
"OrderProcessingChannel": "MOTO" // Overrides merchant setting
}
}
```
**Result**: Invoice uses "MOTO" (overrides the default)
## Best Practices
1. **Set sensible defaults**: Configure merchant settings to match your typical use case
2. **Override when needed**: You can still override settings on individual invoices
3. **Review periodically**: Check settings to ensure they match your business needs
4. **Document your settings**: Keep notes on what settings you've configured and why
## Common Questions
**Q: Do I have to set all merchant settings?** A: No, only set what you need. Defaults are provided for most settings.
**Q: Can I override merchant settings on individual invoices?** A: Yes, many settings can be overridden per-invoice.
**Q: Where do I configure processors?** A: In the portal under Merchant Settings → Processors.
**Q: How do I know what settings are available?** A: Check the portal (Merchant → Settings) or use the **help icon** in the portal to submit a support ticket.
## Next Steps
* [**Order Processing Channels**](/docs/core-concepts/merchants/order-processing-channels) — Learn about processing channels
* [**Dynamic Descriptors**](/docs/core-concepts/invoice/dynamic-descriptor-guide) — Understand statement descriptors
* [**Checkout**](/docs/checkout/checkout) — Learn about trusted hostnames for checkout
***
# Order Processing Channel
Source: https://docs.revolv3.com/docs/core-concepts/merchants/order-processing-channels
Learn about order processing channels (e-commerce vs mail/telephone order). Understand when to use each channel and how it affects payment processing.
## What is Order Processing Channel?
**Order processing channel** tells the payment processor how the customer provided their payment information. This affects how the transaction is processed and can impact fees, fraud checks, and compliance requirements.
**Why it matters:**
* **Different fees**: Some channels have different processing fees
* **Fraud prevention**: Processors handle fraud differently based on channel
* **Compliance**: Some regulations vary by channel
* **Processor requirements**: Some processors require this information
## Available Channels
| Channel | What It Means | When to Use |
| - | - | - |
| `ecommerce` | Internet or electronic commerce transactions | Online payments, website checkout, mobile app payments |
| `moto` | Mail Order / Telephone Order transactions | Customer provides card details over phone or mail |
## When to Use Each Channel
### E-Commerce (Default)
**`Use ecommerce for:`**
* Website checkout
* Mobile app payments
* Online purchases
* Digital payments
* Most standard online transactions
**This is the default** for most merchants.
For e-commerce transactions, you can optionally provide the **eCommercePlatformUrl** - merchant's storefront URL from which the transaction originates. This is sent to the payment processor to identify the originating platform.
This field follows a fallback chain:
1. **Invoice-level value** — if **eCommercePlatformUrl** is included in the invoice, this value is used.
2. **Merchant Settings default** — if no invoice-level value is provided, the E-Commerce Platform URL configured in Merchant Details is used.
3. **Not sent** — if neither is available, the request is sent to TSYS without the Acceptor URL Address.
### MOTO (Mail Order / Telephone Order)
**`Use moto for:`**
* Customer calls to place order
* Customer mails in payment
* Customer service representative takes payment over phone
* Manual order entry scenarios
**When NOT to use**: Regular online checkout (use `ecommerce` instead)
## Processor Support
**Important**: Order processing channel is **currently only applicable to WorldPay, TSYS and BridgePay merchants**.
**For other processors**: The default value (`ecommerce`) is used automatically, and specifying a channel may be ignored.
## How to Specify Channel
### In Invoice Object
Include `orderProcessingChannel` in your invoice when creating a payment:
```bash bash theme={null}
{
"Invoice": {
"merchantInvoiceRefId": "123456789",
"orderProcessingChannel": "moto",
"Amount": {
"currency": "USD",
"value": 30.99
}
}
}
```
### Default Behavior
**If you don't specify** `orderProcessingChannel`:
* **Supported processors merchants**: Uses the value from **Merchant Settings**
* **Other processors**: Uses default (`ecommerce`)
**This field is optional**—you can omit it and use the merchant setting default.
## Merchant Settings Default
You can set a default order processing channel in Merchant Settings:
1. Go to **Merchant Settings (Merchant Details)** in the portal
2. Set the default `orderProcessingChannel` and fill out the `eCommercePlatformUrl`
3. All invoices without a specified channel will use this default
**Benefits**:
* Don't need to specify on every invoice
* Consistent across all transactions
* Easy to change for all future transactions

## Real-World Examples
### Example 1: Online Checkout (E-Commerce)
**Scenario**: Customer buys product on your website
**Request**:
```json theme={null}
{
"Invoice": {
"orderProcessingChannel": "ecommerce", // Or omit to use default
"EcommercePlatformUrl" : "revolv3.com" // Optional parameter
"Amount": { "value": 99.99 }
}
}
```
### Example 2: Phone Order (MOTO)
**Scenario**: Customer calls to place order, representative enters payment
**Request**:
```json theme={null}
{
"Invoice": {
"orderProcessingChannel": "moto", // Must specify for MOTO
"Amount": { "value": 99.99 }
}
}
```
## Best Practices
1. **Use ecommerce by default**: Unless you have a specific MOTO use case
2. **Set merchant default**: Configure default in merchant settings for consistency
3. **Override when needed**: Specify channel on invoices that differ from default
4. **Processor-specific**: Order processing channel currently applies to **WorldPay, TSYS, and BridgePay** merchants
## Common Questions
**Q: Do I need to specify this for every payment?** A: No, it's optional. If omitted, it uses the merchant setting default.
**Q: Can I use MOTO for online payments?** A: No, use the correct channel. MOTO is only for mail/telephone orders.
**Q: Does this affect fees?** A: It can—different channels may have different fee structures. Check with your processor.
**Q: What if I'm not using WorldPay, TSYS, or BridgePay?** A: The channel setting is ignored for other processors (ecommerce is used by default).
## Next Steps
* [**Merchant Settings**](/docs/core-concepts/merchants/merchant-setting) — Learn about setting defaults
* [**Make a Payment**](/docs/getting-started/make-a-payment) — See how to include order processing channel in payments
***
# Account Updater
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/account-updater
Learn how Account Updater automatically keeps stored credit card information current. Understand when cards are updated and how to handle update notifications.
## What is Account Updater?
**Account Updater** is a service that automatically updates stored credit card information when cards are:
* **Replaced**: Customer gets a new card (lost, stolen, expired)
* **Expired**: Card expiration date changes
* **Updated**: Bank changes card details
**Why it's useful:**
* **Reduces failed payments**: Cards stay current even when customers don't update them
* **Better for subscriptions**: Recurring payments continue working
* **Less customer friction**: Customers don't need to manually update expired cards
* **Higher success rates**: More payments go through successfully
**How it works**: When you process a payment, the processor checks with the card network to see if the card has been updated. If it has, Revolv3 automatically updates your stored payment method with the new information.
## When Account Updater Runs
Account Updater checks for updates:
* **During payment processing**: When you charge a stored payment method
* **Automatically**: Revolv3 handles it—you don't need to do anything
* **Periodically**: Processors check with card networks for updates
**You'll know an update happened** when you see `accountUpdateMessage` and `accountUpdateDateTime` in the payment response.
## Understanding Account Update Notifications
When Account Updater updates a card, you'll see additional fields in the payment response:
```json theme={null}
{
"customerId": null,
"invoiceId": 185317,
"merchantInvoiceRefId": "ABC309500654810",
"networkTransactionId": "538302743384089",
"invoiceStatus": "Paid",
"invoiceAttemptStatus": "Success",
"message": "Approved",
"amount": {
"currency": "USD",
"value": 1.03
},
"paymentMethodId": 6061,
"paymentMethodTypeId": 1,
"paymentProcessor": "WorldPay",
"paymentMethodCreditCardDetails": {
"binNumber": "444433",
"paymentLast4Digit": "1111",
"paymentExpirationDate": "1130", // Updated expiration date
"accountUpdateMessage": "NEW_EXPIRY", // Indicates what was updated
"accountUpdateDateTime": "2025-10-30T11:46:33" // When it was updated
}
}
```
## WorldPay Account Updater Response Codes
If you're using WorldPay, you may also see response codes with account update notifications:
| Code | Response Message | What It Means | Recommendation |
| - | - | - | - |
| `500` | The account number was changed | Card number was updated | Use the new account number from the response |
| `501` | The account was closed | Account is closed | Contact customer to collect new payment details |
| `502` | The expiration date was changed | Expiration date updated | Update stored expiration date (Revolv3 does this automatically) |
| `504` | Contact the cardholder for updated information | Bank requires contacting customer | Prompt customer to provide updated payment details |
| `507` | Cardholder has opted out of the update program | | |
**Reference**: [WorldPay Account Updater Documentation](https://docs.worldpay.com/apis/wpg/usdomesticacquiring/managedaccountupdater)
## How to Handle Account Updates
### Automatic Updates (Recommended)
**Revolv3 handles updates automatically**—you don't need to do anything special. When Account Updater updates a card:
* Revolv3 updates the stored payment method
* Future payments use the updated information
* You're notified via `accountUpdateMessage` in the response
**What you should do:**
* **Log the update**: Store `accountUpdateMessage` and `accountUpdateDateTime` for your records
* **Notify customer** (optional): Let them know their card was updated automatically
* **Handle special cases**: Contact the customer
## Real-World Scenarios
### Scenario 1: Card Expiration Updated
**What happens:**
1. Customer's card expires (old: 03/25, new: 03/26)
2. You charge the stored payment method
3. Account Updater detects the new expiration
4. Revolv3 updates the stored payment method automatically
5. Payment succeeds with the updated expiration
**Response shows:**
```json theme={null}
{
"accountUpdateMessage": "NEW_EXPIRY",
"accountUpdateDateTime": "2025-10-30T11:46:33",
"paymentExpirationDate": "0326" // Updated date
}
```
**What you do**: Revolv3 handled it. Just log it for your records.
### Scenario 2: Card Replaced
**What happens:**
1. Customer's card was lost/stolen and replaced
2. New card has a new number
3. Account Updater detects the change
4. Revolv3 updates the stored payment method
**Response shows:**
```json theme={null}
{
"accountUpdateMessage": "UPDATE",
"paymentLast4Digit": "2222" // New last 4 digits
}
```
**What you do**:
* Log the update
* Optionally notify customer that their card was updated
* Future payments will use the new card automatically
### Scenario 3: Account Closed
**What happens:**
1. Customer closed their account with the bank
2. Account Updater detects it
3. Payment may fail or be declined
**Response shows:**
```json theme={null}
{
"accountUpdateMessage": "CLOSED"
}
```
**What you do**:
* Contact the customer
* Ask for a new payment method
* Update your records
* For subscriptions, pause until customer updates
## Best Practices
1. **Monitor account updates**: Log `accountUpdateMessage` to track when cards are updated
2. **Handle closed accounts**
3. **Notify customers**: Optionally notify customers when their card is automatically updated
4. **Keep records**: Store update timestamps for auditing
5. **Note**: Most updates are automatic and don't require action
## Processor Support
Account Updater is supported by:
* **WorldPay**: Batch and real-time support, with detailed response codes
* **Adyen**: Batch and real-time support
* **Paymentech (JPMorgan)**: Real-time support
**In sandbox**: Account Updater is only supported by WorldPay. Other processors may not show account updates in sandbox.
## Common Questions
**Q: Do I need to do anything when a card is updated?** A: Usually no—Revolv3 handles it automatically. Just log the update for your records.
**Q: What if the account is closed?** A: Contact the customer to get a new payment method. The old one won't work anymore.
**Q: How often does Account Updater check?** A: It checks during payment processing. There's no separate "check" you need to run.
**Q: Can I disable Account Updater?** A: It's automatic and beneficial—there's usually no reason to disable it. Contact Revolv3 if you have specific concerns.
**Q: What if I don't see account update messages?** A: Either no update was needed, or your processor doesn't support Account Updater. Check with Revolv3.
## Next Steps
* [**Payment Methods Guide**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Learn about storing payment methods
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — See how Account Updater helps with recurring payments
* [**Make a Payment**](/docs/getting-started/make-a-payment) — See account update fields in payment responses
***
# ACH Direct Debit Payments
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/ach-direct-debit
Learn what ACH is, why it takes days to process, and when to use it. Perfect for recurring bills, subscriptions, and large transactions where the delay is acceptable.
## What is ACH?
**ACH (Automated Clearing House)** is a system for transferring money directly between bank accounts. Instead of using a credit card, customers provide their bank account number and routing number, and you withdraw money directly from their checking or savings account. It is commonly used for recurring billing, subscriptions, and invoice payments.
**Note:** ACH Direct Debit is **not a real-time transaction**. Funds settlement typically takes several business days, and transaction status may remain pending for a period of time.
## Why Use ACH Instead of Credit Cards?
**Advantages:**
* **Lower fees**: ACH typically costs much less than credit card processing fees (often just a few cents vs. 2-3% for cards)
* **Better for large amounts**: No percentage-based fees means ACH is great for large transactions
* **Recurring billing**: Perfect for subscriptions, monthly bills, and recurring payments
* **No chargebacks**: ACH has different dispute rules than credit cards (though customers can still reverse payments)
**Disadvantages:**
* **Not instant**: Takes 1-5 business days to process (unlike credit cards which are immediate)
* **Can fail silently**: You might not know if it failed for several days
* **Requires bank account info**: Customers need to provide routing and account numbers
## When to Use ACH
**Good use cases:**
* **Recurring bills**: Monthly subscriptions, utility bills, membership fees
* **Large transactions**: Where credit card fees would be expensive
* **B2B payments**: Business-to-business transactions
* **Customers who prefer it**: Some customers prefer bank transfers over credit cards
**Not ideal for:**
* **Instant purchases**: E-commerce where customers expect immediate confirmation
* **Small one-time purchases**: Credit cards are usually easier for customers
* **When you need immediate funds**: If you need money right away, use credit cards
## Why Does ACH Take Days?
Unlike credit cards (which are processed instantly through card networks), ACH uses a **batch processing system**. Here's why it takes time:
1. **Batches are processed in groups**: Banks don't process ACH transactions one-by-one. They collect transactions throughout the day and process them in batches (usually overnight).
2. **Multiple banks involved**: Your bank, the customer's bank, and the ACH network all need to coordinate. This takes time.
3. **Business days only**: ACH doesn't process on weekends or holidays. If you submit on Friday, it might not process until Monday or Tuesday.
4. **Verification time**: Banks need time to verify the account exists, has sufficient funds, and isn't frozen.
**Typical timeline:**
* **Day 1**: You submit the ACH request → Status: `Pending`
* **Day 2-3**: Banks process the batch → Still `Pending`
* **Day 3-5**: Final confirmation → Status changes to `Paid` or `Noncollectable`
## The ACH Object
To process an ACH payment, you need to collect the customer's bank account information:
```json theme={null}
{
"RoutingNumber": "021000021",
"AccountNumber": "1234567890",
"AccountType": "Checking"
}
```
### Understanding the Fields
| **Field** | **Description** |
| - | - |
| `routingNumber` | The 9-digit routing number that identifies the customer's bank. This is the same number printed on the bottom of checks. You can find it on the customer's check or they can look it up online. |
| `accountNumber` | The customer's bank account number (4-17 characters). This is their actual account number. |
| `accountType` | Bank account type. Either `"Checking"` or `"Savings"`. Most ACH payments use checking accounts, but savings accounts work too. |
> **Security Note**: Bank account information is sensitive. Make sure you're using HTTPS, storing it securely, and following PCI-like security practices. Consider using Revolv3's payment method storage (tokenization) so you don't have to store account numbers yourself.
## ACH Transaction Lifecycle
ACH transactions go through a predictable lifecycle. Understanding this helps you build a better user experience:
### 1. Pending (Initial Status)
**What it means**: The ACH request has been submitted to the bank, but we haven't received final confirmation yet.
**When you'll see it**: Immediately after submitting the payment, and for the next 1-5 business days.
**What to do**:
* Show a "processing" message to the customer
* Don't fulfill the order yet—wait for confirmation
* Set up webhooks to be notified when status changes
**How long**: Typically 1-5 business days (longer if there's a weekend or holiday)
### 2. Paid (Success)
**What it means**: The bank successfully processed the ACH and money has been withdrawn from the customer's account.
**When you'll see it**: After 1-5 business days, when the bank confirms the transaction succeeded.
**What to do**:
* Show success message to customer
* Fulfill the order (ship product, activate service, etc.)
* Update your records
**Business impact**: Money is in your account (or will be after settlement). You can proceed with fulfillment.
### 3. Noncollectable (Failed)
**What it means**: The ACH failed and money was not withdrawn. The bank rejected the transaction.
**When you'll see it**: After 1-5 business days, when the bank confirms the transaction failed.
**Common reasons**:
* Insufficient funds in customer's account
* Invalid account number or routing number
* Account is closed or frozen
* Customer's bank rejected it for fraud prevention
**What to do**:
* Notify the customer that payment failed
* Ask them to try a different payment method or update their bank account
* For subscriptions, you might pause the subscription and notify them
**Business impact**: No money was collected. You'll need to collect payment another way.
### 4. RefundPending (For Refunds)
**What it means**: You issued a refund via ACH, and it's being processed.
**When you'll see it**: After you submit a refund request, while it's being processed.
**What to do**: Wait for it to complete. It will change to a final status once processed.
## Webhooks: Essential for ACH
Since ACH takes days to process, you **must** use webhooks to know when the status changes. You can't just check the status immediately after submitting—you need to wait for the bank to process it.
**`Set up the InvoiceStatusChanged webhook`** to receive notifications when:
* ACH payment succeeds (`Paid`)
* ACH payment fails (`Noncollectable`)
* Status changes for any reason
Without webhooks, you'd have to constantly poll the API to check status, which is inefficient and can miss updates.
> **Important**: Always implement webhooks for ACH payments. Don't rely on checking status immediately—it will still be `Pending` for days.
## Account Verification: Verify Before You Charge
Before processing an ACH payment, it's **highly recommended** to verify the bank account. This helps:
* Reduce fraud
* Prevent failed transactions
* Catch invalid account numbers early
### How Verification Works
1. **Choose a verification provider** in the Revolv3 portal (Settings → Merchant Settings):
* **GIACT**: Validates account ownership and status
* **Worldpay**: Alternative verification provider


**Call the verification API** before processing the payment
2. **Check the response**: If verification fails, don't proceed with the debit
3. **If verification passes**: Proceed with confidence (though it's still not 100% guaranteed to succeed)
> **Best Practice**: Always verify accounts before the first ACH payment, especially for recurring billing. It saves you and your customers time and frustration.
[View account verification API documentation](https://docs.revolv3.com/api-reference/)
## Processing Time: What to Expect
ACH is a **batch-based system**, which means:
* **Transactions are grouped**: Banks collect ACH requests throughout the day and process them in batches (usually overnight)
* **Business days only**: No processing on weekends or federal holidays
* **Multiple steps**: Your bank → ACH network → customer's bank → confirmation back to you
**Realistic timeline:**
* **Submitted Monday**: Might process Tuesday-Wednesday
* **Submitted Friday**: Might not process until Monday-Tuesday (skips weekend)
* **Holiday week**: Could take longer
**Best practice**: Tell customers upfront that ACH takes 1-5 business days. Set expectations so they're not surprised.
## Real-World Example: Monthly Subscription
Let's walk through a subscription service that bills monthly via ACH:
### Day 1: Billing Date
**You submit the ACH payment:**
```bash theme={null}
POST /api/Payments/sale
{
"PaymentMethod": {
"ACH": {
"RoutingNumber": "021000021",
"AccountNumber": "1234567890",
"AccountType": "Checking"
}
},
"Invoice": {
"Amount": { "Value": 29.99 }
}
}
```
**Response:**
```json theme={null}
{
"InvoiceStatus": "Pending",
"InvoiceAttemptStatus": "Pending"
}
```
**What you do:**
* Show customer: "Your payment is processing (takes 1-5 business days)"
* Set up webhook listener for status changes
* Don't activate/extend their subscription yet
### Day 3: Payment Succeeds
**Webhook notification arrives:**
```json theme={null}
{
"Event": "InvoiceStatusChanged",
"InvoiceId": 12345,
"InvoiceStatus": "Paid",
"InvoiceAttemptStatus": "Success"
}
```
**What you do:**
* Extend customer's subscription
* Send confirmation email
* Update your records
### Alternative: Day 4: Payment Fails
**Webhook notification:**
```json theme={null}
{
"Event": "InvoiceStatusChanged",
"InvoiceId": 12345,
"InvoiceStatus": "Noncollectable",
"InvoiceAttemptStatus": "Failed",
"Message": "Insufficient funds"
}
```
**What you do:**
* Pause customer's subscription
* Send email: "Payment failed. Please update your payment method."
* Give them a grace period to fix it
## Best Practices for ACH
1. **Always verify accounts first**: Especially for recurring billing
2. **Set up webhooks**: Essential for knowing when status changes
3. **Set customer expectations**: Tell them it takes 1-5 business days
4. **Don't fulfill immediately**: Wait for `Paid` status before shipping/activating
5. **Handle failures gracefully**: Have a plan for when payments fail
6. **Use for the right use cases**: Recurring bills, large amounts, B2B
7. **Store payment methods**: Use tokenization so customers don't re-enter bank details
## ACH vs. Credit Cards: Quick Comparison
| Feature | ACH | Credit Cards |
| - | - | - |
| **Processing time** | 1-5 business days | Instant (seconds) |
| **Fees** | Low (cents) | Higher (2-3% + fees) |
| **Good for** | Recurring, large amounts | Instant purchases, small amounts |
| **Failure notification** | Days later | Immediate |
| **Chargebacks** | Different rules | Common, can be expensive |
| **Customer experience** | Requires bank details | Just card number |
## Common Questions
**Q: Can I make ACH instant?** A: No, ACH is inherently a batch system. If you need instant payments, use credit cards or other real-time payment methods.
**Q: What if the customer doesn't have enough funds?** A: The payment will fail with `Noncollectable` status after a few days. You'll need to retry or ask for a different payment method.
**Q: Can I refund an ACH payment?** A: Yes, but refunds also take 1-5 business days to process. The customer will see the money back in their account after processing.
**Q: Is ACH more secure than credit cards?** A: Both have security considerations. ACH requires bank account numbers (sensitive), but has different fraud patterns than credit cards. Use proper security practices for both.
## Next Steps
* [**Payment Methods Guide**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Learn how to store ACH payment methods securely
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — Set up recurring ACH billing
* [**Webhooks**](/docs/webhook-events/webhook) — Set up status change notifications
* [**Account Verification API**](https://docs.revolv3.com/api-reference/) — Verify bank accounts before charging
***
# Managing Billing Addresses
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/billing-address
Learn how to format and validate billing addresses for payment processing. Understand address requirements, validation rules, and international address formats.
## Why Billing Addresses Matter
A **billing address** is the address associated with the customer's payment method (credit card or bank account). It's used for:
* **Fraud prevention**: Banks verify that the address matches what they have on file
* **Address Verification System (AVS)**: Card networks check if the address matches
* **Compliance**: Required for many payment types
* **Customer identification**: Helps verify the customer is authorized to use the payment method
**Why it's important**: Providing the correct billing address can improve payment success rates and reduce fraud. Incorrect addresses may cause payments to be declined.
## Sample Billing Address
Here's a complete example of a valid billing address:
```json theme={null}
{
"PaymentMethod": {
"BillingAddress": {
"AddressLine1": "381 Forest Ave",
"AddressLine2": null,
"City": "Laguna Beach",
"State": "CA",
"PostalCode": "92651",
"Country": "USA"
},
"BillingFirstName": "John",
"BillingLastName": "Doe",
"CreditCard": {
"PaymentAccountNumber": "4111111111111111",
"ExpirationDate": "0330",
"SecurityCode": "737"
}
}
}
```
## Address Field Details
| Field | Required | Description | Examples |
| - | - | - | - |
| `AddressLine1` | Optional | Street address (first line) | `"381 Forest Ave"`, `"123 Main Street"` |
| `AddressLine2` | Optional | Apartment, suite, unit, etc. | `"Suite 100"`, `"Apt 5B"` |
| `City` | Optional | City name | `"Laguna Beach"`, `"New York"` |
| `State` | Optional | State or province | `"CA"`, `"NY"`, `"ON"` (for Canada) |
| `PostalCode` | Optional | ZIP code or postal code | `"92651"`, `"10001"`, `"K1A 0B1"` (Canada) |
| `Country` | Optional | Country code (ISO format) | `"USA"`, `"CA"`, `"GB"` |
## Address Formatting Rules
### Country Codes
Use **ISO Alpha-2 or Alpha-3** country code abbreviations:
* `"USA"` or `"US"` for United States
* `"CA"` or `"CAN"` for Canada
* `"GB"` or `"GBR"` for United Kingdom
* See [Country Codes Reference](https://www.iban.com/country-codes) for complete list
### United States Postal Codes
* **Format**: Exactly 5 digits
* **Examples**: `"92651"`, `"10001"`, `"90210"`
* **Not valid**: `"92651-1234"` (extended ZIP), `"9265"` (too short)
### International Postal Codes
* **Format**: Up to 10 characters
* **Examples**:
* Canada: `"K1A 0B1"` (with space) or `"K1A0B1"` (without)
* UK: `"EC1Y 8SY"` or `"SW1A 1AA"`
* Australia: `"2000"` or `"2000-3000"`
### State/Province Requirements
* **United States**: State is typically required (2-letter code like `"CA"`, `"NY"`)
* **Canada**: Province is typically required (2-letter code like `"ON"`, `"BC"`)
* **Many other countries**: State/province is **not required** (e.g., UK, Australia, most of Europe)
## International Address Examples
### United Kingdom
```json theme={null}
{
"BillingAddress": {
"AddressLine1": "49 Featherstone Street",
"City": "London",
"PostalCode": "EC1Y 8SY",
"Country": "GB"
}
}
```
### Canada
```json theme={null}
{
"BillingAddress": {
"AddressLine1": "100 Main Street",
"City": "Toronto",
"State": "ON",
"PostalCode": "M5H 2N2",
"Country": "CA"
}
}
```
**Note**: Canadian addresses use province codes (ON, BC, QC, etc.) and postal codes can include spaces.
### Australia
```json theme={null}
{
"BillingAddress": {
"AddressLine1": "100 George Street",
"City": "Sydney",
"State": "NSW",
"PostalCode": "2000",
"Country": "AU"
}
}
```
## Using Stored Addresses (AddressId)
If you've previously stored an address in Revolv3, you can reference it by `AddressId`:
```json theme={null}
{
"BillingAddress": {
"AddressId": 7551 // Reference to previously stored address
}
}
```
In this example, `AddressId` refers to an address that was previously stored in Revolv3 and can be reused without resending the full address fields.
This is useful when:
* The customer has used this address before
* You want to avoid sending address data repeatedly
* You're reusing addresses for multiple transactions
## Best Practices
1. **Collect complete addresses**: Get all fields when possible for better fraud prevention
2. **Validate before sending**: Check address format in your application before API calls
3. **Handle international addresses**: Be aware that different countries have different requirements
4. **Store addresses**: If customers use the same address multiple times, store it and reuse
5. **Match card address**: The billing address should match the address on file with the bank
## Common Questions
**Q: Do I need all address fields?** A: No, but providing more fields improves fraud prevention.
**Q: What if the customer doesn't have a state/province?** A: For countries where state isn't required (like UK), you can omit it. For US/Canada, it's typically required.
**Q: Can I use extended ZIP codes (ZIP+4)?** A: For US addresses, use only the 5-digit ZIP code. Extended ZIPs (like "92651-1234") are not supported.
**Q: What format should postal codes be in?** A: Use the format common in that country. Canadian postal codes can include spaces; US ZIPs should be 5 digits only.
**Q: Do I need to include AddressLine2?** A: No, it's optional. Only include it if the customer has an apartment, suite, or unit number.
## Next Steps
* [**Make a Payment**](/docs/getting-started/make-a-payment) — See how billing addresses are used in payment requests
* [**Payment Methods Guide**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Learn about storing payment methods with addresses
* [**Create a Subscription**](/docs/core-concepts/subscription/create-subscription) — See how addresses work with subscriptions
***
# Create a Payment Method
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/paymentmethod-guide
Learn how to securely store customer payment methods using tokenization, and reuse them for future transactions without handling sensitive card data.
## What is a Payment Method and Why Store It?
A **Payment Method** in Revolv3 is a securely stored reference to a customer's payment credential (like a credit card or bank account). Instead of asking customers to enter their card details every time they make a purchase, you can store their payment information once and reuse it.
**Why is this useful?**
* **Better customer experience**: Customers don't have to re-enter their card details every time
* **Faster checkout**: One-click purchases for returning customers
* **Security**: You never store full card numbers in your database (more on this below)
* **Recurring billing**: Essential for subscriptions and recurring payments
## Understanding Tokenization
When you store a payment method, Revolv3 uses a process called **tokenization**. Here's how it works:
1. **You send the full card details** to Revolv3 (card number, expiration, CVV)
2. **Revolv3 securely stores** the card information in a PCI-compliant vault
3. **Revolv3 returns a token** (called a `paymentMethodId`) that represents the card
4. **You store only the token** in your database - never the actual card number
**Security benefits:**
* Your database never contains sensitive card data, reducing your security risk
* If your database is compromised, attackers only get tokens (which are useless without Revolv3)
* You don't need to be PCI-compliant for storing tokens (Revolv3 handles that)
* Card details are encrypted and stored in secure, compliant systems
## Two Ways to Create Payment Methods
You have two options for creating payment methods:
1. **Create a Payment Method separately** before processing a payment (useful if you want to verify the card first or collect payment info ahead of time)
2. **Automatically create one when processing a payment** (Revolv3 will create and return a `paymentMethodId` in the response)
Both approaches work the same way - the difference is timing. Let's look at both.
## Creating a Payment Method
If you want to create a payment method before processing a payment (for example, to verify the card or set up a subscription), you can create it separately.
### API Endpoint
```
POST {{Api Root}}/api/PaymentMethod
```
### Sample API Request
```json theme={null}
{
"BillingAddress": {
"AddressLine1": "100 Main Street",
"AddressLine2": "",
"City": "Santa Ana",
"State": "CA",
"PostalCode": "90000",
"Country": "US"
},
"BillingFullName": "John Smith",
"CreditCard": {
"PaymentAccountNumber": "4111111111111111",
"ExpirationDate": "1025",
"SecurityCode": 123
},
"MerchantPaymentMethodRefId": "payment-method-ref-id_hgays-213-4rf4"
}
```
In this example, `ExpirationDate` uses MMYY format (e.g., `1025` means October 2025), `SecurityCode` is the CVV/CVC, and `MerchantPaymentMethodRefId` is your own internal reference ID.
### Understanding the Request Fields
| **Field** | **Description** |
| - | - |
| `BillingAddress` | The address associated with the credit card. This is used for fraud prevention - banks verify that the address matches what they have on file. |
| `AddressLine1, AddressLine2, City, State, PostalCode, Country` | Complete billing address details. AddressLine2 is optional. |
| `BillingFullName` | The name on the credit card. Can be a person's name (like "John Smith") or a company name. Use standard ASCII characters only (letters, numbers, spaces, hyphens) to avoid compatibility issues. |
| `CreditCard.PaymentAccountNumber` | The full credit card number (16 digits for most cards). **Never store this in your database after getting the token.** |
| `CreditCard.ExpirationDate` | Card expiration date in MMYY format (e.g., "1025" means October 2025). |
| `CreditCard.SecurityCode` | The CVV/CVC security code (usually 3-4 digits on the back of the card). **Never store this - it's only needed for the initial tokenization.** |
| `MerchantPaymentMethodRefId` | Your own internal reference ID for tracking this payment method. Useful for matching Revolv3's response back to your system. |
> **Security Best Practice**: Once you receive the `paymentMethodId` in the response, delete the full card number and CVV from your application's memory. You'll never need them again - just use the token.
### Response When Creating a Payment Method
When you successfully create a payment method, Revolv3 returns a `paymentMethodId` that you can use for all future transactions with this customer.
```
{
"PaymentMethodId": 16336,
"BillingAddressId": 17683,
"BillingAddress": {
"AddressId": 17683,
"AddressLine1": "100 Main Street",
"AddressLine2": "",
"City": "Santa Ana",
"State": "CA",
"PostalCode": "90000",
"PhoneNumber": null,
"Email": null,
"Country": "US"
},
"BillingFirstName": "John",
"BillingLastName": "Smith",
"MerchantPaymentMethodRefId": "payment-method-ref-id_hgays-213-4rf4",
"PaymentMethodAchDetails": null,
"PaymentMethodCreditCardDetails": {
"BinNumber": "411111",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "1025"
}
}
```
Here, `paymentMethodId` is the token you’ll use for future charges, `binNumber` is the first 6 digits of the card (bank identifier), and `paymentLast4Digit` is safe to display to customers.
### Understanding the Response
| **Field** | **Description** |
| - | - |
| `paymentMethodId` | **The most important field** - this is your token. Store this in your database and use it for all future charges. |
| `billingAddressId` | Revolv3's ID for the billing address (useful if you need to update it later). |
| `billingAddress` | The full billing address you provided, stored in Revolv3's system. |
| `merchantPaymentMethodRefId` | Your original reference ID, echoed back for your records. |
| `paymentMethodCreditCardDetails.binNumber` | The first 6 digits of the card (Bank Identification Number). This identifies which bank issued the card. |
| `paymentMethodCreditCardDetails.paymentLast4Digit` | The last 4 digits of the card. This is safe to display to customers (e.g., "Your card ending in 1111"). |
| `paymentMethodCreditCardDetails.paymentExpirationDate` | The card's expiration date in MMYY format. |
> **Note**: Notice that the response doesn't include the full card number or CVV. Revolv3 never returns sensitive data - only the token and safe-to-display information like the last 4 digits.
## Reusing a Stored Payment Method
Once you have a `paymentMethodId`, you can use it to charge the customer without ever handling their card details again. This is much more secure and provides a better user experience.
### API Endpoint
```
POST {{Api Root}}/api/Payments/sale/{paymentMethodId}
```
Replace `{paymentMethodId}` with the ID you received when creating the payment method (e.g., `16336`).
### Sample API Request
```json theme={null}
{
"NetworkProcessing": {
"ProcessingType": "initialRecurring",
"OriginalNetworkTransactionId": null
},
"CustomerId": null,
"Invoice": {
"MerchantInvoiceRefId": "ABC309500654810",
"Amount": {
"Value": 1.03
}
}
}
```
In this request, `processingType` controls how networks classify the transaction (recurring vs installment), `CustomerId` can link to an existing customer record, `MerchantInvoiceRefId` is your order ID, and `Amount.value` is the charge amount.
### Understanding the Request Fields
| **Field** | **Description** |
| - | - |
| `NetworkProcessing.processingType` | How to classify this transaction. For a one-time purchase, use `null`. For subscriptions, use `initialRecurring` for the first payment, then `recurring` for subsequent payments. |
| `NetworkProcessing.originalNetworkTransactionId` | Leave `null` for new transactions. Use this if you're referencing a previous transaction (like a follow-up payment). |
| `CustomerId` | Optional. If you have a customer record in Revolv3, link this payment to it. Otherwise, leave `null`. |
| `Invoice.MerchantInvoiceRefId` | Your internal order or invoice ID. Use this to match the response back to your system. |
| `Invoice.Amount.value` | The amount to charge (USD is a default). |
### Payment Response
When you successfully charge a stored payment method, you'll get a response similar to when you charge a card directly:
```json theme={null}
{
"CustomerId": null,
"InvoiceId": 575950,
"MerchantInvoiceRefId": "ABC309500654810",
"MerchantPaymentMethodRefId": null,
"NetworkTransactionId": "295845970297960",
"InvoiceStatus": "Paid",
"InvoiceAttemptStatus": "Success",
"Message": "Approved",
"Amount": {
"Currency": "USD",
"Value": 1.03
},
"PaymentMethodId": 63121,
"PaymentMethodTypeId": 1,
"PaymentProcessor": "WorldPay",
"ProcessorMerchantId": "10071676",
"RawResponse": null,
"PaymentMethodCreditCardDetails": {
"BinNumber": "411111",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "1130",
"AccountUpdateMessage": null,
"AccountUpdateDateTime": null
},
"ResponseMessage": "Approved",
"ResponseCode": "000"
}
```
In this response, `paymentMethodId` confirms which stored payment method was used, and `paymentMethodTypeId` indicates the type (`1` = credit card, `2` = ACH, `3` = Google Pay, `4` = Apple Pay).
### Understanding the Response
| **Field** | **Description** |
| - | - |
| `invoiceId` | Revolv3's unique identifier for this invoice. Save this for refunds and customer support. |
| `merchantInvoiceRefId` | Your original order ID, echoed back. |
| `networkTransactionId` | The transaction ID from the card network. **Always store this** - you'll need it for disputes, chargebacks, and reconciliation. |
| `invoiceStatus` | Current status of the invoice. "Paid" means the payment succeeded. |
| `invoiceAttemptStatus` | Result of this payment attempt. "Success" means it went through. |
| `message` | Human-readable result. |
| `paymentMethodId` | Confirms which stored payment method was used. |
| `paymentMethodTypeId` | Type of payment method: `1` = Credit Card, `2` = ACH, `3` = Google Pay, `4` = Apple Pay |
## Account Updater: Keeping Cards Current
Some payment processors support **Account Updater**, a service that automatically updates expired or replaced cards in your stored payment methods. For example, if a customer gets a new card number or their card expires, Account Updater can update your records so recurring payments don't fail.
When Account Updater updates a card, you'll see additional fields in the response:
```json theme={null}
{
"PaymentMethodCreditCardDetails": {
"BinNumber": "411111",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "1130",
"AccountUpdateMessage": "NEW_EXPIRY",
"AccountUpdateDateTime": "2025-10-30T11:46:33"
}
}
```
Here, `accountUpdateMessage` indicates what the account updater changed (for example, a new expiry date), and `accountUpdateDateTime` records when it was updated.
## Real-World Use Cases
**E-commerce with saved cards**: When a customer checks out, offer to "save this card for faster checkout." Store the `paymentMethodId` and show "Pay with card ending in 1111" on their next visit.
**Subscription services**: When a customer signs up for a monthly subscription, create a payment method and use it for all recurring charges. Account Updater will keep the card current even if it expires.
**One-click purchases**: Store payment methods for returning customers so they can complete purchases with a single click instead of entering card details every time.
**Guest checkout with optional save**: Allow customers to checkout as guests, but offer to save their payment method if they create an account later.
## Summary
| **Action** | **API Endpoint** | **Purpose** |
| - | - | - |
| **Create a Payment Method** | `POST /api/PaymentMethod` | Securely store a customer's payment credential and get a token (`paymentMethodId`) |
| **Charge a Stored Payment Method** | `POST /api/Payments/sale/{paymentMethodId}` | Charge a customer using a stored payment method without handling card details |
## Security Reminders
* **Do**: Store `paymentMethodId` tokens in your database
* **Do**: Display the last 4 digits to customers for confirmation
* **Do**: Delete card numbers and CVV codes from memory after tokenization
* **Don't**: Store full card numbers or CVV codes in your database
* **Don't**: Log card numbers or CVV codes
* **Don't**: Send card details in URLs or query parameters
## Next Steps
* [**ACH Direct Debit**](/docs/core-concepts/paymentmethod/ach-direct-debit) — Learn how to store and charge bank accounts
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — Use payment methods for recurring billing
* [**Account Updater**](/docs/core-concepts/paymentmethod/account-updater) — Understand how cards are automatically updated
***
# Using Apple Pay
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/using-applepay
Learn how to accept Apple Pay payments through Revolv3. Understand the setup process, how to pass Apple Pay tokens, and handle responses.
## What is Apple Pay?
**Apple Pay** is a mobile and web payment service from Apple that lets customers pay using their iPhone, iPad, Apple Watch, or Mac. Instead of entering card details, customers authenticate with Face ID, Touch ID, or a passcode.
**Benefits for merchants:**
* **Faster checkout**: Customers don't need to type card details
* **Higher conversion**: Easier checkout means more completed purchases
* **Better security**: Apple handles card data—you never see it
* **Mobile-friendly**: Great experience on iOS devices
**How it works**: Apple creates an encrypted token representing the payment method. You send this token to Revolv3, and the payment processor decrypts it to process the payment.
## Scope of Revolv3's Apple Pay Support
Revolv3 currently supports Apple Pay in a **token processing scenario only**. This means Revolv3 does not provide the Apple Pay button, merchant validation, or any client-side Apple Pay SDK functionality. Merchants must implement Apple Pay directly using Apple's official APIs on their website or mobile application and obtain the Apple Pay payment token after the customer authorizes the payment. Once the token is generated, it can be sent to Revolv3 as part of the payment request. Revolv3 forwards the token to the configured payment processor, which decrypts the token using the merchant's Apple Pay payment processing certificate and processes the transaction. In this model, Revolv3 acts as the secure transport layer for the Apple Pay token, while Apple handles token generation and the payment processor performs decryption and authorization.
### Supported processors
Apple Pay token pass-through is currently supported for:
* **Nuvei**
Other processors are not supported for Apple Pay through Revolv3 at this time.
## Prerequisites
Before you can accept Apple Pay through Revolv3, you need to complete these setup steps:
### Step 1: Obtain a Certificate Signing Request (CSR)
1. Contact your payment processor (**Nuvei** for Apple Pay)
2. Request a CSR file from them
3. The processor will provide the CSR file needed for certificate generation
### Step 2: Generate a Payment Processing Certificate
1. Use the CSR file from your processor
2. Log in to your [Apple Developer account](https://developer.apple.com/)
3. Generate a Payment Processing Certificate (`.cer` file)
4. Follow Apple's [official documentation](https://developer.apple.com/documentation/apple_pay_on_the_web/setting_up_your_server) for detailed instructions
**What this certificate does**: It allows the payment processor to decrypt Apple Pay tokens. Apple requires this for security.
### Step 3: Register the Certificate with Your Processor
1. Submit the generated `.cer` file to your payment processor
2. The processor registers it on their end
3. This enables them to decrypt Apple Pay tokens for your merchant account
### Step 4: Get Confirmation
1. Wait for confirmation from your processor
2. Verify that Apple Pay is enabled for your merchant account
3. Once confirmed, you can start accepting Apple Pay payments
> **Note**: If you've already implemented Apple Pay buttons on your website, you may already have this certificate. Check with your processor to see if it can be reused.
## How Apple Pay Works with Revolv3
### The Flow
1. **Customer taps Apple Pay button** on your website or app
2. **Apple authenticates** the customer (Face ID, Touch ID, or passcode)
3. **Apple returns a token** containing encrypted payment data
4. **You send the token to Revolv3** in your payment request
5. **Revolv3 forwards to processor** which decrypts the token
6. **Payment is processed** using the decrypted card information
**Key point**: You never see or handle the actual card number. Apple and the processor handle all the sensitive data.
## Getting the Apple Pay Token
When a customer completes Apple Pay authentication, you'll receive a token from Apple. Here's how to get it:
### JavaScript Example
```javascript theme={null}
session.onpaymentauthorized = (evt) => {
const token = evt.payment.token; // ⭐ This is what you send to Revolv3
// Send token to your backend, then to Revolv3
}
```
**What the token looks like**: It's a JSON object containing encrypted payment data. You'll send this entire token to Revolv3.
## Sending Apple Pay Token to Revolv3
Include the Apple Pay token in your payment request using the `ApplePay` object:
```json theme={null}
{
"PaymentMethod": {
"BillingAddress": {
"AddressId": null,
"AddressLine1": "2001 Main Street",
"AddressLine2": "",
"City": "Santa Ana",
"State": "CA",
"PostalCode": "90000",
"Country": "USA"
},
"BillingFirstName": "John",
"BillingLastName": "Smith",
"ApplePay": {
"ApplePayToken": "eyJwYXltZW50RGF0YSI6eyJkYXRhIjoibUVzam10QUdUeU5DRzB0VmtlRGFMVHAweGJFUkN1NXBocU94dGxPVDdJYURKUDVFN3I4MmtGNjJCMEF0dktGOURtY014eUlZTGNFaXFxM1N5YlNzblQwWVgwaXJkS3FRdDduZjRBNHlEWXVRcVVJeHVJREUxejJFTENPeWFiZ3p5TVp5cnM2VVhDRERva0w3UkpPeGFhQWgzRHdMVVFMc2hLMndibkk4VnVXRmNDVmNsQ2tBQnQzVjNZSFdodWV6U3pVTFozSnJkZ0xmblJQQ1ZoeVNHZXBDL2xWYXVUT1dqc2taVGJmQ2JmKytsaitUQmtjV2NJTy91cy96SVVsczBRMlFwTWQweEIyRXJiNTNtM24vUHBiQy90UjNWdnFXWDVDcVIxWVgxM1FzYU11VXhZT24vUy9weHk0Y1lQem1Fem5PalpZRllGbmNHbmhzWFIwNUxRanhYVmlEaldJY283dzF0VzhVWGNlNmkzb2NUQk95NGZMTWtFWWFwaUpKUlVwcjM3V09LNUhjZU9VcDVBPT0iLCJzaWduYXR1cmUiOiJNSUFHQ1NxR1NJYjNEUUVIQXFDQU1JQUNBUUV4RFRBTEJnbGdoa2dCWlFNRUFnRXdnQVlKS29aSWh2Y05BUWNCQUFDZ2dEQ0NBK1F3Z2dPTG9BTUNBUUlDQ0ZuWW9ieXE5T1BOTUFvR0NDcUdTTTQ5QkFNQ01Ib3hMakFzQmdOVkJBTU1KVUZ3Y0d4bElFRndjR3hwWTJGMGFXOXVJRWx1ZEdWbmNtRjBhVzl1SUVOQklDMGdSek14SmpBa0JnTlZCQXNNSFVGd2NHeGxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1STXdFUVlEVlFRS0RBcEJjSEJzWlNCSmJtTXVNUXN3Q1FZRFZRUUdFd0pWVXpBZUZ3MHlNVEEwTWpBeE9UTTNNREJhRncweU5qQTBNVGt4T1RNMk5UbGFNR0l4S0RBbUJnTlZCQU1NSDJWall5MXpiWEF0WW5KdmEyVnlMWE5wWjI1ZlZVTTBMVk5CVGtSQ1QxZ3hGREFTQmdOVkJBc01DMmxQVXlCVGVYTjBaVzF6TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCSUl3L2F2RG5QZGVJQ3hRMlp0RkV1WTM0cWtCM1d5ejRMSE5TMUpubVBqUFRyM29HaVdvd2g1TU05M09qaXFXd3Zhdm9aTURSY1RvZWtRbXpwVWJFcFdqZ2dJUk1JSUNEVEFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGQ1B5U2NSUGsrVHZKK2JFOWloc1A2SzcvUzVMTUVVR0NDc0dBUVVGQndFQkJEa3dOekExQmdnckJnRUZCUWN3QVlZcGFIUjBjRG92TDI5amMzQXVZWEJ3YkdVdVkyOXRMMjlqYzNBd05DMWhjSEJzWldGcFkyRXpNREl3Z2dFZEJnTlZIU0FFZ2dFVU1JSUJFRENDQVF3R0NTcUdTSWIzWTJRRkFUQ0IvakNCd3dZSUt3WUJCUVVIQWdJd2diWU1nYk5TWld4cFlXNWpaU0J2YmlCMGFHbHpJR05sY25ScFptbGpZWFJsSUdKNUlHRnVlU0J3WVhKMGVTQmhjM04xYldWeklHRmpZMlZ3ZEdGdVkyVWdiMllnZEdobElIUm9aVzRnWVhCd2JHbGpZV0pzWlNCemRHRnVaR0Z5WkNCMFpYSnRjeUJoYm1RZ1kyOXVaR2wwYVc5dWN5QnZaaUIxYzJVc0lHTmxjblJwWm1sallYUmxJSEJ2YkdsamVTQmhibVFnWTJWeWRHbG1hV05oZEdsdmJpQndjbUZqZEdsalpTQnpkR0YwWlcxbGJuUnpMakEyQmdnckJnRUZCUWNDQVJZcWFIUjBjRG92TDNkM2R5NWhjSEJzWlM1amIyMHZZMlZ5ZEdsbWFXTmhkR1ZoZFhSb2IzSnBkSGt2TURRR0ExVWRId1F0TUNzd0thQW5vQ1dHSTJoMGRIQTZMeTlqY213dVlYQndiR1V1WTI5dEwyRndjR3hsWVdsallUTXVZM0pzTUIwR0ExVWREZ1FXQkJRQ0pEQUxtdTd0UmpHWHBLWmFLWjVDY1lJY1JUQU9CZ05WSFE4QkFmOEVCQU1DQjRBd0R3WUpLb1pJaHZkalpBWWRCQUlGQURBS0JnZ3Foa2pPUFFRREFnTkhBREJFQWlCMG9iTWsyMEpKUXczVEoweFFkTVNBalpvZlNBNDZoY1hCTmlWbU1sKzhvd0lnYVRhUVU2djFDMXBTK2ZZQVRjV0tyV3hRcDlZSWFEZVE0S2M2MEI1SzJZRXdnZ0x1TUlJQ2RhQURBZ0VDQWdoSmJTKy9PcGphbHpBS0JnZ3Foa2pPUFFRREFqQm5NUnN3R1FZRFZRUUREQkpCY0hCc1pTQlNiMjkwSUVOQklDMGdSek14SmpBa0JnTlZCQXNNSFVGd2NHeGxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1STXdFUVlEVlFRS0RBcEJjSEJzWlNCSmJtTXVNUXN3Q1FZRFZRUUdFd0pWVXpBZUZ3MHhOREExTURZeU16UTJNekJhRncweU9UQTFNRFl5TXpRMk16QmFNSG94TGpBc0JnTlZCQU1NSlVGd2NHeGxJRUZ3Y0d4cFkyRjBhVzl1SUVsdWRHVm5jbUYwYVc5dUlFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJQQVhFWVFaMTJTRjFScGVKWUVIZHVpQW91L2VlNjVONEkzOFM1UGhNMWJWWmxzMXJpTFFsM1lOSWs1N3VnajlkaGZPaU10MnUyWnd2c2pvS1lUL1ZFV2pnZmN3Z2ZRd1JnWUlLd1lCQlFVSEFRRUVPakE0TURZR0NDc0dBUVVGQnpBQmhpcG9kSFJ3T2k4dmIyTnpjQzVoY0hCc1pTNWpiMjB2YjJOemNEQTBMV0Z3Y0d4bGNtOXZkR05oWnpNd0hRWURWUjBPQkJZRUZDUHlTY1JQaytUdkorYkU5aWhzUDZLNy9TNUxNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdId1lEVlIwakJCZ3dGb0FVdTdEZW9WZ3ppSnFraXBuZXZyM3JyOXJMSktzd053WURWUjBmQkRBd0xqQXNvQ3FnS0lZbWFIUjBjRG92TDJOeWJDNWhjSEJzWlM1amIyMHZZWEJ3YkdWeWIyOTBZMkZuTXk1amNtd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CQUdDaXFHU0liM1kyUUdBZzRFQWdVQU1Bb0dDQ3FHU000OUJBTUNBMmNBTUdRQ01EclBjb05SRnBteGh2czF3MWJLWXIvMEYrM1pEM1ZOb282KzhaeUJYa0szaWZpWTk1dFpuNWpWUVEyUG5lbkMvZ0l3TWkzVlJDR3dvd1YzYkYzek9EdVFaLzBYZkN3aGJaWlB4bkpwZ2hKdlZQaDZmUnVaeTVzSmlTRmhCcGtQQ1pJZEFBQXhnZ0dJTUlJQmhBSUJBVENCaGpCNk1TNHdMQVlEVlFRRERDVkJjSEJzWlNCQmNIQnNhV05oZEdsdmJpQkpiblJsWjNKaGRHbHZiaUJEUVNBdElFY3pNU1l3SkFZRFZRUUxEQjFCY0hCc1pTQkRaWEowYVdacFkyRjBhVzl1SUVGMWRHaHZjbWwwZVRFVE1CRUdBMVVFQ2d3S1FYQndiR1VnU1c1akxqRUxNQWtHQTFVRUJoTUNWVk1DQ0ZuWW9ieXE5T1BOTUFzR0NXQ0dTQUZsQXdRQ0FhQ0JrekFZQmdrcWhraUc5dzBCQ1FNeEN3WUpLb1pJaHZjTkFRY0JNQndHQ1NxR1NJYjNEUUVKQlRFUEZ3MHlOVEF6TVRJeE5USTRORFZhTUNnR0NTcUdTSWIzRFFFSk5ERWJNQmt3Q3dZSllJWklBV1VEQkFJQm9Rb0dDQ3FHU000OUJBTUNNQzhHQ1NxR1NJYjNEUUVKQkRFaUJDQkY5ckt2OGZLZmZtdjNyS1JrRmNHdmtXb2ZpZEpiMjZGTk1iVTc0MUVzTkRBS0JnZ3Foa2pPUFFRREFnUkhNRVVDSUJ4aFh0V3EvRkxEVVZhMVMwVUZIVGhzSWsvNk8zL1FQWE5lZUlpdjAxb2RBaUVBakVxR0pROTdPRGEyd3M1UVJJVkU5SC9kaUY2NzBhL1ZUYndST1RzSHpUZ0FBQUFBQUFBPSIsImhlYWRlciI6eyJwdWJsaWNLZXlIYXNoIjoiZWFIbkRIUmVDT0xDazQ5RkFKbTVmOWhVM2didTFxUitxRFdUc29GdU9PMD0iLCJlcGhlbWVyYWxQdWJsaWNLZXkiOiJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV1bjI1ODNUQXNnRXlBYTk5SERueEZ0amlxSWNpditVK1NNKy84c1p0Ymo3Ykxxc1orSzBLNk5iWWRnd2JZcmw0VWU4bVJad3hJb1luZU54aTl4cm1adz09IiwidHJhbnNhY3Rpb25JZCI6IjQyMGE5MDJhMDRjZGE2OGFhZmE3NDRkYjUwZjBkOTdkMGRjYmFiMzdiMDM2MTBiNDZkMTZhOGRkZjBkNjgwOWYifSwidmVyc2lvbiI6IkVDX3YxIn0sInBheW1lbnRNZXRob2QiOnsiZGlzcGxheU5hbWUiOiJNYXN0ZXJDYXJkIDAwNDkiLCJuZXR3b3JrIjoiTWFzdGVyQ2FyZCIsInR5cGUiOiJjcmVkaXQifSwidHJhbnNhY3Rpb25JZGVudGlmaWVyIjoiNDIwYTkwMmEwNGNkYTY4YWFmYTc0NGRiNTBmMGQ5N2QwZGNiYWIzN2IwMzYxMGI0NmQxNmE4ZGRmMGQ2ODA5ZiJ9"
}
},
"Invoice": {
"Amount": {
"Value": 10.0
}
}
}
```
### Important: Token Encoding
**The Apple Pay token must be Base64 encoded** before including it in your JSON request.
**What this means:**
1. Apple gives you a token (JSON object)
2. You need to Base64 encode it
3. Send the encoded string to Revolv3
**Example in JavaScript:**
```javascript theme={null}
const applePayToken = evt.payment.token; // From Apple
const encodedToken = btoa(JSON.stringify(applePayToken)); // Base64 encode
// Send encodedToken to Revolv3
```
## Understanding the Apple Pay Token
The token from Apple contains:
* **Payment data**: Encrypted card information
* **Signature**: Cryptographic signature for verification
* **Header**: Public key and transaction information
* **Payment method info**: Card network and type (for display)
**You don't need to parse it**—just send the entire encoded token to Revolv3. The processor handles decryption.
## Error Handling
### Processor Not Configured
If your processor doesn't support Apple Pay or it's not configured, you'll get a 400 error:
```json theme={null}
{
"message": "Merchant does not have configured processor for payment method type ApplePay"
}
```
**What this means:**
* Apple Pay isn't enabled for your merchant account
* Your processor doesn't support Apple Pay
* The certificate isn't properly configured
**What to do:**
* Contact Revolv3 Support to enable Apple Pay
* Verify your processor supports Apple Pay
* Check that your certificate is properly registered
## Best Practices
1. **Encode the token**: Always Base64 encode the Apple Pay token before sending
2. **Handle errors gracefully**: Show user-friendly messages if Apple Pay fails
3. **Test thoroughly**: Test in sandbox before going to production
4. **Keep certificate current**: Renew your Payment Processing Certificate when it expires
5. **Mobile-first**: Apple Pay works best on iOS devices—optimize for mobile
## Common Questions
**Q: Do I need to decrypt the token?**
A: No, send it to Revolv3 as-is (after Base64 encoding). The processor decrypts it.
**Q: Can I use Apple Pay on Android?**
A: No, Apple Pay only works on Apple devices (iPhone, iPad, Mac, Apple Watch).
**Q: What if the processor doesn't support Apple Pay?**
A: Apple Pay through Revolv3 is currently supported only for **Nuvei**. Contact Revolv3 Support if you need Apple Pay on another processor.
**Q: Do I need a separate certificate for each processor?**
A: Yes. Today only Nuvei is supported for Apple Pay; if support expands later, each processor would require its own certificate.
**Q: Can I store Apple Pay tokens like regular payment methods?**
A: Yes, Revolv3 can create a `paymentMethodId` from Apple Pay tokens that you can reuse.
## Next Steps
* **[Using Google Pay](/docs/core-concepts/paymentmethod/using-googlepay)** — Learn about Google Pay integration
* **[Payment Methods Guide](/docs/core-concepts/paymentmethod/paymentmethod-guide)** — Understand how to store payment methods
* Contact Revolv3 Support to enable Apple Pay for your account
***
# Using Google Pay
Source: https://docs.revolv3.com/docs/core-concepts/paymentmethod/using-googlepay
Accept Google Pay payments through Revolv3 using gateway-based tokenization (PAYMENT_GATEWAY). Includes Worldpay (Vantiv) examples, environment setup, and architecture diagrams.
## Using Google Pay with Revolv3
Revolv3 supports **gateway-based Google Pay tokenization**.\
You must use:
```javascript theme={null}
type: 'PAYMENT_GATEWAY'
```
Revolv3 does **NOT** support `DIRECT` tokenization for Google Pay.
***
## Architecture Overview
```mermaid theme={null}
sequenceDiagram
participant Customer
participant Browser
participant Google
participant Revolv3
participant Processor
Customer->>Browser: Click Google Pay
Browser->>Google: loadPaymentData()
Google-->>Browser: GooglePayPaymentDataResponse
Browser->>Revolv3: Send full response
Revolv3->>Processor: Forward encrypted token
Processor-->>Revolv3: Authorization result
Revolv3-->>Browser: Sale response
```
**Key Point:**\
Google encrypts the token for your **processor**.\
Revolv3 forwards the encrypted payload.\
The processor decrypts and authorizes it.
***
## Prerequisites
* Google Pay enabled on your Revolv3 merchant account
* Processor supports Google Pay (**Worldpay** or **Adyen** only)
* Google Pay enabled on your processor account
* Use `PAYMENT_GATEWAY` tokenization
> **Note**: Google Pay pass-through is **not** supported for Nuvei or other processors at this time. Revolv3 also does **not** support Google Pay `DIRECT` tokenization (where Revolv3 would decrypt the token).
***
## Tokenization Setup (Worldpay Example)
### Correct Configuration
```javascript theme={null}
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'vantiv', // Worldpay uses 'vantiv'
'vantiv:merchantPayPageId': 'YOUR_PAYPAGE_ID',
'vantiv:merchantOrderId': 'ORDER123',
'vantiv:merchantTransactionId': 'TX123',
'vantiv:merchantReportGroup': 'report-group'
}
};
```
#### Why `vantiv`?
Worldpay’s Google Pay gateway identifier is:
```javascript theme={null}
gateway: 'vantiv'
```
It is **not** `'worldpay'`.
Using the wrong gateway value will cause processor token registration failures.
***
## Environment Configuration
### TEST
```javascript theme={null}
environment: 'TEST',
merchantId: '01234567890123456789'
```
* Google shared test merchant ID
* Use processor TEST credentials
* Use Revolv3 sandbox/UAT
### PRODUCTION
```javascript theme={null}
environment: 'PRODUCTION',
merchantId: 'YOUR_GOOGLE_BUSINESS_CONSOLE_ID'
```
You must:
* Register in Google Pay Business Console
* Verify domain
* Use production processor credentials
* Use Revolv3 production API
***
## Sale Request Example
Send the **entire** GooglePayPaymentDataResponse as a JSON string.
```json theme={null}
{
"IncludeRawProcessorResponse": true,
"PaymentMethod": {
"GooglePay": {
"GooglePayPaymentDataResponse": "{...full Google response JSON...}"
},
"BillingFullName": "Joe Smith",
"BillingAddress": {
"AddressLine1": "381 Forest Ave",
"City": "Laguna Beach",
"State": "CA",
"PostalCode": "92651",
"Country": "US"
}
},
"Invoice": {
"MerchantInvoiceRefId": "ORDER-12345",
"Amount": {
"Currency": "USD",
"Value": "12.20"
}
}
}
```
POST to:
```text theme={null}
/api/payments/sale
```
***
## Common Processor Error
### "Unable to register low-value Google Pay token"
Caused by:
* Using `DIRECT` instead of `PAYMENT_GATEWAY`
* Wrong `gateway` value (must be `'vantiv'` for Worldpay)
* Wrong merchant credentials
* Environment mismatch
***
## Environment Alignment Matrix
| Google Pay | Revolv3 | Processor |
| - | - | - |
| TEST | Sandbox/UAT | Test |
| PRODUCTION | Production | Production |
Mismatch will cause processor failures.
***
## Script Examples
Revolv3 provides:
* Google Pay HTML demo examples
* Sandbox testing pages
* Script-based examples for Worldpay (Vantiv)
* TEST/PRODUCTION toggle examples
Contact Revolv3 Support if you need:
* A working HTML prototype
* Worldpay-specific script example
* Processor credential guidance
***
## Best Practices
1. Always use `PAYMENT_GATEWAY`
2. Use `gateway: 'vantiv'` for Worldpay
3. Send full GooglePayPaymentDataResponse
4. Align environments
5. Test in sandbox before production
***
## Additional Resources
* [Google Pay Web Docs](https://developers.google.com/pay/api/web/overview) — Official Google Pay API documentation
* Contact Revolv3 Support for enablement
## Next Steps
* **[Using Apple Pay](/docs/core-concepts/paymentmethod/using-applepay)** — Learn about Apple Pay integration
* **[Create a Payment Method](/docs/core-concepts/paymentmethod/paymentmethod-guide)** — Store and reuse payment methods
* Contact Revolv3 Support to enable Google Pay for your account
# Decline Codes Reference
Source: https://docs.revolv3.com/docs/error-codes/decline-codes
A comprehensive reference for Revolv3 API payment decline codes. Understand why a transaction failed and how to handle the error.
When a payment fails, the processor returns a decline code that indicates why. Use this page to find where each processor documents its codes and to understand common categories.
## Understanding Decline Codes
* **Decline codes help identify the reason for failed transactions.**
* **Each payment processor has its own list of decline codes.**
* **Understanding decline codes helps merchants troubleshoot and improve transaction approval rates.**
## Processor-Specific Decline Codes
Below are links to **official processor documentation** for detailed decline code lists:
### Worldpay
[Worldpay Decline Codes](http://support.worldpay.com/support/CNP-API/content/paytransrespcodes.htm)
### Nuvei
[Nuvei Decline Codes](https://docs.nuvei.com/documentation/integration/response-handling/#gateway-decline-reasons)
### EPX
[EPX Decline Codes](https://developer.north.com/supplemental-resources/epx-data-dictionary/transaction-response-fields)
### Adyen
[Adyen Decline Codes](https://docs.adyen.com/development-resources/error-codes/)
For additional assistance, refer to each processor’s documentation or contact support. For additional assistance, refer to each processor's documentation or contact support via the portal (log in and use the help icon).
## Common Decline Code Categories
| **Category** | **Description** |
| - | - |
| **Insufficient Funds** | The cardholder’s account does not have enough balance to complete the transaction. |
| **Expired Card** | The credit/debit card used has expired. |
| **Incorrect Card Details** | The card number, CVV, or expiration date is incorrect. |
| **Fraud Suspected** | The transaction was flagged due to unusual activity. |
| **Processor Decline** | The payment processor rejected the transaction for unspecified reasons. |
| **Merchant Restrictions** | The merchant is not allowed to process payments in certain regions or categories. |
# Revolv3 API Response Codes and Errors
Source: https://docs.revolv3.com/docs/error-codes/error-responses
Comprehensive reference for HTTP status codes and error responses in the Revolv3 API.
This guide provides a detailed overview of all possible HTTP status codes returned by the Revolv3 API, including success responses, client errors, server errors, and infrastructure-related issues from Revolv3.
## Success Response Codes
These codes indicate successful operations.
| Status Code | Description |
| - | - |
| **200 (OK)** | Successful request with data returned in the response body. |
| **204 (No Content)** | Request successful, but no data to return (e.g., a successful deletion or update without content). |
## Error Response Codes
These codes signal issues with the request or server-side problems. Always check the response body for detailed error messages where applicable.
| Status Code | Description |
| - | - |
| **400 (Bad Request)** | Invalid field, value, or data formatting submitted. Includes validation errors. See the example below for details. |
| **404 (Not Found)** | Requested resource not found (e.g., customer, subscription, or invoice). |
| **422 (Unprocessable Entity)** | The request was well-formed but could not be processed. Check the error message or contact Revolv3 Support. |
| **429 (Too Many Requests)** | Rate limit exceeded. Limits: 20 calls per second or 20,000 calls per 15 minutes. Wait and retry after the limit resets. |
| **500 (Internal Server Error)** | Unexpected server error. Contact Revolv3 support if this persists. |
| **502 (Bad Gateway)** | Revolv3 application is down or unreachable. Contact Revolv3 support if this persists. |
| **503 (Service Unavailable)** | The service is temporarily unavailable, possibly due to maintenance or overload. Retry after a short delay. Contact Revolv3 support if this persists. |
| **504 (Gateway Timeout)** | Request timed out while waiting for a response from the server. This could occur if the API call exceeds processing time limits or there's a network issue. Retry the request. Contact Revolv3 support if this persists. |
## Handling Validation Errors (400 Bad Request)
For incorrect data formatting or validation failures, the API returns a 400 status with an array of errors in the response body. Example for an invalid expiration date format:
```json theme={null}
{
"message": "One or more validation failed.",
"fluentValidatorErrors": [
{
"propertyName": "OneTimePaymentWithoutSubscriptionRequest.PaymentMethod",
"errorMessage": "Expiration date needs to be in either one of the following format: MMYY, MMYYYY, MM/YY, and MM/YYYY.",
"attemptedValue": null,
"customState": null,
"severity": 0,
"errorCode": null,
"formattedMessagePlaceholderValues": null
}
]
}
```
## Handling Processor Failures (200 OK with Failure Status)
Even on a successful API call (200 OK), the payment processor may decline the transaction. The response includes a "Fail" status and a message. To include the full raw processor response, add `"includeRawProcessorResponse": true` to your payload.
Example response:
```json theme={null}
{
"customerId": null,
"invoiceId": 396247,
"merchantInvoiceRefId": "ABC309500654810",
"merchantPaymentMethodRefId": null,
"networkTransactionId": "451831812015385",
"invoiceStatus": "Noncollectable",
"invoiceAttemptStatus": "Fail",
"message": "Generic Decline",
"amount": {
"currency": "USD",
"value": 1.03
},
"paymentMethodId": 6445,
"paymentMethodTypeId": 1,
"rawResponse": null
}
```
## Retrieving Additional Invoice Details
For more information on a failed or successful invoice, use a GET request to the invoice endpoint:
`{{Api Root}}/api/Invoices/{{Active Invoice Id}}`
Example response:
```json theme={null}
{
"invoiceId": 292438,
"parentInvoiceId": null,
"customerId": null,
"merchantInvoiceRefId": "ABC309500654810",
"paymentMethod": {
"paymentMethodId": 6446,
"billingAddressId": 7528,
"billingFirstName": "Joe",
"billingLastName": "Smith",
"merchantPaymentMethodRefId": null,
"billingAddress": {
"addressId": 7528,
"addressLine1": "381 Forest Ave. Suite C",
"addressLine2": null,
"city": "Laguna Beach",
"state": "CA",
"postalCode": "92651",
"phoneNumber": null,
"email": null,
"country": "US"
},
"paymentMethodAchDetails": null,
"paymentMethodCreditCardDetails": {
"binNumber": "445700",
"paymentLast4Digit": "0005",
"paymentExpirationDate": "0330"
}
},
"invoiceStatus": "Noncollectable",
"subtotal": 1.03,
"tax": 0.00,
"total": 1.03,
"billingDate": "9/4/2024",
"merchantLegalName": "[TEST] WP House (MD Adyen Route)",
"merchantCustomerRefId": null,
"customerFirstName": null,
"customerLastName": null,
"subscriptionId": null,
"installmentId": null,
"eligibilityFailReason": null,
"merchantSubscriptionRefId": null,
"networkTransactionId": null,
"invoiceLineItems": [],
"invoiceAttempts": [
{
"invoiceAttemptId": 134495,
"amount": 1.03,
"invoiceAttemptStatus": "Fail",
"invoiceAttemptDate": "2024-09-04T18:35:39.95",
"paymentProcessor": "WorldPay",
"processorTransactionId": "84082941507574465",
"responseCode": "110",
"responseMessage": "Insufficient Funds",
"paymentMethod": {
"paymentMethodId": 6446,
"billingAddressId": 7528,
"billingAddress": {
"addressId": 7528,
"addressLine1": "381 Forest Ave. Suite C",
"addressLine2": null,
"city": "Laguna Beach",
"state": "CA",
"postalCode": "92651",
"phoneNumber": null,
"email": null,
"country": "US"
},
"billingFirstName": "Joe",
"billingLastName": "Smith",
"merchantPaymentMethodRefId": null,
"paymentMethodAchDetails": null,
"paymentMethodCreditCardDetails": {
"binNumber": "445700",
"paymentLast4Digit": "0005",
"paymentExpirationDate": "0330"
}
},
"eligibilityCheckOrderCode": null
}
]
}
```
## Best Practices for Error Handling
* **Retry Logic**: For 429, 502, 503, and 504 errors, implement exponential backoff retries.
* **Logging**: Capture response codes and bodies for debugging.
* **User Feedback**: Translate technical errors into user-friendly messages in your application.
* **Monitoring**: Track error rates to identify integration issues early.
For further assistance, contact Revolv3 support.
# Revolv3 FAQ
Source: https://docs.revolv3.com/docs/faq
Answers to common questions about Revolv3 API authentication, errors, environments, network transaction IDs, tokenization, and support.
## Question Index
### Authentication & API Keys
* [How do I use my Revolv3 static token for API authentication?](#faq-static-token-auth)
* [Why am I seeing "Attempted to perform an unauthorized operation"?](#faq-unauthorized-operation)
* [Why am I getting a 401 Unauthorized error?](#faq-401-unauthorized)
### Environments
* [How do I know if I'm using the correct API environment?](#faq-correct-environment)
### Network Transaction IDs & Subscriptions
* [What is a network transaction ID and where can I find it?](#faq-network-transaction-id)
* [If I change the payment method for a subscription, do I reuse the original networkTransactionId?](#faq-subscription-network-transaction-id)
### Tokenization & Vaulting
* [What is the difference between a processor token, a network token, and a Revolv3 payment method ID?](#faq-token-differences)
* [Will we receive the same token back or a new one? How should we map tokens?](#faq-token-mapping)
### Reporting & Reconciliation
* [How do we reconcile transactions routed through different processors?](#faq-reconciliation)
* [Can we see which processor handled each transaction?](#faq-processor-reporting)
### Support & Troubleshooting
* [Who do I contact for technical support?](#faq-technical-support)
* [How do I rotate or reset my API key?](#faq-rotate-api-key)
### Authentication & API Keys
#### Q: How do I use my Revolv3 static token for API authentication?
Include your static token in the `x-revolv3-token` header on every request. Never expose this token in client-side code; store it securely on the server.
Recommendation: Use environment variables and secrets management, and rotate keys periodically.
#### Q: Why am I seeing "Attempted to perform an unauthorized operation"?
This indicates an authentication or authorization issue. Common causes:
* Missing or incorrect `x-revolv3-token` header
* Using a token with insufficient permissions
* Token from the wrong environment (sandbox vs production)
Recommendation: Verify the header, confirm token scope, and ensure you're pointed at the correct API endpoint.
#### Q: Why am I getting a 401 Unauthorized error?
A 401 means authentication failed. Check for typos in the header, expired/revoked keys, and environment mismatches.
Recommendation: Log request headers server-side and include networkTransactionId when escalating to support.
***
### Environments
#### Q: How do I know if I’m using the correct API environment?
Use sandbox for development/testing and production for live processing:
* Sandbox portal: `portal-sandbox.revolv3.com`
* Production portal: `portal.revolv3.com`
* Sandbox API: `api-sandbox.revolv3.com`
* Production API: `api.revolv3.com`
Recommendation: Keep separate credentials per environment and never reuse sandbox static keys in production.
***
### Network Transaction IDs & Subscriptions
#### Q: What is a network transaction ID and where can I find it?
networkTransactionId is a unique identifier returned in API responses for each processed payment. Use it for tracking, reconciliation, and support.
Recommendation: Store networkTransactionId with your order and reconciliation records.
#### Q: If I change the payment method for a subscription, do I reuse the original networkTransactionId?
Short answer:
* If the change is an edit to the same card (same PAN/token, e.g., expiry update) — you may continue using the same networkTransactionId for that subscription.
* If it's a different card (different PAN/token) — obtain the new networkTransactionId and use that for subsequent recurring payments.
Why: vaulted payment methods can be linked to multiple subscriptions; storing the networkTransactionId on the vaulted method alone does not guarantee per-subscription continuity.
Recommendation: Maintain a subscription → networkTransactionId mapping in your system to ensure per-subscription continuity.
***
### Tokenization & Vaulting
#### Q: What is the difference between a processor token, a network token, and a Revolv3 payment method ID?
* Processor token: token issued by a specific processor.
* Network token: token issued at the card-network/tokenization layer.
* Revolv3 payment method ID: Revolv3's internal canonical ID that maps processor/network tokens to a single vaulted reference.
Recommendation: Keep a mapping table (processor token → Revolv3 ID) and prefer Revolv3 IDs in integration flows.
#### Q: Will we receive the same token back or a new one? How should we map tokens?
Revolv3 returns an internal payment method ID. Processor tokens may be preserved or normalized depending on the source. Implement a token-mapping strategy and store both external and internal IDs as needed.
Recommendation: Provide a token mapping export or API endpoint for reconciliation.
***
### Reporting & Reconciliation
#### Q: How do we reconcile transactions routed through different processors?
Match networkTransactionId, merchant order IDs, and processor response fields across exports. Use exportable reports and standardized templates for reconciliation.
Recommendation: Automate reconciliation with scripts that join exports on networkTransactionId and order IDs.
#### Q: Can we see which processor handled each transaction?
Yes — API responses and transaction records include a processor identifier field for filtering and reporting.
Recommendation: Include processor ID in reporting dashboards for faster root-cause analysis.
***
### Support & Troubleshooting
#### Q: Who do I contact for technical support?
For technical issues, log into the Revolv3 portal and use the **help icon** to submit a support ticket (or use the support channels provided during onboarding). Include networkTransactionId, request timestamps, and sample payloads when filing tickets.
Recommendation: Capture and attach request/response logs (server-side) when escalating to support.
#### Q: How do I rotate or reset my API key?
Rotate keys from the developer portal under Merchant Settings → Integration Profile. After rotation, update server-side secrets and deploy safely.
Recommendation: Use a staged key rotation process and test in sandbox before switching production keys.
# Getting Started with Revolv3
Source: https://docs.revolv3.com/docs/getting-started/getting-started
Your first guide to integrating with the Revolv3 API. Covers authentication, sandbox testing, and making your first API call successfully.
Welcome to the **Revolv3 Developer Hub**, your central resource for integrating payment processing into your application. Whether you're building an e-commerce site, a subscription service, or any application that needs to accept payments, this documentation will help you get up and running.
## What is Revolv3?
Revolv3 is a payment processing platform that acts as a smart layer between your application and multiple payment processors (the companies that actually move money between banks). Think of it like a universal translator for payments — instead of integrating directly with each payment processor (which can be complex and time-consuming), you integrate once with Revolv3, and we handle routing transactions to the right processor, managing retries, and optimizing for success rates.
**Why use a payment platform instead of integrating directly?**
* **Multiple processors**: If one processor is down or declines a transaction, Revolv3 can automatically try another one (called "fallback routing")
* **Simplified integration**: One API instead of learning multiple processor APIs
* **Better success rates**: Intelligent routing helps get more transactions approved
* **Security**: We handle sensitive payment data securely and help you stay compliant with industry standards
## Understanding Payment Processing Basics
If you're new to payment processing, here's what happens when a customer makes a purchase:
1. **Your app sends a payment request** to Revolv3 with the customer's payment details (card number, amount, etc.)
2. **Revolv3 routes the request** to a payment processor (like WorldPay, Nuvei, TSYS, Adyen, or others)
3. **The processor checks with the bank** to see if the customer has funds and approves the transaction
4. **Money moves** from the customer's account to your merchant account (this can take a few days to "settle")
5. **You get a response** telling you whether the payment succeeded or failed
The whole process usually takes just a few seconds, though some payment types (like [ACH bank transfers](/docs/core-concepts/paymentmethod/ach-direct-debit)) can take several business days to complete.
## About Revolv3's APIs
Revolv3 offers a comprehensive suite of APIs that let you:
* **Process payments** — Accept one-time payments, subscriptions, and installments
* **Store payment methods** — Securely save customer cards or bank accounts for future use (called "[tokenization](/docs/appendix/appendix-revolv3#tokenization)")
* **Handle refunds** — Issue full or partial refunds when customers return items
* **Manage subscriptions** — Set up recurring billing for services or products
* **Track everything** — Get detailed information about transactions, invoices, and payment attempts
To streamline your integration, our documentation includes:
* **Quickstart Guides** — Get up and running quickly with step-by-step examples
* **API Reference** — Complete details on every endpoint, request format, and response structure
* **Core Concepts** — Understand how payments, invoices, subscriptions, and other features work
* **Best Practices** — Learn how to optimize your payment flows and handle edge cases
## Your API Environment
Revolv3 provides two environments for development and production:
* **Sandbox** (`api-sandbox.revolv3.com`) — Use this for testing. It works just like production but uses test data and doesn't move real money.
* **Production** (`api.revolv3.com`) — Use this for live transactions with real customers and real money.
> **Important**: Always test thoroughly in sandbox before using production. Never use production API keys in your development environment.
Throughout this documentation, you'll see `{{Api Root}}` in code examples. Replace this with the appropriate base URL based on which environment you're using.
## 5-Minute Quickstart
This quickstart walks through the simplest sandbox flow:
1. Obtain a sandbox token
2. Create a payment with a sandbox test card
3. Receive the response
This example uses:
* **Sandbox API root**: `https://api-sandbox.revolv3.com`
* **Authentication header**: `x-revolv3-token`
* **Flow**: sandbox token -> direct sale request -> payment response
### Step 1: Obtain a Sandbox Token
First, create or copy a **Developer Static Token** from the sandbox portal:
1. Sign in to `portal-sandbox.revolv3.com`
2. Go to **Settings -> Integration Profile**
3. Open **Developer Static Tokens**
4. Create a token and keep it secure
You'll send that value in the `x-revolv3-token` header on every API request.
If you need the full walkthrough, see [**Authentication**](/docs/authentication-security/merchant-access-token).
### Step 2: Create a Payment
Submit a sale directly in sandbox using a test card:
```bash theme={null}
curl --location 'https://api-sandbox.revolv3.com/api/Payments/sale' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-revolv3-token: YOUR_SANDBOX_STATIC_TOKEN' \
--data '{
"NetworkProcessing": {
"ProcessingType": "initialInstallment",
"OriginalNetworkTransactionId": null
},
"CustomerId": null,
"PaymentMethod": {
"BillingAddress": {
"AddressLine1": "100 Main Street",
"AddressLine2": "",
"City": "Santa Ana",
"State": "CA",
"PostalCode": "90000",
"Country": "US"
},
"BillingFullName": "John Smith",
"CreditCard": {
"PaymentAccountNumber": "4111111111111111",
"ExpirationDate": "1030",
"SecurityCode": "123"
}
},
"Invoice": {
"MerchantInvoiceRefId": "QUICKSTART-ORDER-1001",
"Amount": {
"Value": 1.03
}
}
}'
```
This is the fastest way to test a sale in sandbox because it combines the card details and payment request in a single API call. If you want to store and reuse cards later, see [**Create a Payment Method**](/docs/core-concepts/paymentmethod/paymentmethod-guide).
For a deeper walkthrough of the payment flow, see [**Step-by-step "Make a Payment" example**](/docs/getting-started/make-a-payment).
### Step 3: Receive the Response
If the payment succeeds, you'll receive a response similar to this:
```json theme={null}
{
"InvoiceId": 575950,
"MerchantInvoiceRefId": "QUICKSTART-ORDER-1001",
"NetworkTransactionId": "295845970297960",
"InvoiceStatus": "Paid",
"InvoiceAttemptStatus": "Success",
"Message": "Approved",
"Amount": {
"Currency": "USD",
"Value": 1.03
},
"PaymentMethodId": 16336,
"PaymentMethodTypeId": 1,
"ResponseCode": "000"
}
```
The main fields to check are:
* `InvoiceAttemptStatus` -> confirms whether the payment attempt succeeded
* `Message` -> human-readable processor result
* `InvoiceId` -> Revolv3's invoice identifier for lookup and support
* `NetworkTransactionId` -> important for reconciliation and disputes
* `PaymentMethodId` -> the tokenized payment method created from this successful sale, which you can store for future reuse
## Related Guides
* [**Authentication**](/docs/authentication-security/merchant-access-token) -> Get your sandbox static token and required headers
* [**Step-by-step "Make a Payment" example**](/docs/getting-started/make-a-payment) -> Learn the full payment request and response
* [**Create a Payment Method**](/docs/core-concepts/paymentmethod/paymentmethod-guide) -> Tokenize and reuse cards securely
## Next Steps
Ready to start integrating? Here's a suggested path:
1. [**Authentication**](/docs/authentication-security/merchant-access-token) — Get your sandbox credentials and request headers in one place
2. [**Make a Payment**](/docs/getting-started/make-a-payment) — Process your first test transaction
3. [**Core Concepts**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Learn about payment methods, invoices, and subscriptions
4. [**API Reference**](https://docs.revolv3.com/api-reference/) — Explore all available endpoints
If you're already familiar with payment processing, you can jump straight to the [API Reference](https://docs.revolv3.com/api-reference/) for complete endpoint documentation.
***
# Postman Collection
Source: https://docs.revolv3.com/docs/getting-started/links-to-postman
Access Revolv3's Postman collections for easy API testing. Learn how to get the collections and use them to test your integration.
## What Are Postman Collections?
**Postman collections** are pre-configured API requests that make it easy to test the Revolv3 API without writing code. They include:
* All API endpoints pre-configured
* Example requests with sample data
* Environment variables for easy switching
* Documentation built into each request
**Why use them:**
* **Quick testing**: Test API calls without writing code
* **Learn the API**: See how requests should be structured
* **Debugging**: Test specific endpoints when troubleshooting
* **Documentation**: Built-in examples and descriptions
## How to Get Postman Collections
To get the latest Revolv3 Postman collection:
1. **Contact Revolv3 Support**
* Your Onboarding Team will provide you access to these collections when you get your Sandbox Credentials
2. **What you'll receive**
* Postman collection file
* Instructions for importing
* Environment files for sandbox and production
* Documentation on how to use it
## Using Postman Collections
Once you have the collection:
1. **Import into Postman**
* Open Postman
* Click "Import"
* Select the collection file
* Import any environment files
2. **Set up your environment**
* Create or use the provided environment
* Add your API key to environment variables
* Set the API root URL
3. **Start testing**
* Browse the collection for the endpoint you need
* Update request parameters as needed
* Send requests and view responses
## Benefits of Using Postman
* **No code required**: Test APIs without writing integration code
* **Visual interface**: See requests and responses clearly
* **Variable management**: Store API keys and URLs in variables
* **Team sharing**: Share collections with your team
## Alternative Testing Methods
If you don't use Postman, you can also test with:
* **curl**: Command-line tool (examples in our docs)
* **Your own code**: Write test scripts in your preferred language
* **Revolv3 Portal**: Some operations can be tested in the web portal
## Next Steps
* [**Authentication**](/docs/authentication-security/merchant-access-token) — Get your API token and required headers for testing
* [**Make a Payment**](/docs/getting-started/make-a-payment) — Process your first test payment
* [**Production vs Sandbox**](/docs/getting-started/production-vs-sandbox) — Understand which environment to use
***
# Step-by-step "Make a Payment" example
Source: https://docs.revolv3.com/docs/getting-started/make-a-payment
Learn how to process a payment with a real-world e-commerce scenario. Understand what happens behind the scenes when you charge a customer.
Let's walk through processing a payment using a real-world scenario: a customer buying a product from your online store. This example shows you how to charge a customer's card and understand what happens behind the scenes.
## Before You Start
Before initiating a payment request, make sure your account is properly configured with:
* A **supported payment processor** (like WorldPay, Adyen, Nuvei, TSYS) that's been set up in your merchant account
* A valid **static token** that you'll include in the `x-revolv3-token` request header for authentication
If you haven't set these up yet, check out [Authentication](/docs/authentication-security/merchant-access-token) first.
## Real-World Scenario: E-Commerce Checkout
Imagine a customer named John Doe is buying a \$1.03 product from your online store. They've entered their card information and clicked "Complete Purchase." Here's what happens:
1. **Your application collects** the customer's payment details (card number, billing address, amount)
2. **You send a request** to Revolv3 to process the payment
3. **Revolv3 routes the request** to a payment processor, which checks with the bank
4. **The bank approves or declines** the transaction
5. **You receive a response** telling you whether the payment succeeded
The whole process typically takes 2-3 seconds. If approved, the money is authorized (held) immediately, though it may take a few days to actually settle into your bank account.
## API Endpoint
Use the following endpoint to process a payment:
```
POST {{Api Root}}/api/payments/sale
```
Replace `{{Api Root}}` with:
* **Sandbox**: `api-sandbox.revolv3.com` (for testing)
* **Production**: `api.revolv3.com` (for live transactions)
## Sample Request: Charging a Customer
Here's what a payment request looks like for our example scenario:
```bash bash theme={null}
{
"NetworkProcessing": {
"ProcessingType": "initialInstallment",
"OriginalNetworkTransactionId": null
},
"CustomerId": null,
"PaymentMethod": {
"BillingAddress": {
"AddressLine1": "381 Forest Ave. Suite C",
"City": "Laguna Beach",
"State": "CA",
"PostalCode": "92651",
"Country": "USA"
},
"BillingFullName": "John Doe",
"CreditCard": {
"PaymentAccountNumber": "4444333322221111",
"ExpirationDate": "0330",
"SecurityCode": "737"
}
},
"Invoice": {
"MerchantInvoiceRefId": "ABC309500654810",
"Amount": {
"Value": 1.03
}
}
}
```
## Understanding the Request Fields
Let's break down what each part of the request does:
### NetworkProcessing
This tells Revolv3 how to classify the transaction, which affects how card networks process it:
* **`processingType`**:
* `initialInstallment` — First payment in a series of installments (like "buy now, pay later")
* `initialRecurring` — First payment in a subscription (like a monthly service)
* `installment` — Subsequent installment payment
* `recurring` — Subsequent subscription payment
* For a one-time purchase, use `initialInstallment`
* **`originalNetworkTransactionId`**: Leave this `null` for new transactions. You'd use this if you're referencing a previous transaction (like a refund or follow-up payment).
### CustomerId
This is optional. If you already have a customer record in Revolv3, provide their ID here. If you leave it `null`, Revolv3 may create a new customer profile automatically (depending on your settings). This is useful if you want to track all of a customer's purchases together.
### PaymentMethod
This contains the customer's payment information:
* **`BillingAddress`**: The address associated with the credit card. This is used for fraud prevention—banks check if the address matches what they have on file.
* **`BillingFullName`**: The name on the credit card. Can be a person's name or a company name. Use standard ASCII characters only (letters, numbers, spaces, hyphens).
* **`CreditCard`**:
* **`PaymentAccountNumber`**: The full credit card number (16 digits for most cards)
* **`ExpirationDate`**: Format is MMYY (e.g., "0330" means March 2030)
* **`SecurityCode`**: The CVV/CVC code (usually 3-4 digits on the back of the card)
> **Security Note**: Never store full card numbers or CVV codes in your database. Once you process a payment, you can store the `paymentMethodId` that Revolv3 returns and use that for future charges instead.
### Invoice
This represents the purchase being made:
* **`MerchantInvoiceRefId`**: Your internal order ID or invoice number. This helps you match Revolv3's response back to your system. Use something unique like "ORDER-12345" or a UUID.
* **`Amount.value`**: The amount to charge in USD (as a decimal number)
## What Happens Behind the Scenes
When you send this request, here's the flow:
1. **Revolv3 receives your request** and validates the format
2. **Revolv3 routes to a payment processor** (like WorldPay or Adyen) based on your merchant configuration
3. **The processor sends the request to the card network** (Visa, Mastercard, etc.)
4. **The card network checks with the bank** that issued the card:
* Is the card valid?
* Does the customer have enough funds?
* Is the billing address correct?
* Are there any fraud flags?
5. **The bank responds** with approval or decline
6. **The response flows back** through the network → processor → Revolv3 → your application
All of this happens in just a few seconds!
## Sample Response: Payment Approved
If everything goes well, you'll get a response like this:
```bash bash theme={null}
{
"CustomerId": null,
"InvoiceId": 185317,
"MerchantInvoiceRefId": "ABC309500654810",
"MerchantPaymentMethodRefId": null,
"NetworkTransactionId": "538302743384089",
"InvoiceStatus": "Paid",
"InvoiceAttemptStatus": "Success",
"Message": "Approved",
"Amount": {
"Currency": "USD",
"Value": 1.03
},
"PaymentMethodId": 6061,
"PaymentMethodTypeId": 1,
"PaymentProcessor": "WorldPay",
"ProcessorMerchantId": "10011222",
"RawResponse": null,
"PaymentMethodCreditCardDetails": {
"BinNumber": "444433",
"PaymentLast4Digit": "1111",
"PaymentExpirationDate": "1130",
"AccountUpdateMessage": null,
"AccountUpdateDateTime": null
},
"ResponseMessage": null,
"ResponseCode": "00"
}
```
## Understanding the Response
Here's what each field means and why it matters:
* **`invoiceId`**: Revolv3's unique identifier for this invoice. **Save this**—you'll need it for refunds, looking up the transaction, or customer support.
* **`merchantInvoiceRefId`**: Your original order ID, echoed back. Use this to match the response to your internal records.
* **`networkTransactionId`**: A unique ID assigned by the card network (Visa, Mastercard, etc.). This is crucial for disputes, [chargebacks](/docs/appendix/appendix-revolv3#chargeback), and reconciliation. **Always store this**. Learn more about [network transaction IDs](/docs/appendix/appendix-revolv3#network-transaction-id) in the glossary.
* **`invoiceStatus`**: The current status of the invoice. "Paid" means the payment was successful.
* **`invoiceAttemptStatus`**: The result of this specific payment attempt. "Success" means it went through.
* **`message`**: Human-readable result from the processor. "Approved" is what you want to see!
* **`amount`**: Confirms the currency and amount that was processed.
* **`paymentMethodId`**: If you want to charge this customer again later, you can use this ID instead of sending their full card details. This is called "[tokenization](/docs/appendix/appendix-revolv3#tokenization)" and is much more secure. Learn more in the [Payment Methods Guide](/docs/core-concepts/paymentmethod/paymentmethod-guide).
* **`paymentMethodTypeId`**: The type of payment method used:
* `1` = Credit Card
* `2` = ACH (bank transfer)
* `3` = Google Pay
* `4` = Apple Pay
* **`paymentProcessor`**: Which processor handled this transaction (useful for troubleshooting).
* **`paymentMethodCreditCardDetails`**:
* **`binNumber`**: First 6 digits of the card (identifies the bank)
* **`paymentLast4Digit`**: Last 4 digits (safe to display to customers)
* **`paymentExpirationDate`**: When the card expires
> **Optional Field**: You can include `"includeRawProcessorResponse": false` in your request if you don't need the full processor response. By default, it's `true`.
## What to Do Next
After a successful payment:
1. **Store the important IDs**: Save `invoiceId`, `networkTransactionId`, and `merchantInvoiceRefId` in your database. You'll need these for:
* Customer support ("I was charged twice!")
* Refunds
* Reconciliation (matching your records with bank statements)
* Disputes and chargebacks
2. **Handle the response in your code**:
* If `invoiceAttemptStatus` is "Success", show a confirmation page to the customer
* If it's anything else, check the `message` field for the reason and handle accordingly
3. **Consider storing the payment method**: If the customer might buy again, save the `paymentMethodId` so they don't have to re-enter their card next time.
4. **Update your order status**: Mark the order as "paid" in your system and trigger any fulfillment processes (send confirmation email, ship the product, etc.).
## Handling Errors
If a payment fails, the `invoiceAttemptStatus` will be something other than "Success", and the `message` field will explain why. Common reasons include:
* Insufficient funds
* Card expired
* Incorrect billing address
* Card reported as stolen
* Bank declined (fraud prevention)
Always show a helpful error message to your customer and give them a chance to try a different payment method.
## Next Steps
Now that you've processed a payment, explore these related topics:
* [**Payment Methods Guide**](/docs/core-concepts/paymentmethod/paymentmethod-guide) — Learn how to store payment methods securely for future use
* [**Authorizations & Captures**](/docs/integration-flows/authorizations-captures) — Understand the two-step payment process (useful for hotels, pre-orders, etc.)
* [**Refunds**](/docs/integration-flows/refunds) — Learn how to issue refunds when customers return items
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — Set up recurring billing for subscription services
***
# Production Environment Limitations
Source: https://docs.revolv3.com/docs/getting-started/production-limitations
Understand API rate limits and throttling for production. Learn the limits, what happens when you exceed them, and how to handle rate limit errors.
## Why Rate Limits Exist
Revolv3 enforces **rate limits** (also called "throttling") on API requests to:
* **Maintain performance**: Ensure the API stays fast for everyone
* **Prevent abuse**: Stop malicious or poorly-designed integrations from overwhelming the system
* **Ensure fairness**: Give all merchants equal access to resources
* **Protect infrastructure**: Keep the system stable under high load
Think of it like speed limits on a highway—they keep traffic flowing smoothly for everyone.
## Rate Limits for One-Time Payments
For one-time payment transactions, Revolv3 enforces the following rate limits:
### Per IP Address Limits
* **20 requests per second** per IP address
* **20,000 requests** within a rolling 15-minute window
**What this means:**
* You can make up to 20 API calls per second from the same IP address
* You can make up to 20,000 API calls in any 15-minute period
* Limits are tracked per IP address (so different servers have separate limits)
### How Throttling Works
* **IP-based**: Limits are applied per IP address making the requests
* **Automatic**: Revolv3 automatically enforces limits—no configuration needed
* **Rolling window**: The 15-minute limit uses a rolling window (not fixed 15-minute blocks)
## What Happens When You Exceed the Limit?
If you exceed the rate limits, Revolv3 will return a **429 Too Many Requests** HTTP status code.
### 429 Response
**Status Code**: `429 Too Many Requests`
**What it means:**
* You've made too many requests too quickly
* You need to slow down and wait before making more requests
* The limit will reset after a short period
**What to do:**
1. **Stop making requests immediately**
2. **Wait a few seconds** (or minutes if you hit the 15-minute limit)
3. **Retry with exponential backoff** (wait longer between retries)
4. **Implement rate limiting in your code** to prevent hitting limits
### Example 429 Response
```json theme={null}
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please retry after a few seconds.",
"retryAfter": 5
}
```
## Best Practices for Handling Rate Limits
### 1. Implement Exponential Backoff
When you get a 429 error, wait before retrying, and increase the wait time for each retry:
```javascript theme={null}
// Pseudo-code example
let retryDelay = 1; // Start with 1 second
const maxRetries = 5;
for (let i = 0; i < maxRetries; i++) {
try {
const response = await makeApiRequest();
return response;
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
await sleep(retryDelay);
retryDelay *= 2; // Double the delay each time
} else {
throw error;
}
}
}
```
### 2. Queue Requests
Instead of making requests immediately, queue them and process at a controlled rate:
* Use a message queue (RabbitMQ, AWS SQS, etc.)
* Process requests at a rate below the limit (e.g., 15 requests/second to stay safe)
* Batch requests when possible
### 3. Monitor Your Usage
Track how many requests you're making:
* Log request counts
* Monitor for 429 errors
* Set up alerts if you're approaching limits
* Review your code for unnecessary API calls
### 4. Optimize Your Integration
Reduce the number of API calls you need:
* **Batch operations**: Process multiple items in one request when possible
* **Cache responses**: Store data you've already fetched
* **Use webhooks**: Instead of polling, listen for events
* **Combine requests**: Get multiple pieces of data in one call when the API supports it
## Rate Limits for Other Operations
**Subscriptions and recurring payments** may have different rate limits. Check with Revolv3 support or your account manager for specific limits for your use case.
**Webhooks** (incoming from Revolv3) are not subject to these rate limits—you can receive as many webhooks as Revolv3 sends.
## Calculating Your Needs
**Example calculation:**
* 20 requests/second = 1,200 requests/minute = 72,000 requests/hour
* 20,000 requests per 15 minutes = \~1,333 requests/minute
**For most businesses:**
* These limits are more than sufficient
* You'd need very high transaction volume to hit them
* If you're hitting limits, you may need to optimize your integration
**If you need higher limits:**
* Contact Revolv3 support
* Explain your use case and volume
* They may be able to adjust limits for your account
## Common Scenarios
### Scenario 1: High-Volume Checkout
**Problem**: Processing many checkout requests simultaneously
**Solution**:
* Queue requests and process at a controlled rate
* Use webhooks instead of polling for status updates
* Batch operations when possible
### Scenario 2: Bulk Operations
**Problem**: Need to process many payments at once (e.g., payroll, bulk refunds)
**Solution**:
* Spread operations over time
* Process in batches with delays between batches
* Contact Revolv3 if you need to process very large batches
### Scenario 3: Retry Logic Causing Issues
**Problem**: Aggressive retry logic hitting rate limits
**Solution**:
* Implement exponential backoff
* Respect 429 responses (don't retry immediately)
* Add jitter (random delay) to prevent thundering herd
## Monitoring and Alerts
Set up monitoring to track:
* **Request rate**: How many requests per second you're making
* **429 errors**: When you hit rate limits
* **Response times**: Slow responses might indicate you're approaching limits
* **Error rates**: High error rates might indicate throttling issues
## Troubleshooting
### If You're Getting 429 Errors Frequently
1. **Check your request rate**: Count how many requests you're making per second
2. **Review your code**: Look for unnecessary API calls or tight loops
3. **Implement rate limiting**: Add client-side rate limiting to stay under limits
4. **Contact support**: If you legitimately need higher limits, Revolv3 may be able to help
### If You Need Higher Limits
Contact Revolv3 support with:
* Your use case and why you need higher limits
* Your expected request volume
* Your account information
They can evaluate your needs and potentially adjust limits.
## Summary
* **Rate limits**: 20 requests/second, 20,000 per 15 minutes (per IP)
* **429 errors**: You've exceeded the limit—slow down and retry
* **Best practice**: Implement exponential backoff and rate limiting in your code
* **Optimization**: Reduce API calls through batching, caching, and webhooks
* **Need more?**: Contact Revolv3 support if you need higher limits
## Next Steps
* **[Error Responses](/docs/error-codes/error-responses)** — Learn how to handle all API errors
* **[Production vs Sandbox](/docs/getting-started/production-vs-sandbox)** — Understand environment differences
* **[Webhooks](/docs/webhook-events/webhook)** — Use webhooks to reduce polling and API calls
***
# Production Environment vs Sandbox Environment
Source: https://docs.revolv3.com/docs/getting-started/production-vs-sandbox
Understand the differences between Revolv3's production and sandbox environments, when to use each, and how to switch from testing to live payments.
## Why Two Environments?
Revolv3 provides two separate environments so you can safely test your integration before processing real payments. This prevents mistakes, protects your customers, and ensures everything works correctly before going live.
## Sandbox Environment
The **sandbox** is a testing environment that mimics production but doesn't process real payments.
### What It's For
* **Development**: Build and test your integration
* **Testing**: Try different scenarios without risk
* **Learning**: Understand how the API works
* **Debugging**: Fix issues before going live
### Key Details
| Aspect | Details |
| - | - |
| **Portal URL** | [portal-sandbox.revolv3.com](https://portal-sandbox.revolv3.com) |
| **API URL** | `api-sandbox.revolv3.com` |
| **Real Money** | No — uses test data only |
| **Real Cards** | No — use test card numbers |
| **Credentials** | Separate sandbox API key |
| **Processors** | Uses processor test environments |
### When to Use Sandbox
* You're building your integration
* You're testing new features
* You're debugging issues
* You're learning how the API works
* You want to try different scenarios safely
> **Important**: Always test thoroughly in sandbox before using production. It's free, safe, and prevents costly mistakes.
## Production Environment
The **production** environment is for live payment processing with real customers and real money.
### What It's For
* **Live payments**: Process actual customer transactions
* **Real revenue**: Money actually moves
* **Customer data**: Real customer information
* **Business operations**: Your actual payment processing
### Key Details
| Aspect | Details |
| - | - |
| **Portal URL** | [portal.revolv3.com](https://portal.revolv3.com) |
| **API URL** | `api.revolv3.com` |
| **Real Money** | Yes — actual transactions |
| **Real Cards** | Yes — customer payment methods |
| **Credentials** | Separate production API key |
| **Processors** | Uses live processor systems |
### When to Use Production
* Your integration is tested and ready
* You've completed [certification](/docs/certification-go-live/checklist) (if required)
* You're ready to process real payments
* You understand the API and error handling
> **Critical**: Only use production when you're confident your integration works correctly. Mistakes here affect real customers and real money.
## Key Differences
| Feature | Sandbox | Production |
| - | - | - |
| **Purpose** | Testing and development | Live payment processing |
| **Money** | Test transactions only | Real money moves |
| **Cards** | Test card numbers | Real customer cards |
| **API Key** | Separate sandbox key | Separate production key |
| **Portal** | `portal-sandbox.revolv3.com` | `portal.revolv3.com` |
| **API Endpoint** | `api-sandbox.revolv3.com` | `api.revolv3.com` |
| **Rate Limits** | May differ from production | Production limits apply |
| **Support** | For testing issues | For production issues |
## Switching from Sandbox to Production
When you're ready to go live, follow these steps:
### 1. Complete Testing
* Test all payment flows in sandbox
* Test error handling and edge cases
* Verify webhooks work correctly
* Test with different payment methods
* Complete any required [certification](/docs/certification-go-live/checklist)
### 2. Request Production Access
See the [Certification & Go-Live Checklist](/docs/certification-go-live/checklist) for how to request production access, certification steps (if required), and contact points.
### 3. Get Production Credentials
Revolv3 will provide:
* Production portal login
* Production API key (different from sandbox)
* Production merchant account setup
* Any processor-specific credentials
### 4. Update Your Integration
Update your code to use production endpoints and credentials:
**Before (Sandbox):**
```bash theme={null}
API_URL = "https://api-sandbox.revolv3.com"
API_KEY = "your-sandbox-key"
```
**After (Production):**
```bash theme={null}
API_URL = "https://api.revolv3.com"
API_KEY = "your-production-key"
```
> **Important**: Use environment variables or configuration files so you can easily switch between environments.
### 5. Test in Production (Carefully)
* Start with a small test transaction
* Verify the payment processes correctly
* Check that webhooks are received
* Monitor for any errors
* Gradually increase volume
## Important Notes
### Credentials Don't Cross Over
* **Sandbox credentials won't work in production**
* **Production credentials won't work in sandbox**
* **Always use the correct credentials for each environment**
### Keep Environments Separate
* Use separate API keys for sandbox and production
* Don't mix test data with production data
* Keep separate code branches or configurations if needed
* Never use production keys in development
### Testing in Production
If you need to test in production (after going live):
* Use small amounts
* Test with your own payment methods
* Be careful not to charge real customers during testing
* Consider using a test mode or staging account if available
## Best Practices
1. **Always test in sandbox first**: Never skip sandbox testing
2. **Use environment variables**: Store API keys and URLs in config, not hardcoded
3. **Keep credentials separate**: Never mix sandbox and production credentials
4. **Monitor carefully**: Watch for errors when first going live
5. **Have a rollback plan**: Know how to quickly switch back if needed
## Common Questions
**Q: Can I use the same API key for both environments?** A: No. Sandbox and production have separate API keys. You'll get a new key when you're approved for production.
**Q: Will my sandbox data transfer to production?** A: No. Sandbox and production are completely separate. You'll start fresh in production.
**Q: How long can I use sandbox?** A: As long as you need. Sandbox is free and available for ongoing testing and development.
**Q: What if I make a mistake in production?** A: Contact Revolv3 support immediately. They can help you resolve issues, process refunds if needed, and prevent further problems.
## Next Steps
* [**Authentication**](/docs/authentication-security/merchant-access-token) — Get your sandbox and production credentials
* [**Production Limitations**](/docs/getting-started/production-limitations) — Understand rate limits and throttling
* [**Sandbox Environment Limitations**](/docs/testing-sandbox/sandbox-environment-limitations) — Learn about sandbox-specific limitations
* [**Make a Payment**](/docs/getting-started/make-a-payment) — Process your first test payment in sandbox
***
# ACH Payment Flow
Source: https://docs.revolv3.com/docs/integration-flows/ach-payment-flow
End-to-end ACH payment flow: verification and settlement. Sequence diagram and how timing differs from card payments. Links to ACH direct debit and test data.
This page describes how ACH (bank account) payments move through Revolv3: from your request through verification and settlement. ACH is **not** instant like card payments; it uses batch processing and can take several business days.
## Flow Overview
| Phase | What happens | Typical timing |
| - | - | - |
| **Submit** | You send the ACH payment request; Revolv3 accepts it. | Immediate |
| **Verification / processing** | Banks and the ACH network process the transaction in batches. | 1–3 business days |
| **Settlement** | Funds are debited from the customer’s account and credited to yours. | Day 3–5 (business days) |
## Sequence: ACH Payment (Verification and Settlement)
```mermaid theme={null}
sequenceDiagram
participant App as Your app
participant Revolv3 as Revolv3 API
participant Processor as ACH processor
participant ACH as ACH network
participant Bank as Customer bank
App->>Revolv3: POST payment (ACH details, amount, invoice)
Revolv3->>Processor: Submit ACH debit
Processor->>ACH: Batch entry
Revolv3-->>App: 200 + attempt id, status Pending
Note over ACH,Bank: 1–3 business days
ACH->>Bank: Debit request
Bank-->>ACH: Accept/reject
ACH-->>Processor: Result
Processor-->>Revolv3: Status update (e.g. Paid / Noncollectable)
Note over Revolv3: Webhook / polling
Revolv3-->>App: Event or GET attempt: Paid or failed
```
**Important**: The API returns quickly with a “pending” attempt. Final outcome (e.g. `Paid`, `Noncollectable`) comes later via webhooks or by polling invoice/attempt status.
## Why ACH Takes Multiple Days
ACH does not authorize and settle in real time like cards. Transactions are batched and processed on business days by the ACH network and banks. For more detail, see [ACH Direct Debit Payments](/docs/core-concepts/paymentmethod/ach-direct-debit).
## Sample ACH Request (summary)
* **Endpoint**: Use the same payment/invoice flow as for cards, but send **ACH** details instead of `CreditCard` in `PaymentMethod` (e.g. routing number, account number, account type).
* **Base URL**: Use your environment (e.g. `https://api-sandbox.revolv3.com` for sandbox).
* **Response**: You get an attempt ID and a status such as `Pending`; final status is updated when the ACH cycle completes.
For full ACH object shape, required fields, and test values, see [ACH Direct Debit Payments](/docs/core-concepts/paymentmethod/ach-direct-debit) and [Test ACH for Account Verification](/docs/testing-sandbox/test-ach-for-validate-person).
## Where to Go Next
* [ACH Direct Debit Payments](/docs/core-concepts/paymentmethod/ach-direct-debit) — When to use ACH, object structure, and timing
* [Test ACH for Account Verification](/docs/testing-sandbox/test-ach-for-validate-person) — Sandbox test data for ACH
# Payment Authorizations & Captures
Source: https://docs.revolv3.com/docs/integration-flows/authorizations-captures
Learn when and why to use the two-step authorization and capture flow. Perfect for hotels, pre-orders, and scenarios where you need to reserve funds before charging.
## Why Authorization and Capture?
Most payments are simple: you charge the customer immediately and you're done. But sometimes you need to **reserve funds** without actually charging them right away. That's where authorization and capture comes in.
**Authorization** = "Can this customer pay $100? If yes, hold that $100 for me."
**Capture** = "Actually charge that \$100 you're holding."
Think of it like a hotel room: when you check in, they authorize your card (put a hold on funds) but don't charge you yet. When you check out, they capture the funds (actually charge you) for the final amount (which might be different if you used the minibar or had room service).
## When to Use Authorization & Capture
Use this two-step process when:
* **You don't know the final amount yet** (hotels, car rentals, restaurants with tips)
* **You want to verify the card before shipping** (pre-orders, custom products)
* **You need to hold funds temporarily** (deposits, reservations)
* **The service happens over time** (subscriptions that start later, services with variable pricing)
**When NOT to use it**: For simple e-commerce purchases where you know the exact amount and want to charge immediately, use the regular [sale endpoint](/docs/getting-started/make-a-payment) instead.
## Real-World Use Cases
### Hotel Booking
1. **Check-in**: Authorize \$200 (estimated room + incidentals)
2. **During stay**: Customer might use room service, minibar, etc.
3. **Check-out**: Capture the actual amount (maybe \$250 after incidentals)
### Pre-Order Products
1. **Customer pre-orders**: Authorize the full amount to verify their card is valid
2. **Product ships**: Capture the funds when you actually ship (weeks or months later)
3. **If customer cancels**: Reverse the authorization, no charge
### Restaurant with Tips
1. **Customer orders**: Authorize the bill amount
2. **Customer adds tip**: Capture the total (bill + tip)
3. **Or if they walk out**: Capture just the bill amount
### Custom Products
1. **Customer orders custom item**: Authorize to verify payment method
2. **You build the product**: Takes time, customer's card is verified
3. **You ship**: Capture when ready to charge
## How Authorization & Capture Works
Here's the flow:
1. **Authorize** → Bank checks if customer has funds, puts a hold on the money
2. **Wait** → Funds are reserved but not charged (authorization lasts \~7 days)
3. **Capture** → Actually charge the customer (can be same amount or different)
4. **Or Reverse** → Release the hold if you don't need to charge
The key difference from a regular sale:
* **Regular sale**: Authorize + Capture happens immediately in one step
* **Authorization/Capture**: You control when each step happens
## Step 1: Authorize a Payment
When you authorize, you're asking the bank "Can this customer pay \$X?" If yes, they put a hold on that amount. The customer's available balance decreases, but the money hasn't actually been charged yet.
### API Endpoint
```
POST {{Api Root}}/api/Payments/authorization
```
### Sample Authorization Request
```bash bash theme={null}
{
"PaymentMethod": {
"BillingAddress": {
"AddressLine1": "100 Main",
"AddressLine2": null,
"City": "Santa Ana",
"State": "CA",
"PostalCode": "91111",
"Country": "US"
},
"BillingFullName": "John Doe",
"CreditCard": {
"PaymentAccountNumber": "4111111111111111",
"ExpirationDate": "1025" // Format: MMYY
}
},
"NetworkProcessing": {
"ProcessingType": "initialInstallment",
"OriginalNetworkTransactionId": null
},
"Amount": {
"Value": 30.99 // Amount to authorize (hold)
}
}
```
### Understanding the Request
| **Field** | **Description** |
| - | - |
| `PaymentMethod` | The customer's payment details (card, billing address, etc.) |
| `BillingAddress` | Cardholder's billing address (used for fraud prevention) |
| `BillingFullName` | Name on the credit card |
| `CreditCard.PaymentAccountNumber` | Full credit card number |
| `CreditCard.ExpirationDate` | Card expiration in MMYY format (e.g., "1025" = October 2025) |
| `NetworkProcessing.ProcessingType` | Transaction type. Use `initialInstallment` for one-time authorizations |
| `Amount.Value` | How much to authorize (hold). This can be your best estimate—you can capture a different amount later |
### Alternative: Authorize with Stored Payment Method
If you already have a `paymentMethodId` (from a previous transaction), you can use that instead of sending full card details:
```
POST {{Api Root}}/api/Payments/authorization/{paymentMethodId}
```
**Request** (much simpler—no card details needed):
```bash bash theme={null}
{
"NetworkProcessing": {
"processingType": "initialInstallment",
"originalNetworkTransactionId": null
},
"Amount": {
"value": 1.03
}
}
```
### Authorization Response
When authorization succeeds, you'll get back a `paymentMethodAuthorizationId`—this is what you'll use to capture or reverse the payment later.
```bash bash theme={null}
{
"networkTransactionId": "431241081661798",
"paymentMethodAuthorizationId": 2055, // ⭐ Save this! You'll need it to capture
"paymentMethod": {
"paymentMethodId": 6061,
"billingAddressId": 7056,
"billingAddress": {
"addressId": 7056,
"addressLine1": "381 Forest Ave. Suite C",
"addressLine2": null,
"city": "Laguna Beach",
"state": "CA",
"postalCode": "92651",
"phoneNumber": null,
"email": null,
"country": "US"
},
"billingFirstName": "Joe",
"billingLastName": "Smith",
"merchantPaymentMethodRefId": null,
"paymentMethodCreditCardDetails": {
"paymentLast4Digit": "1111",
"paymentExpirationDate": "0330"
}
}
}
```
### Understanding the Response
| **Field** | **Description** |
| - | - |
| `paymentMethodAuthorizationId` | **The most important field**—save this! You'll need it to capture or reverse the payment |
| `networkTransactionId` | Unique ID from the card network. Store this for your records |
| `paymentMethod.paymentMethodId` | If a payment method was created, you can use this for future transactions |
| `paymentMethodCreditCardDetails.paymentLast4Digit` | Last 4 digits of the card (safe to display) |
> **Important**: Store the `paymentMethodAuthorizationId` immediately. You'll need it to capture or reverse, and authorizations expire after about 7 days.
## Step 2: Capture the Payment
Once you're ready to actually charge the customer, you "capture" the authorized amount. You can capture:
* The same amount you authorized
* A different amount (more or less)
* But you can't capture more than you authorized
### API Endpoint
```
POST {{Api Root}}/api/Payments/capture/{paymentMethodAuthorizationId}
```
Replace `{paymentMethodAuthorizationId}` with the ID you got from the authorization response.
### Sample Capture Request
```bash bash theme={null}
{
"CustomerId": null, // Optional: link to a customer record
"Invoice": {
"MerchantInvoiceRefId": "ABC309500654810", // Your order/invoice ID
"Amount": {
"value": 1.03 // Amount to capture (can be different from authorized amount)
}
}
}
```
### Understanding the Request
| **Field** | **Description** |
| - | - |
| `CustomerId` | Optional. Link this payment to a customer record in Revolv3 |
| `Invoice.MerchantInvoiceRefId` | Your internal order or invoice ID (for tracking) |
| `Invoice.Amount.value` | **The amount to actually charge**. This can be: |
* Same as authorized amount
* Less than authorized (e.g., authorized $200, capture $150)
* But NOT more than authorized |
### Key Notes About Capturing
* ✅ **You must capture within \~7 days** of authorization, or it expires
* ✅ **You can capture a different amount** than you authorized (as long as it's not more)
* ✅ **You can only capture once** per authorization
* ❌ **If authorization expires**, you'll need to authorize again
### Capture Response
The capture response looks similar to a regular payment response:
```bash bash theme={null}
{
"invoiceId": 185317,
"merchantInvoiceRefId": "ABC309500654810",
"networkTransactionId": "538302743384089",
"invoiceStatus": "Paid",
"invoiceAttemptStatus": "Success",
"message": "Approved",
"amount": {
"currency": "USD",
"value": 1.03
},
"paymentMethodId": 6061,
"paymentProcessor": "WorldPay"
}
```
At this point, the customer has been charged and you can fulfill the order.
## Step 3: Reversing an Authorization (Optional)
If you authorized funds but decide you don't need to charge the customer (they cancelled, you can't fulfill the order, etc.), you can **reverse** the authorization to release the hold.
### API Endpoint
```
POST {{Api Root}}/api/PaymentMethod/reverse-auth
```
### Sample Reversal Request
```bash theme={null}
{
"PaymentMethodAuthorizationId": 2055 // The authorization ID from step 1
}
```
### What Happens When You Reverse
* ✅ The hold on the customer's funds is released immediately
* ✅ Their available balance goes back to normal
* ✅ They were never charged
* ❌ You can't capture this authorization anymore (it's cancelled)
**When to reverse**:
* Customer cancels before you capture
* You can't fulfill the order
* You want to release the hold for any reason
> **Note**: If you don't capture or reverse, the authorization will automatically expire after \~7 days and the hold will be released. But it's better to explicitly reverse if you know you won't capture.
## Complete Example: Hotel Booking Flow
Let's walk through a real scenario:
### Day 1: Customer Checks In
**1. Authorize for estimated amount:**
```bash theme={null}
POST /api/Payments/authorization
{
"Amount": { "Value": 200.00 }, // Estimated: $150 room + $50 incidentals
"PaymentMethod": { /* card details */ }
}
```
**Response:**
```bash theme={null}
{
"paymentMethodAuthorizationId": 2055,
"networkTransactionId": "431241081661798"
}
```
✅ Customer's card is verified, \$200 is held
### Day 2-3: Customer Stays
Customer uses room service, minibar, etc. You track the actual charges.
### Day 3: Customer Checks Out
**2. Capture the actual amount:**
```bash theme={null}
POST /api/Payments/capture/2055
{
"Invoice": {
"MerchantInvoiceRefId": "HOTEL-12345",
"Amount": { "value": 187.50 } // Actual: $150 room + $37.50 incidentals
}
}
```
**Response:**
```bash theme={null}
{
"invoiceStatus": "Paid",
"invoiceAttemptStatus": "Success"
}
```
✅ Customer is charged $187.50 (less than the $200 hold)
✅ The remaining \$12.50 hold is automatically released
## Authorization vs. Regular Sale: When to Use Which?
| Scenario | Use Authorization/Capture | Use Regular Sale |
| - | - | - |
| E-commerce (known amount, ship immediately) | ❌ | ✅ |
| Hotel booking (variable final amount) | ✅ | ❌ |
| Pre-order (charge when shipped) | ✅ | ❌ |
| Subscription (recurring, known amount) | ❌ | ✅ |
| Custom product (verify card, charge later) | ✅ | ❌ |
| Restaurant (bill + tip) | ✅ | ❌ |
| Digital product (instant delivery) | ❌ | ✅ |
## Best Practices
1. **Store authorization IDs immediately**: You'll need them to capture or reverse
2. **Set reminders**: Authorizations expire in \~7 days—don't forget to capture
3. **Capture the right amount**: You can capture less than authorized, but not more
4. **Reverse when appropriate**: If you won't capture, reverse to release the hold quickly
5. **Handle expiration**: If an authorization expires, you'll need to authorize again
6. **Use webhooks**: Get notified when captures complete or authorizations expire
## Common Questions
**Q: Can I capture more than I authorized?**
A: No. You can capture the same amount or less, but not more. If you need more, authorize again for the additional amount.
**Q: What happens if I don't capture?**
A: The authorization expires after \~7 days and the hold is automatically released. The customer is never charged.
**Q: Can I capture multiple times?**
A: No, each authorization can only be captured once. If you need to charge more, create a new authorization.
**Q: How long do authorizations last?**
A: Typically 7 days, but this can vary by processor. Check with Revolv3 support for your specific processor's expiration time.
## Next Steps
* **[Make a Payment](/docs/getting-started/make-a-payment)** — Learn about regular one-step payments
* **[Payment Methods](/docs/core-concepts/paymentmethod/paymentmethod-guide)** — Store payment methods for faster checkout
* **[Refunds](/docs/integration-flows/refunds)** — Learn how to refund captured payments
***
# Card Payment Flow
Source: https://docs.revolv3.com/docs/integration-flows/card-payment-flow
End-to-end card payment flow: sale vs auth/capture. Sequence diagrams and sample requests for immediate charge and two-step authorize-then-capture.
This page describes how card payments move through Revolv3: **sale** (one-step charge) and **authorization then capture** (two-step hold and charge).
## Flow Overview
You can charge a card in two ways:
| Flow | When to use | Steps |
| - | - | - |
| **Sale** | You know the amount and want to charge now (e.g. e‑commerce) | One request; Revolv3 authorizes and captures in a single step. |
| **Auth / Capture** | You need to hold funds first and charge later (e.g. hotel, restaurant) | 1) Authorize to hold funds. 2) Capture (same or different amount) when ready. |
## Sequence: Sale (One-Step Charge)
```mermaid theme={null}
sequenceDiagram
participant App as Your app
participant Revolv3 as Revolv3 API
participant Processor as Payment processor
participant Bank as Issuing bank
App->>Revolv3: POST /payments/sale (amount, card, invoice)
Revolv3->>Processor: Route payment
Processor->>Bank: Authorize + capture
Bank-->>Processor: Approve/decline
Processor-->>Revolv3: Result
Revolv3-->>App: 200 + payment details or error
```
**When to use**: Checkout when the amount is known and you want to charge immediately. See [Step-by-step "Make a Payment" example](/docs/getting-started/make-a-payment) for a full request/response example.
## Sequence: Authorization Then Capture
```mermaid theme={null}
sequenceDiagram
participant App as Your app
participant Revolv3 as Revolv3 API
participant Processor as Payment processor
participant Bank as Issuing bank
App->>Revolv3: POST /payments/authorization (amount, card)
Revolv3->>Processor: Authorize only
Processor->>Bank: Hold funds
Bank-->>Processor: Approved
Processor-->>Revolv3: Authorization ID
Revolv3-->>App: 200 + authorization id
Note over App,Bank: Later: capture or void
App->>Revolv3: POST /payments/{id}/capture (final amount)
Revolv3->>Processor: Capture
Processor->>Bank: Charge held amount
Bank-->>Processor: Captured
Processor-->>Revolv3: Result
Revolv3-->>App: 200 + capture details
```
**When to use**: When the final amount is unknown at auth time (e.g. hotel, restaurant, pre‑order). See [Payment Authorizations & Captures](/docs/integration-flows/authorizations-captures) for endpoints, sample requests, and responses.
## Sample Sale Request (summary)
Use your environment base URL (e.g. `https://api-sandbox.revolv3.com` for sandbox) as the API root.
* **Endpoint**: `POST /api/payments/sale`
* **Body**: `PaymentMethod` (e.g. `CreditCard` + `BillingAddress`), `Invoice` (e.g. `Amount`, `MerchantInvoiceRefId`), optional `CustomerId`, optional `NetworkProcessing`.
For a full example with all fields, see [Make a Payment](/docs/getting-started/make-a-payment).
## Sample Auth Request (summary)
* **Endpoint**: `POST /api/payments/authorization`
* **Body**: Same shape as sale (amount, card, billing). Revolv3 holds funds and returns an authorization ID. You then call **Capture** or **Void** before the auth expires.
For full request/response samples, see [Authorizations & Captures](/docs/integration-flows/authorizations-captures).
## Where to Go Next
* [Make a Payment](/docs/getting-started/make-a-payment) — Full sale example and field descriptions
* [Payment Authorizations & Captures](/docs/integration-flows/authorizations-captures) — Auth/capture flow, samples, and voids
# Processing Refunds
Source: https://docs.revolv3.com/docs/integration-flows/refunds
Learn when and how to issue refunds, including full and partial refunds. Understand refund scenarios, timing, and how to handle returns in your application.
## What is a Refund?
A **refund** returns money to a customer for a previous payment. This is different from canceling a payment before it's processed—refunds are for payments that have already been completed.
**Common scenarios:**
* Customer returns a product
* Service was not delivered as promised
* Customer cancels and is eligible for a refund
* Partial refund for damaged items or partial service
* Customer dispute resolution
## Why Partial Refunds Exist
Sometimes you need to refund only part of a payment:
**Real-world examples:**
* **Multi-item order**: Customer returns 2 out of 5 items → Partial refund for those 2 items
* **Service cancellation**: Customer cancels mid-month → Refund for unused portion
* **Damaged goods**: Product arrived damaged but customer keeps it → Partial refund as compensation
* **Shipping issues**: Order delayed, customer gets partial refund for inconvenience
* **Subscription proration**: Customer cancels subscription, refund unused portion of current period
**Benefits of partial refunds:**
* Better customer experience (fair refunds)
* Flexibility in handling edge cases
* Can issue multiple partial refunds (as long as total doesn't exceed original amount)
## Refund Basics
### What You Can Refund
* **Any amount up to the original payment** (excluding taxes, see below)
* **Multiple partial refunds** (as long as the total doesn't exceed the original)
* **Full refund** (returns the entire amount)
* **Cannot refund more than the original payment**
* **Cannot refund if already fully refunded**
### Important Limitations
> **Note**: Currently, Revolv3 supports refunds only for transactions processed by Revolv3. If a payment was processed by another payment service provider (PSP), you'll need to handle the refund through that provider.
## How Refunds Work
Here's the process:
1. **You issue a refund** via API or portal
2. **Revolv3 processes the refund** through the same processor that handled the original payment
3. **Money is returned** to the customer's original payment method
4. **Timing varies**:
* **Credit cards**: Usually 3-10 business days to appear on customer's statement
* **ACH**: 1-5 business days (similar to ACH payments)
The customer sees the refund on their credit card statement or bank account, but it's not instant—it takes a few days to process.
### Refund Flow Sequence
```mermaid theme={null}
sequenceDiagram
participant App as Your app
participant Revolv3 as Revolv3 API
participant Processor as Payment processor
participant Bank as Issuing bank
App->>Revolv3: POST /invoices/{invoiceId}/refund (amount optional)
Revolv3->>Revolv3: Validate invoice, amount
Revolv3->>Processor: Refund request (same processor as original)
Processor->>Bank: Credit customer
Bank-->>Processor: Accepted
Processor-->>Revolv3: Refund result
Revolv3-->>App: 200 + refund details
```
## Processing a Refund via API
### API Endpoint
```
POST {{Api Root}}/api/Invoices/{invoiceId}/refund
```
Replace `{invoiceId}` with the invoice ID from the original payment.
### Required Parameters
* **`invoiceId`** (in URL): The invoice ID of the original payment transaction. You get this from the payment response when you first charged the customer.
* **`amount`** (in request body, optional): The refund amount.
* If not provided, defaults to full refund
* Must be less than or equal to the original amount (excluding taxes)
### Sample Refund Request
**Full refund** (return entire amount):
```bash bash theme={null}
POST /api/Invoices/237058/refund
{
// No amount specified = full refund
}
```
**Partial refund** (return specific amount):
```bash bash theme={null}
POST /api/Invoices/237058/refund
{
"amount": 1.03 // Refund $1.03 (must be ≤ original amount)
}
```
### Understanding the Request
| **Parameter** | **Description** |
| - | - |
| `invoiceId` | The invoice ID from the original payment. This links the refund to the original transaction. |
| `amount` | Optional. Refund amount (excluding taxes). If omitted, refunds the full amount. |
> **Important**: The refund amount is specified **excluding taxes**. If the original payment included tax, Revolv3 will automatically calculate and refund the proportional tax amount. See the Taxes section below for details.
## Refund Response
When you issue a refund, Revolv3 creates a new invoice for the refund and returns details:
```bash bash theme={null}
{
"invoice": {
"invoiceId": 237059, // New invoice ID for this refund
"parentInvoiceId": 237058, // Links back to original payment
"customerId": null,
"merchantInvoiceRefId": null,
"paymentMethod": {
"paymentMethodId": 6469,
"billingAddressId": 7551,
"billingFirstName": "Joe",
"billingLastName": "Smith",
"billingAddress": {
"addressId": 7551,
"addressLine1": "381 Forest Ave. Suite C",
"city": "Laguna Beach",
"state": "CA",
"postalCode": "92651",
"country": "US"
},
"paymentMethodCreditCardDetails": {
"binNumber": "444433",
"paymentLast4Digit": "1111",
"paymentExpirationDate": "0330"
}
},
"invoiceStatus": "Refund", // Status indicates this is a refund
"subtotal": 1.03,
"tax": 0.0,
"total": 1.03,
"billingDate": "7/11/2024"
},
"refunds": [
{
"invoiceAttemptId": 114130,
"amount": -1.03, // Negative amount indicates refund
"invoiceAttemptStatus": "Success",
"invoiceAttemptDate": "2024-07-11T18:19:28.6971789Z",
"paymentProcessor": "WorldPay",
"processorTransactionId": "84082561857760470",
"responseCode": "000",
"responseMessage": "Approved"
}
],
"refundedSubtotal": 1.03, // Total refunded so far (subtotal)
"refundedTax": 0.0000, // Total tax refunded
"refundedTotal": 1.03 // Total refunded (subtotal + tax)
}
```
### Understanding the Response
| **Field** | **Description** |
| - | - |
| `invoice.invoiceId` | New invoice ID created for this refund. Save this for your records. |
| `invoice.parentInvoiceId` | Links back to the original payment invoice. |
| `invoice.invoiceStatus` | Will be `"Refund"` for full refunds or `"PartialRefund"` for partial refunds. |
| `refunds[].invoiceAttemptStatus` | Status of the refund attempt. `"Success"` means it was processed. |
| `refunds[].amount` | Negative amount (indicates money going back to customer). |
| `refundedSubtotal` | Total amount refunded so far (excluding tax). |
| `refundedTax` | Total tax refunded so far. |
| `refundedTotal` | Total refunded (subtotal + tax). |
## Understanding Taxes in Refunds
Tax handling can be confusing. Here's how it works:
### If Original Payment Had No Tax
If the original payment didn't include tax:
* Refund the amount you specify (or full amount if not specified)
* No tax calculation needed
### If Original Payment Included Tax
If the original payment included tax (e.g., from a subscription):
**For full refunds:**
* Specify the refund amount excluding taxes
* Revolv3 automatically refunds the full tax amount as well
* Customer gets back: refund amount + full tax
**For partial refunds:**
* Specify the refund amount excluding taxes
* Revolv3 automatically calculates proportional tax
* Example: If original was \$100 + \$10 tax = \$110 total, and you refund \$50:
* Customer gets: \$50 (subtotal) + \$5 (proportional tax) = \$55 total
**If you don't specify an amount:**
* Defaults to full refund (including all taxes)
### Example: Tax Refund Calculation
**Original payment:**
* Subtotal: \$100.00
* Tax: \$10.00
* Total: \$110.00
**Partial refund of \$50:**
```bash theme={null}
POST /api/Invoices/12345/refund
{
"amount": 50.00 // Excluding tax
}
```
**Result:**
* Refunded subtotal: \$50.00
* Refunded tax: \$5.00 (proportional: 50% of original tax)
* Total refunded: \$55.00
## Processing Refunds via Portal
You can also issue refunds through the Revolv3 portal:
1. Go to the **Invoices** screen
2. Select the invoice you want to refund
3. Click **Refund** in the Invoice section
4. Choose:
* **Full refund**: Return the entire amount
* **Partial refund**: Enter a specific amount
5. Click **Refund** to process
The portal shows the original transaction amount (excluding taxes) and lets you enter a different amount for partial refunds.
## Real-World Refund Scenarios
### Scenario 1: Customer Returns One Item from Multi-Item Order
**Original order:**
* Item A: \$30.00
* Item B: \$20.00
* Item C: \$15.00
* Total: \$65.00
**Customer returns Item B:**
```bash theme={null}
POST /api/Invoices/12345/refund
{
"amount": 20.00 // Refund for Item B
}
```
**Result**: Customer gets \$20.00 back. Order status: Partial refund. You can refund more later if needed.
### Scenario 2: Subscription Cancellation with Proration
**Original subscription:**
* Monthly fee: \$29.99
* Customer paid on the 1st
* Customer cancels on the 15th (halfway through month)
**Refund calculation:**
* Unused portion: \$29.99 / 2 = \$14.99
```bash theme={null}
POST /api/Invoices/12345/refund
{
"amount": 14.99 // Prorated refund
}
```
**Result**: Customer gets \$14.99 back for the unused portion.
### Scenario 3: Multiple Partial Refunds
**Original order:** \$100.00
**First refund:** \$30.00 (customer returns one item)
```bash theme={null}
POST /api/Invoices/12345/refund
{ "amount": 30.00 }
```
**Second refund:** \$20.00 (compensation for delay)
```bash theme={null}
POST /api/Invoices/12345/refund
{ "amount": 20.00 }
```
**Total refunded:** \$50.00 **Remaining:** \$50.00 (can still refund up to this amount)
### Scenario 4: Full Refund
**Customer wants to return entire order:**
```bash theme={null}
POST /api/Invoices/12345/refund
// No amount = full refund
```
**Result**: Customer gets the full amount back. Invoice status: `Refund`.
## Why Refunds Fail
Refunds can fail validation for several reasons:
| **Reason** | **Explanation** |
| - | - |
| **Amount too high** | Requested refund exceeds the original payment amount (excluding taxes) |
| **Already fully refunded** | The invoice has already been fully refunded, no remaining amount |
| **Partial refunds exceed total** | Sum of all partial refunds would exceed the original amount |
| **Invoice not found** | The invoice ID doesn't exist or wasn't processed by Revolv3 |
**What to do if refund fails:**
* Check the error message for the specific reason
* Verify the invoice ID is correct
* Check how much has already been refunded
* Ensure the amount is valid
## Refund Timing Considerations
### Credit Card Refunds
* **Processing time**: Usually processed within 1-2 business days
* **Customer sees it**: 3-10 business days on their statement (depends on their bank)
* **Best practice**: Tell customers it takes 5-10 business days to appear
### ACH Refunds
* **Processing time**: 1-5 business days (similar to ACH payments)
* **Customer sees it**: When the ACH batch processes
* **Best practice**: Tell customers it takes 3-5 business days
### Important Notes
* **Refunds are not instant**: Even though Revolv3 processes them quickly, banks take time to post them
* **Set customer expectations**: Always tell customers when to expect the refund
* **Track refund status**: Use webhooks or API polling to know when refunds complete
* **Keep records**: Store refund invoice IDs for customer support and reconciliation
## Best Practices
1. **Store original invoice IDs**: You'll need them to issue refunds
2. **Set customer expectations**: Tell them refunds take 5-10 business days
3. **Handle partial refunds gracefully**: Have a clear policy on when partial refunds are appropriate
4. **Track refund history**: Keep records of all refunds for customer support
5. **Use webhooks**: Get notified when refunds complete
6. **Reconcile regularly**: Match refunds with your accounting records
7. **Have a refund policy**: Clear policy helps avoid disputes
## Common Questions
**Q: Can I refund more than the original payment?** A: No, you can only refund up to the original payment amount (excluding taxes).
**Q: How long do refunds take?** A: Revolv3 processes them quickly (1-2 days), but banks take 3-10 business days to show them on customer statements.
**Q: Can I cancel a refund?** A: No, once a refund is issued, it cannot be cancelled. You'd need to charge the customer again if you made a mistake.
**Q: What if the customer's card is expired?** A: The refund will still go through—banks handle expired card refunds automatically.
**Q: Can I refund to a different payment method?** A: No, refunds always go back to the original payment method. If the customer wants a different method, you'd need to process it as a new transaction.
## Next Steps
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand refund statuses (`Refund`, `PartialRefund`)
* [**Subscriptions**](/docs/core-concepts/subscription/canceling-a-subscription) — Learn about canceling subscriptions and refunds
* [**Webhooks**](/docs/webhook-events/webhook) — Set up notifications for refund completions
***
# Shopify Integration
Source: https://docs.revolv3.com/docs/plugins/shopify
Integrate Shopify checkout with Revolv3 using a Custom Payment App (Credit Card Payment Extension).
## Overview
Shopify is a fully hosted eCommerce platform that provides a secure, optimized checkout experience, including built-in handling of sensitive payment data.
Through Shopify’s Custom Payment App (Credit Card Payment Extension), merchants can integrate external payment providers while preserving a native checkout flow.
With the Revolv3 Shopify Integration, customers enter their card details in Shopify Checkout and Revolv3 processes the payment in the background.
Shopify is responsible for collecting and tokenizing card data, while Revolv3 handles payment processing, routing, and communication with downstream processors.
This architecture delivers a seamless, secure, fully embedded checkout experience without redirects.
## Key Features
* Seamless checkout experience (no redirects)
* Card data handled securely by Shopify
* Revolv3 processes payments via configured processor
* Support for charge and refund operations
## Architecture
The integration includes the following components:
* **Shopify Checkout** – collects and tokenizes card data
* **Shopify Payment Extension** – app installed by merchant
* **Revolv3 Integration Service** – backend handling payment requests
* **Processor** – executes transaction processing
### High-Level Flow
Shopify Checkout → Revolv3 Integration → Processor → Revolv3 → Shopify
In short:
* Shopify handles customer interaction and card data
* Revolv3 handles payment processing and routing
## Payment Flow
Here’s the integration flow at a glance: a charge (payment) and then a refund.
```mermaid theme={null}
flowchart TD
subgraph Charge [Charge - Payment]
A1[Customer enters card details in Shopify Checkout] --> B1[Shopify tokenizes card data]
B1 --> C1[Shopify sends request to Revolv3]
C1 --> D1[Revolv3 transforms request to processor format]
D1 --> E1[Payment is processed by the processor]
E1 --> F1[Revolv3 returns response]
F1 --> G1[Shopify updates order status]
end
subgraph Refund
A2[Merchant initiates refund in Shopify Admin] --> B2[Shopify sends request to Revolv3]
B2 --> C2[Revolv3 sends refund request to processor]
C2 --> D2[Processor returns result]
D2 --> E2[Revolv3 returns response to Shopify]
E2 --> F2[Shopify updates refund status]
end
```
### Charge (Payment)
1. Customer enters card details in Shopify Checkout
2. Shopify tokenizes card data
3. Shopify sends request to Revolv3
4. Revolv3 transforms request to processor format
5. Payment is processed by the processor
6. Revolv3 returns response
7. Shopify updates order status
### Refund
1. Merchant initiates refund in Shopify Admin
2. Shopify sends request to Revolv3
3. Revolv3 sends refund request to processor
4. Processor returns result
5. Revolv3 returns response to Shopify
6. Shopify updates refund status
## Supported Features
| Feature | Status | Notes |
| - | - | - |
| Card Payments | Supported | Shopify Checkout |
| Charge (Sale) | Supported | Immediate processing |
| Refund | Supported | Via Shopify Admin |
| 3DS | Not supported | Planned for future |
| Auth/Capture split | Not supported | Sale only |
| Void | Not supported | Not available |
| Subscriptions | Not supported | Out of scope |
# FAQ
Source: https://docs.revolv3.com/docs/plugins/shopify-faq
Frequently asked questions about using Revolv3 with Shopify.
## Frequently Asked Questions (FAQ)
Below are answers to the questions merchants ask most often when using Revolv3 with Shopify.
## Question Index
* [Do I need any technical setup to use Revolv3?](#faq-technical-setup)
* [Where do my customers enter their card details?](#faq-card-details)
* [Will customers be redirected to another page?](#faq-redirects)
* [What payment methods are supported?](#faq-payment-methods)
* [Can I issue refunds?](#faq-refunds)
* [Can I void a transaction?](#faq-void)
* [Do you support 3D Secure (3DS)?](#faq-3ds)
* [Why can’t I activate Revolv3 in Shopify?](#faq-activate)
* [Who should I contact if something doesn’t work?](#faq-support-contact)
### Do I need any technical setup to use Revolv3?
No. There is no manual configuration required.
You only need to install the Revolv3 payment app in Shopify, connect your account, and activate it. All technical setup is handled automatically.
### Where do my customers enter their card details?
Customers enter their card details directly in Shopify checkout.
Revolv3 processes the payment securely in the background.
### Will customers be redirected to another page?
No. The entire checkout process happens within Shopify.
There are no redirects to external payment pages.
### What payment methods are supported?
Currently supported:
* Credit cards
* Debit cards
Not supported (yet):
* Apple Pay
* Google Pay
* Alternative payment methods
### Can I issue refunds?
Yes. You can issue refunds directly from Shopify Admin.
Revolv3 will process the refund automatically.
### Can I void a transaction?
No. Void functionality is not supported in the current version.
### Do you support 3D Secure (3DS)?
Not at the moment.
3DS support is planned for a future release.
### Why can’t I activate Revolv3 in Shopify?
Most likely reason:
* Your store domain has not been configured in Revolv3
Make sure you complete the setup in the Revolv3 portal before returning to Shopify.
### Who should I contact if something doesn’t work?
Please contact your Revolv3 support team or account manager.
# Quick Start
Source: https://docs.revolv3.com/docs/plugins/shopify-quick-start
Set up Revolv3 as a payment provider in Shopify and activate payments.
## Quick Start
To get started with Revolv3 as a payment provider:
1. Install the Revolv3 payment app in Shopify
2. Log in to Revolv3 portal when prompted
3. Add your store domain
4. Activate the payment provider in Shopify
### Step 1: Open Payment Settings
From Shopify Admin:
* Log in to your Shopify Admin
* Go to **Settings → Payments**


### Step 2: Add Revolv3
* Click **See all providers**
* Search for **Revolv3**
* Select it as your payment provider

### Step 3: Connect Your Account
* Grant required permissions. You must grant Revolv3 access to read and write payment sessions
* You will be redirected to Revolv3
* Log in to your Revolv3 account. You need to log in and specify your store's domain in the merchant settings
* Add your store domain
### Step 4: Activate Payments
* Return to Shopify
* Click **Activate**

> [!TIP]
>
> Your store is ready to accept payments.
> [!WARNING]
>
> ### Important Note
>
> You must complete the Revolv3 setup (including store domain configuration), otherwise the Activate button will remain disabled.
## Configuration
> [!NOTE]
>
> No manual configuration is required from the merchant side.
All technical setup, including:
* payment processing endpoints
* processor configuration
* security setup
is handled automatically by Revolv3 during onboarding and app installation.
Merchants only need to install and activate the Revolv3 payment app in Shopify.
## Backend Responsibilities
The Revolv3 backend handles:
* Processing payment session requests
* Processing refund session requests
* Mapping Shopify requests to Revolv3 API
* Handling processor communication
* Returning Shopify-compliant responses
## Testing
Once you’ve activated Revolv3 in Shopify, test the integration in the following environments:
* Shopify Partner Development Store
* Revolv3 Sandbox
* Shopify test card numbers
Then validate the integration behaves as expected for:
* Payment flow
* Refund flow
* Error handling
* Webhook processing
## Limitations
Current implementation limitations:
* Card payments only
* No 3DS support
* No auth/capture separation
* No void functionality
* No alternative payment methods
* No subscriptions
## Troubleshooting
### Common Issues
**Payment not processed**
* Check endpoint availability
* Verify API credentials
* Validate request schema
**Activation button disabled**
* Ensure store domain is configured in Revolv3
# Security & Compliance
Source: https://docs.revolv3.com/docs/plugins/shopify-security-compliance
How Revolv3 keeps Shopify card data secure and minimizes PCI scope.
## Security & Compliance
Revolv3 is designed to provide secure and compliant payment processing while minimizing the compliance burden for merchants.
> [!NOTE]
>
> The key security model is that card data stays with Shopify, while Revolv3 works with tokenized payment information.
### Card Data Handling
* Card details are entered directly in Shopify Checkout
* Shopify securely handles and tokenizes card data
* Revolv3 receives only tokenized payment information
* Revolv3 does not store or process raw cardholder data
### PCI DSS Scope
Since card data is collected and processed by Shopify, merchants using Revolv3 fall under a reduced PCI DSS scope (SAQ-A).
This means:
* No direct handling of card data by the merchant
* No storage of sensitive card information
* Simplified PCI compliance requirements
Revolv3 operates as a PCI-compliant payment gateway and processes transactions using secure, tokenized data.
### Secure Communication
All communication between Shopify and Revolv3 is secured using industry-standard mechanisms:
* Encrypted HTTPS connections
* HMAC-SHA256 signature verification
* Certificate-based validation
* Domain verification (store-level access control)
### Data Protection & Privacy
Revolv3 supports Shopify’s data protection requirements and complies with applicable regulations such as GDPR and CCPA.
The integration includes mandatory webhook handling for:
* Customer data access requests
* Customer data deletion requests
* Shop data deletion requests
Revolv3 processes such requests within the required regulatory timeframes.
### Key Security Principles
* No card data exposure outside Shopify
* Tokenized payment processing
* Encrypted data transmission
* Strict access control per merchant/store
## Deployment Model
### Shopify
* App registration via Partner Dashboard
* Payment extension configuration
* Endpoint registration
### Revolv3
* Backend hosted externally (e.g. Azure Functions)
* Payment processing logic
* Database and configuration
Note: No backend code is deployed to Shopify
## Summary
The Shopify–Revolv3 integration provides a seamless way to process card payments directly within Shopify checkout while leveraging Revolv3 as the payment gateway.
This integration:
* Minimizes PCI scope
* Ensures secure processing
* Provides scalable backend architecture
* Aligns with Shopify payment platform requirements
# Sandbox Environment Limitations
Source: https://docs.revolv3.com/docs/testing-sandbox/sandbox-environment-limitations
Understand the limitations and constraints of the Revolv3 sandbox environment. Learn about data retention, maintenance windows, and transaction limits.
## Why Sandbox Has Limitations
The **sandbox environment** is designed for testing, not production workloads. It has limitations to:
* **Prevent abuse**: Stop people from using sandbox for production traffic
* **Manage resources**: Keep sandbox costs reasonable
* **Simulate real conditions**: Some limitations mirror production constraints
* **Maintain stability**: Ensure sandbox stays available for all developers
**Important**: These limitations apply to sandbox only. Production has different (typically higher) limits.
## WorldPay Sandbox Limitations
If you're using WorldPay as your processor, these limitations apply in sandbox:
### Data Retention Policy
* **Maximum retention**: Data is retained for a maximum of **30 days**
* **Purges may occur more frequently**: Depending on system capacity and maintenance
* **Advanced notification**: You'll be notified when possible before data purges
**What this means**:
* Test data older than 30 days may be deleted
* Don't rely on sandbox data for long-term testing
* Export or document important test data if you need it longer
### Maintenance Windows
WorldPay sandbox has scheduled maintenance:
**General maintenance**:
* **Days**: Tuesdays and Thursdays
* **Time**: 4:00 AM to 8:00 AM ET
* **Impact**: Sandbox may be unavailable during these windows
**Enterprise eProtect maintenance**:
* **Frequency**: Every other Thursday
* **Time**: 10:00 PM to 6:00 AM ET
* **Impact**: eProtect features may be unavailable
**What to do**:
* Plan testing around maintenance windows
* Don't schedule critical tests during maintenance
* Check WorldPay status if sandbox seems unavailable
### Transaction Limits
**Online transactions**:
* **Daily limit**: 1,000 transactions per day
* **Shared capacity**: This is shared across all sandbox users, so your actual limit may be lower during peak usage
**Batch transactions**:
* **Daily limit**: 10,000 batch transactions per day
**What this means**:
* Don't run high-volume load tests in sandbox
* If you hit limits, wait until the next day
* For high-volume testing, contact Revolv3 about production testing options
## General Sandbox Limitations
### Behavior Differences
Sandbox may behave differently from production in:
* **Tokenization**: Token behavior may differ
* **Account Updater**: Only supported by WorldPay in sandbox
* **Settlement timing**: May be faster or slower than production
* **Processor responses**: Some processors have different sandbox behaviors
### Rate Limits
* Sandbox has rate limits (similar to production)
* May be more restrictive than production
* Check with Revolv3 for specific sandbox rate limits
### Test Data
* Use only test card numbers and test ACH data
* Real card numbers will be declined in sandbox
* Test data is provided by each processor
## Best Practices
1. **Plan around maintenance**: Avoid critical testing during maintenance windows
2. **Don't rely on long-term data**: Export important test data before 30 days
3. **Respect transaction limits**: Don't exceed daily limits
4. **Test incrementally**: Build up test volume gradually
5. **Use production for load testing**: Sandbox isn't for high-volume testing
## Getting Latest Information
For the most current WorldPay sandbox limitations, refer to:
[WorldPay Sandbox Limits Documentation](http://support.worldpay.com/support/CNP-API/content/preliveenvlimits.htm)
WorldPay's documentation is the authoritative source for their specific limitations.
## Common Questions
**Q: Why is my sandbox data gone?**
A: Sandbox data is retained for a maximum of 30 days. Older data may be purged.
**Q: Can I increase sandbox transaction limits?**
A: Sandbox limits are set by the processors. Contact Revolv3 if you need higher limits for testing.
**Q: What if sandbox is down during maintenance?**
A: Wait until maintenance completes. Maintenance windows are scheduled and temporary.
**Q: Can I use sandbox for production-like load testing?**
A: No, sandbox has lower limits. Use production (carefully) or contact Revolv3 for load testing options.
## Next Steps
* **[Test Cards for Sandbox](/docs/testing-sandbox/test-cards-for-sandbox)** — Get test card numbers
* **[Production vs Sandbox](/docs/getting-started/production-vs-sandbox)** — Understand environment differences
* **[Production Limitations](/docs/getting-started/production-limitations)** — See production rate limits
***
# Test ACH for Account Verification
Source: https://docs.revolv3.com/docs/testing-sandbox/test-ach-for-validate-person
Test data for ACH account verification in sandbox. Use these test values to verify bank accounts before processing ACH payments.
## What is ACH Account Verification?
**ACH account verification** (also called "validate person") checks if a bank account is valid and belongs to the person you think it does. This helps:
* **Reduce fraud**: Verify accounts before processing payments
* **Prevent failures**: Catch invalid accounts early
* **Improve success rates**: Only process payments for verified accounts
**When to use it**: Before processing an ACH payment, especially for recurring billing or large amounts.
## How Verification Works
1. **You send account details** to the verification API
2. **Verification provider checks** with the bank
3. **You get a response** telling you if the account is valid
4. **If valid**: Proceed with the ACH payment
5. **If invalid**: Don't process the payment, ask customer for correct information
## Test Data by Verification Provider
The test data you use depends on which verification provider is configured in your Revolv3 account. You can select the provider in the portal (Settings → Merchant Settings).
### WorldPay Verification
Use this test data when WorldPay is your verification provider:
```bash bash theme={null}
{
"FirstName": "John",
"LastName": "Doe",
"Address": {
"AddressLine1": "200 Main St",
"City": "King City",
"State": "CA",
"PostalCode": "93930",
"Country": "USA",
"PhoneNumber": "408-555-1212"
},
"Ach": {
"AccountNumber": "4099999992",
"RoutingNumber": "011075123",
"AccountType": "Checking"
}
}
```
**What to expect**: This should return a successful verification response if WorldPay is configured.
### GIACT Verification
Use this test data when GIACT is your verification provider:
```bash bash theme={null}
{
"FirstName": "Robert",
"LastName": "Williams",
"Address": {
"AddressLine1": "100 Main St",
"City": "Little Elm",
"State": "TX",
"PostalCode": "75068",
"Country": "USA",
"PhoneNumber": "18425551234"
},
"Ach": {
"AccountNumber": "0000000018",
"RoutingNumber": "122105123",
"AccountType": "Checking"
}
}
```
**What to expect**: This should return a successful verification response if GIACT is configured.
## Important Notes
### Provider Selection
* **Only one active**: Only one verification provider can be active at a time
* **Changeable**: You can switch providers in the portal if needed
* **Check your settings**: Verify which provider is active before testing
### Test Data Requirements
* **Use exact values**: Test data must match exactly (account numbers, routing numbers, addresses)
* **Provider-specific**: Each provider has different test data
* **Address matters**: The address values are important for verification
## Best Practices
1. **Verify before charging**: Always verify accounts before processing ACH payments
2. **Use correct test data**: Match the test data to your active verification provider
3. **Handle failures**: If verification fails, don't proceed with the payment
4. **Test both scenarios**: Test both successful and failed verifications
## Next Steps
* **[ACH Direct Debit](/docs/core-concepts/paymentmethod/ach-direct-debit)** — Learn about ACH payments
* **[Account Verification API](https://docs.revolv3.com/api-reference/)** — See the full verification API documentation
* **[Sandbox Test Cards](/docs/testing-sandbox/test-cards-for-sandbox)** — Test credit card payments
***
# Test Cards for Sandbox
Source: https://docs.revolv3.com/docs/testing-sandbox/test-cards-for-sandbox
Complete list of test credit card numbers for the Revolv3 sandbox. Test different payment scenarios, responses, and decline codes safely.
## What are Test Cards?
**Test cards** are fake credit card numbers that work in the sandbox environment. They let you test payment flows without using real cards or moving real money.
**Why use test cards:**
* **Safe testing**: No risk of accidentally charging real cards
* **Predictable results**: Each test card returns a specific response
* **Test scenarios**: Simulate approvals, declines, and errors
* **Free**: No cost to test as much as you want
**Important**: Test cards **only work in sandbox**. They will be declined in production. Always use sandbox (`api-sandbox.revolv3.com`) when testing.
## Sandbox Behavior and Limitations
### ACH Transactions
* **Status**: ACH transactions typically start in `Pending` status
* **Settlement**: Can take 1-2 business days to settle (even in sandbox)
* **Webhooks**: Use webhooks to receive status updates when ACH completes
### Account Updater
* **Sandbox support**: Account Updater in sandbox is only supported by WorldPay
* **Other processors**: May not show account updates in sandbox
### Rate Limits
* Sandbox has rate limits and simulator constraints
* Test high-volume flows carefully
* Some behaviors may differ from production
## WorldPay Test Cards
WorldPay provides comprehensive test card documentation. For the most up-to-date list, see:
[WorldPay Test Card Documentation](http://support.worldpay.com/support/CNP-API/content/testresprea.htm)
### Example: Successful Payment
```json theme={null}
{
"CreditCard": {
"PaymentAccountNumber": "4444333322221111",
"ExpirationDate": "0330",
"SecurityCode": "737"
}
}
```
**Result**: Payment should be approved.
### Example: Declined Payment
```json theme={null}
{
"CreditCard": {
"PaymentAccountNumber": "4457002900000007",
"ExpirationDate": "0330",
"SecurityCode": "737"
}
}
```
**Result**: Payment will be declined with "Generic Decline" message.
**Response example**:
```json theme={null}
{
"invoiceStatus": "Noncollectable",
"invoiceAttemptStatus": "Fail",
"message": "Generic Decline"
}
```
### WorldPay ACH Test Data
For testing ACH payments with WorldPay:
```json theme={null}
{
"ACH": {
"RoutingNumber": "011075150",
"AccountNumber": "1099999999",
"AccountType": "Checking"
}
}
```
For ACH testing, WorldPay provides test data:
[WorldPay ACH Test Data](http://support.worldpay.com/support/CNP-API/content/testddtrans.htm)
### WorldPay Account Updater
For testing Account Updater functionality:
[WorldPay Account Updater Test Cards](http://support.worldpay.com/support/CNP-API/content/testaccupdate.htm#TABLE_2-20)
**Example**:
```json theme={null}
{
"CreditCard": {
"PaymentAccountNumber": "5112010000047111",
"ExpirationDate": "0899",
"SecurityCode": 737
}
}
```
## Adyen Test Cards
Adyen provides test card numbers for their sandbox environment:
[Adyen Test Card Numbers](https://docs.adyen.com/development-resources/testing/test-card-numbers)
### Example
```json theme={null}
{
"CreditCard": {
"PaymentAccountNumber": "4444333322221111",
"ExpirationDate": "0330",
"SecurityCode": "737"
}
}
```
## Nuvei Test Cards
Nuvei provides test cards for sandbox testing:
[Nuvei Test Cards Documentation](https://docs.nuvei.com/documentation/integration/testing/testing-cards/)
### ACH Test Data
For successful ACH responses in Nuvei sandbox:
```json theme={null}
{
"ACH": {
"RoutingNumber": "011075150",
"AccountNumber": "1099999999",
"AccountType": "Checking"
}
}
```
### ACH Decline Test Cases
To test ACH declines, use these values:
**For declined deposits or pre-approvals:**
* **Account number**: `3666394279`
* **Routing number**: `123456780`
**Trigger amounts** (use these specific amounts to trigger different responses):
* **NSF (Insufficient Funds)**: Use amount `1.27`
* **Declined response**: Use amount `1.30`
**Example request**:
```json theme={null}
{
"ACH": {
"RoutingNumber": "123456780",
"AccountNumber": "3666394279",
"AccountType": "Checking"
},
"Invoice": {
"Amount": {
"value": 1.27 // Triggers NSF response
}
}
}
```
## EPX Test Cards
EPX (PaymentHub) provides test card data:
### Credit Card Test Data
* **Payment Account Number**: `4000000000000002`
* **Security Code**: `123`
* **Expiration Date**: Any future date (must be greater than current date)
* **Amount for success**: Use `1.00` for successful transactions
[EPX Test Data Documentation](https://developer.paymentshub.com/supplemental-resources/epx-credit-card-test-data)
### Example Request
```json theme={null}
{
"CreditCard": {
"PaymentAccountNumber": "4000000000000002",
"ExpirationDate": "1225",
"SecurityCode": "123"
},
"Invoice": {
"Amount": {
"value": 1.00 // Use 1.00 for success
}
}
}
```
### EPX Test Amounts
Different amounts trigger different responses. See the EPX documentation for the complete table, or refer to the image in the documentation:

**Note**: Create a developer account with EPX to see the most up-to-date test card options.
## TSYS Test Cards
### Visa Test Card
* **Card number**: `4012000098765439`
* **Expiration**: `12/25`
* **CVV**: `999`
* **Amount for success**: `0.52`
### MasterCard Test Cards
* **Card number**: `5146 XXXX 3150 0000` or `5146 XXXX 3122 0000`
* Use standard expiration and CVV
### Testing Billing Address
For TSYS, the billing address values are important and trigger different results:
```json theme={null}
{
"BillingAddress": {
"AddressLine1": "100 Main St",
"City": "Tempe",
"State": "AZ",
"PostalCode": "85284",
"Country": "USA"
}
}
```
**Important**: The address values matter for TSYS—different addresses can trigger different test responses.
## Best Practices for Testing
1. **Use sandbox**: Always test in sandbox (`api-sandbox.revolv3.com`) before production
2. **Test all scenarios**: Test both success and failure cases
3. **Use webhooks**: Set up webhooks to test async scenarios (like ACH)
4. **Test edge cases**: Try different amounts, expired cards, etc.
5. **Keep test data separate**: Don't mix test and production data
## Common Questions
**Q: Can I use these cards in production?** A: No, test cards only work in sandbox. They will be declined in production.
**Q: Do test cards expire?** A: Use future expiration dates. The exact date doesn't matter as long as it's in the future.
**Q: What if a test card doesn't work?** A: Check the processor documentation for the most current test cards. Test card numbers can change.
**Q: Can I test all decline codes?** A: Different processors support different test scenarios. Check each processor's documentation for specific decline codes.
## Next Steps
* [**Test ACH Validation**](/docs/testing-sandbox/test-ach-for-validate-person) — Learn about ACH account verification testing
* [**Sandbox Limitations**](/docs/testing-sandbox/sandbox-environment-limitations) — Understand sandbox constraints
* [**Production vs Sandbox**](/docs/getting-started/production-vs-sandbox) — Learn the differences between environments
***
# Creating a Webhook
Source: https://docs.revolv3.com/docs/webhook-events/creating-a-webhook
Step-by-step guide to creating and configuring webhooks in the Revolv3 portal. Learn how to set up your endpoint and verify it works.
## What is Webhook Setup?
Setting up a webhook tells Revolv3 where to send event notifications. Once configured, Revolv3 will automatically send HTTP POST requests to your server when events occur (like payments completing, invoices changing status, etc.).
**Why you need this:**
* **Real-time updates**: Get notified immediately when events happen
* **Essential for ACH**: ACH payments take days—webhooks tell you when they complete
* **Better user experience**: Update your UI instantly
* **Efficient**: No need to constantly poll the API
## Prerequisites
Before creating a webhook, you need:
1. **Public endpoint**: Your webhook URL must be publicly accessible (not localhost)
2. **HTTPS**: Use HTTPS for security (webhooks contain sensitive data)
3. **Endpoint ready**: Your server should be able to receive POST requests
4. **Revolv3 account**: Access to the Revolv3 portal
## Step 1: Prepare Your Webhook Endpoint
Before configuring in Revolv3, make sure your endpoint is ready to receive webhooks.
### Your Endpoint Should:
* Accept HTTP POST requests
* Return 200 OK quickly (process asynchronously if needed)
* Be publicly accessible (not behind a firewall or localhost)
* Use HTTPS (required for security)
* Handle the webhook payload (JSON with Body and Entropy fields)
### Example Endpoint (Node.js/Express)
```javascript theme={null}
app.post('/webhooks/revolv3', (req, res) => {
// 1. Verify signature (important!)
const signature = req.headers['x-revolv3-signature'];
const isValid = verifySignature(req.body, signature, webhookKey, webhookUrl);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// 2. Parse the Body field (it's a JSON string)
const eventData = JSON.parse(req.body.Body);
// 3. Process the event
handleWebhookEvent(eventData);
// 4. Respond quickly with 200 OK
res.status(200).send('OK');
});
```
## Step 2: Create Webhook in Revolv3 Portal
1. **Log in to the Revolv3 Portal**:
* Production: [portal.revolv3.com](https://portal.revolv3.com)
* Sandbox: [portal-sandbox.revolv3.com](https://portal-sandbox.revolv3.com)
2. **Navigate to Webhooks**:
* Go to the **Webhooks** page in the portal
3. **Create a new webhook**:
* Click the button to create a new webhook
4. **Configure the webhook**:
* **URL**: Enter your webhook endpoint URL (must be HTTPS and publicly accessible)
* **Webhook Type**: Select **"Object"** (the "Event" type is deprecated)

5. **Copy your Webhook Key**:
* After creating the webhook, you'll see a **Webhook Key**
* **Copy this immediately**—you'll need it to verify signatures
* Store it securely (like your API keys)
## Step 3: Test Your Connection
Before saving, test that Revolv3 can reach your endpoint:
1. **Click "Test Connection"** in the portal
2. **Revolv3 sends a test webhook** to your endpoint
3. **Your endpoint should return 200 OK**
4. **If successful**: The "Save" button will be enabled
5. **If failed**: Check your endpoint, make sure it's accessible and returns 200 OK
**What the test does**: Revolv3 sends a `WebhookTest` event to verify your endpoint is reachable and responds correctly.
## Step 4: Save Your Configuration
Once the test connection succeeds:
1. **Click "Save"** to save your webhook configuration
2. **Your webhook is now active** and will receive events
3. **Monitor your endpoint** to ensure webhooks are being received
## Understanding Webhook Security: Signature Verification
Revolv3 includes a signature in each webhook request so you can verify it came from Revolv3.
### The x-revolv3-signature Header
Each webhook request includes an `x-revolv3-signature` header containing a hashed signature of the payload.
**Why it matters**: This signature proves the webhook came from Revolv3 and wasn't tampered with.
### How to Verify Signatures
Revolv3 uses **HMAC-SHA256** to generate the signature:
1. **Concatenate**: `{your-webhook-url}${request-body}`
* Note the `$` delimiter between URL and body
2. **Create HMAC**: Use HMAC-SHA256 with your webhook key
3. **Encode**: Base64 encode the result
4. **Compare**: This should match the `x-revolv3-signature` header
### Verification Code Examples
#### C# Example
```csharp theme={null}
public static bool IsValidWebhookEventSignature(
string requestBody,
string signatureHeader,
string signatureKey,
string url)
{
if (string.IsNullOrEmpty(signatureKey))
throw new ArgumentNullException(nameof(signatureKey));
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException(nameof(url));
// Concatenate url + "$" + requestBody
byte[] bytes = Encoding.UTF8.GetBytes(url + "$" + requestBody);
// Create HMAC-SHA256 hash
using var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(signatureKey));
// Compare signatures
return Convert.ToBase64String(hmacsha256.ComputeHash(bytes)).Equals(signatureHeader);
}
```
#### PHP Example
```php theme={null}
function IsValidWebhookEventSignature(
string $requestBody,
string $signatureHeader,
string $signatureKey,
string $url
): bool {
if (empty($signatureKey)) {
throw new ArgumentNullException('signatureKey');
}
if (empty($url)) {
throw new ArgumentNullException('url');
}
// Concatenate url + "$" + requestBody
$data = $url . '$' . $requestBody;
// Create HMAC-SHA256 hash
$hmac = hash_hmac('sha256', $data, $signatureKey, true);
// Compare signatures
return base64_encode($hmac) === $signatureHeader;
}
```
#### JavaScript/Node.js Example
```javascript theme={null}
const crypto = require('crypto');
function isValidWebhookSignature(requestBody, signatureHeader, signatureKey, url) {
if (!signatureKey || !url) {
throw new Error('signatureKey and url are required');
}
// Concatenate url + "$" + requestBody
const data = url + '$' + requestBody;
// Create HMAC-SHA256 hash
const hmac = crypto.createHmac('sha256', signatureKey);
hmac.update(data);
const hash = hmac.digest('base64');
// Compare signatures (use constant-time comparison for security)
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(signatureHeader)
);
}
```
## Important Notes
### Webhook Type: Use "Object"
* **Use "Object" type**: This is the current format
* **Don't use "Event" type**: It's deprecated and will be removed
### URL Requirements
* **Must be HTTPS**: Webhooks require secure connections
* **Must be publicly accessible**: Can't use localhost or private IPs
* **Must return 200 OK**: Your endpoint should respond quickly with 200 status
### Webhook Key Security
* **Store securely**: Treat webhook keys like API keys
* **Never expose**: Don't commit to version control
* **Use environment variables**: Store in secrets manager
## Testing Your Webhook
### Test Connection Button
The "Test Connection" button in the portal:
1. Sends a `WebhookTest` event to your endpoint
2. Waits for a 200 OK response
3. Enables the Save button if successful
### Manual Testing
You can also test manually by:
1. Making a test payment in sandbox
2. Checking if your endpoint receives the webhook
3. Verifying the signature is correct
4. Ensuring you process the event correctly
## Troubleshooting
### Test Connection Fails
**Possible issues**:
* Endpoint not publicly accessible (localhost won't work)
* Endpoint not returning 200 OK
* Firewall blocking Revolv3's requests
* Incorrect URL format
**Solutions**:
* Use a service like ngrok for local testing
* Ensure your endpoint responds with 200 OK
* Check server logs for incoming requests
* Verify the URL is correct and uses HTTPS
### Webhooks Not Received After Setup
**Check**:
* Is your endpoint publicly accessible?
* Is it returning 200 OK?
* Are you checking the correct URL?
* Check Revolv3 portal for webhook delivery status
### Signature Verification Fails
**Check**:
* Are you using the correct webhook key?
* Is the URL exactly as configured (including https\://)?
* Are you concatenating URL + "\$" + body correctly?
* Are you using HMAC-SHA256 and Base64 encoding?
## Best Practices
1. **Always verify signatures**: Never process webhooks without signature verification
2. **Respond quickly**: Return 200 OK immediately, process asynchronously
3. **Handle duplicates**: Make your handler idempotent
4. **Log everything**: Log all webhooks for debugging and auditing
5. **Test thoroughly**: Test in sandbox before production
6. **Monitor delivery**: Check webhook delivery status in the portal
## Next Steps
* [**Webhook Guide**](/docs/webhook-events/webhook) — Learn about webhook events and how to handle them
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand statuses you'll receive in webhooks
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — Learn about subscription webhook events
***
# Webhooks Guide
Source: https://docs.revolv3.com/docs/webhook-events/webhook
Learn how to receive real-time notifications from Revolv3 via webhooks. Understand webhook events, how to verify signatures, and handle different event types.
## What are Webhooks?
**Webhooks** are HTTP callbacks that Revolv3 sends to your server when events happen. Instead of you constantly checking ("polling") the API to see if something changed, Revolv3 automatically notifies you when events occur.
**Why use webhooks:**
* **Real-time updates**: Know immediately when payments succeed or fail
* **Efficient**: No need to constantly poll the API
* **Better UX**: Update your UI instantly when events happen
* **Essential for ACH**: ACH payments take days—webhooks tell you when they complete
## How Webhooks Work
### The Flow
1. **Event happens** in Revolv3 (payment succeeds, invoice status changes, etc.)
2. **Revolv3 sends HTTP POST** to your webhook URL
3. **Your server receives** the webhook and processes it
4. **Your server responds** with 200 OK to confirm receipt
5. **You update your system** based on the event data
### Webhook Format
Revolv3 sends webhooks with this structure:
```json theme={null}
{
"Body": "{\"Invoice\":{\"InvoiceId\":330973,\"InvoiceStatus\":\"Paid\"...},\"EventDateTime\":\"2025-01-27T18:18:48Z\",\"EventType\":\"InvoiceStatusChanged\",\"RevolvMerchantId\":579}",
"Entropy": "b39d4914-cb32-46d0-b3ab-e832539d3d7b"
}
```
**Understanding the fields:**
* `Body`: A JSON string containing the event data (you need to parse it)
* `Entropy`: A random string for additional security
**`The Body field is a string`**, so you need to parse it as JSON to access the data inside.
## Available Webhook Events
Revolv3 sends webhooks for these events:
| Event Type | When It's Sent | What It Means |
| - | - | - |
| `SubscriptionCreated` | Subscription is successfully created | New subscription is active |
| `SubscriptionChanged` | Subscription is updated | Subscription details changed |
| `InvoiceCreated` | New invoice is created | Invoice ready for payment |
| `InvoiceStatusChanged` | Invoice status changes | Payment succeeded, failed, or status updated |
| `InvoiceAttemptCreated` | Payment attempt is made | Revolv3 tried to process a payment |
| `InvoiceAttemptStatusChanged` | Payment attempt status changes | Attempt succeeded or failed |
| `WebhookTest` | During webhook setup | Test event to verify your endpoint works |
> **Note**: The `ACHInvoiceStatusChanged` webhook is deprecated. Use `InvoiceStatusChanged` instead—it covers all payment types including ACH.
## Understanding Event Data
### Parsing the Body
The `Body` field is a JSON string, so you need to parse it:
**Before parsing** (what you receive):
```json theme={null}
{
"Body": "{\"Invoice\":{\"InvoiceId\":330973...},\"EventType\":\"InvoiceStatusChanged\"}",
"Entropy": "b39d4914-cb32-46d0-b3ab-e832539d3d7b"
}
```
**After parsing** (what you use):
```json theme={null}
{
"Invoice": {
"InvoiceId": 330973,
"InvoiceStatus": "Paid",
"Subtotal": 0.13,
"Total": 0.13
},
"EventDateTime": "2025-01-27T18:18:48.3105823Z",
"EventType": "InvoiceStatusChanged",
"RevolvMerchantId": 579
}
```
### Data Structure
Each event includes:
* `Event-specific data`: The main object (Invoice, Subscription, Attempt, etc.).
* `EventDateTime`: When the event occurred (ISO 8601 timestamp).
* `EventType`: The type of event (see table above).
* `RevolvMerchantId`: Your merchant ID (useful for multi-merchant setups).
Event-specific data may include:
* `SubscriptionBillingPlanId`: The ID of an active billing plan for the invoice at event time. Null if the invoice has no associated subscription.
* `SubscriptionBillingPlanName`: The name of an active billing plan for the invoice at event time. Null if the invoice has no associated subscription.
* `BillingCycleNumber`: 1-based index of this invoice within its subscription's ordered SubscriptionInvoice sequence; null (not 0) when no subscription applies; a trial invoice is cycle 1, the first paid rebill is cycle 2; declined and Noncollectable invoices count as their own cycle; refund invoices are not counted.
## Webhook Examples
### Subscription Created
**When**: A subscription is successfully created
**Body** (after parsing):
```json theme={null}
{
"Subscription": {
"SubscriptionId": 2691,
"CustomerId": 9687,
"MerchantSubscriptionRefId": "1234-5678-9101",
"SubscriptionStatusType": "Current",
"NextBillDate": "1/28/2025",
"BillingPlans": [...]
},
"EventDateTime": "2025-01-28T18:09:27.6118027Z",
"EventType": "SubscriptionCreated",
"RevolvMerchantId": 579
}
```
**What to do**: Store the subscription ID, update your system, notify the customer.
### Invoice Status Changed
**When**: An invoice status changes (e.g., from Pending to Paid)
**Body** (after parsing):
```json theme={null}
{
"Invoice": {
"InvoiceId": 900123,
"MerchantId": 4021,
"CustomerId": 55021,
"Amount": 49.99,
"Currency": "USD",
"InvoiceStatus": "Pending",
"InvoiceDate": "2026-08-31T14:22:05.123Z",
"MerchantDbaName": "Acme Fitness Co.",
"PaymentType": "CardNotPresent",
"AuthCode": "OK1234",
"SubscriptionBillingPlans": [
{
"SubscriptionBillingPlanId": 501001,
"SubscriptionBillingPlanName": "Standard Monthly Plan"
},
{
"SubscriptionBillingPlanId": 501002,
"SubscriptionBillingPlanName": "Add-on Support Fee"
}
],
"BillingCycleNumber": 1
},
"EventDateTime": "2026-08-31T14:22:06.045Z",
"EventType": "InvoiceCreated",
"RevolvMerchantId": 4021
}
```
**What to do**:
* If status is "Paid": Fulfill the order, send confirmation
* If status is "Noncollectable": Notify customer, ask for different payment method
### Invoice Attempt Status Changed
**When**: A payment attempt's status changes
**Body** (after parsing):
```json theme={null}
{
"Attempt": {
"InvoiceAttemptId": 700456,
"Amount": 49.99,
"InvoiceAttemptStatus": "Approved",
"InvoiceAttemptDate": "2026-08-31T14:22:06.500Z",
"PaymentProcessor": "Stripe",
"ProcessorTransactionId": "txn_3P9AbCDeFg",
"ResponseCode": "00",
"ResponseMessage": "Approved",
"ProcessorRawResponse": null,
"PaymentMethod": {
"PaymentMethodId": 881234,
"PaymentMethodTypeId": 1,
"LastFour": "4242",
"ExpirationMonth": 12,
"ExpirationYear": 2028
},
"ProcessorMerchantId": "acct_1P8xYzABCDEF",
"ProcessingMethod": "CardNotPresent",
"Revolv3ResponseCode": "00",
"Revolv3ResponseMessage": "Approved",
"AuthCode": "OK1234",
"ProcessorResponseDateTime": "2026-08-31T14:22:06.480Z",
"InvoiceId": 900123,
"SubscriptionId": 100234,
"InstallmentId": 0,
"SubscriptionBillingPlans": [
{
"SubscriptionBillingPlanId": 501001,
"SubscriptionBillingPlanName": "Standard Monthly Plan"
},
{
"SubscriptionBillingPlanId": 501002,
"SubscriptionBillingPlanName": "Add-on Support Fee"
}
],
"BillingCycleNumber": 1
},
"EventDateTime": "2026-08-31T14:22:06.600Z",
"EventType": "InvoiceAttemptCreated",
"RevolvMerchantId": 4021
}
```
**What to do**: Handle the payment failure, notify customer, potentially retry.
## Webhook Security: Signature Verification
Revolv3 includes a signature in the `x-revolv3-signature` header so you can verify the webhook came from Revolv3.
### Why Verify Signatures?
**Security**: Verifying signatures ensures:
* The webhook actually came from Revolv3 (not a malicious third party)
* The data wasn't tampered with in transit
* You're processing legitimate events
**Always verify signatures** before processing webhook data.
### How Signature Verification Works
Revolv3 uses **HMAC-SHA256** to create a signature:
1. Concatenate your webhook URL + `$` + request body
2. Create HMAC-SHA256 hash using your webhook key
3. Encode the hash as Base64
4. Compare with the `x-revolv3-signature` header
### Verification Examples
#### C# Example
```csharp theme={null}
public static bool IsValidWebhookEventSignature(
string requestBody,
string signatureHeader,
string signatureKey,
string url)
{
if (string.IsNullOrEmpty(signatureKey))
throw new ArgumentNullException(nameof(signatureKey));
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException(nameof(url));
// Concatenate url + "$" + requestBody
byte[] bytes = Encoding.UTF8.GetBytes(url + "$" + requestBody);
// Create HMAC-SHA256 hash
using var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(signatureKey));
// Compare signatures
return Convert.ToBase64String(hmacsha256.ComputeHash(bytes)).Equals(signatureHeader);
}
```
#### PHP Example
```php theme={null}
function IsValidWebhookEventSignature(
string $requestBody,
string $signatureHeader,
string $signatureKey,
string $url
): bool {
if (empty($signatureKey)) {
throw new ArgumentNullException('signatureKey');
}
if (empty($url)) {
throw new ArgumentNullException('url');
}
// Concatenate url + "$" + requestBody
$data = $url . '$' . $requestBody;
// Create HMAC-SHA256 hash
$hmac = hash_hmac('sha256', $data, $signatureKey, true);
// Compare signatures
return base64_encode($hmac) === $signatureHeader;
}
```
#### JavaScript/Node.js Example
```javascript theme={null}
const crypto = require('crypto');
function isValidWebhookSignature(requestBody, signatureHeader, signatureKey, url) {
if (!signatureKey || !url) {
throw new Error('signatureKey and url are required');
}
// Concatenate url + "$" + requestBody
const data = url + '$' + requestBody;
// Create HMAC-SHA256 hash
const hmac = crypto.createHmac('sha256', signatureKey);
hmac.update(data);
const hash = hmac.digest('base64');
// Compare signatures (use constant-time comparison for security)
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(signatureHeader)
);
}
```
## Best Practices for Webhook Handling
### 1. Always Verify Signatures
**Never process webhooks without verifying the signature first.** This is a critical security requirement.
### 2. Respond Quickly
* **Respond with 200 OK** as soon as you receive the webhook
* **Process asynchronously** if processing takes time
* **Don't block** on long operations
### 3. Handle Duplicates
Webhooks may be sent multiple times. Make your handler **idempotent**:
* Check if you've already processed this event
* Use event IDs or timestamps to detect duplicates
* Don't process the same event twice
### 4. Log Everything
* Log all incoming webhooks (for debugging)
* Store event data for auditing
* Track which events you've processed
### 5. Handle Errors Gracefully
* If processing fails, log the error
* Consider retrying failed processing
* Don't crash your server on webhook errors
## Common Webhook Scenarios
### Scenario 1: Payment Succeeds
**Event**: `InvoiceStatusChanged` **Status**: `Paid`
**What to do**:
1. Verify signature
2. Parse the Body JSON
3. Extract invoice ID and status
4. Update order status to "paid"
5. Fulfill the order (ship product, activate service, etc.)
6. Send confirmation email to customer
7. Respond with 200 OK
### Scenario 2: ACH Payment Completes
**Event**: `InvoiceStatusChanged` **Status**: `Paid` (after 1-5 business days)
**What to do**:
1. Verify signature
2. Parse the Body JSON
3. Check if status is "Paid" or "Noncollectable"
4. If Paid: Fulfill order, send confirmation
5. If Noncollectable: Notify customer, ask for different payment method
6. Respond with 200 OK
### Scenario 3: Subscription Payment Fails
**Event**: `InvoiceAttemptStatusChanged` **Status**: `Fail`
**What to do**:
1. Verify signature
2. Parse the Body JSON
3. Check the failure reason
4. Notify customer that payment failed
5. Pause subscription (optional)
6. Give customer a grace period to update payment method
7. Respond with 200 OK
## Troubleshooting
### Webhook Not Received
**Check**:
* Is your endpoint publicly accessible? (webhooks can't reach localhost)
* Is your endpoint returning 200 OK?
* Are you checking the correct URL?
* Is your server firewall blocking requests?
### Signature Verification Fails
**Check**:
* Are you using the correct webhook key?
* Are you concatenating URL + "\$" + body correctly?
* Are you using HMAC-SHA256 and Base64 encoding?
* Is the URL exactly as configured (including https\://)?
### Duplicate Events
**Solution**:
* Implement idempotency checking
* Store event IDs or timestamps
* Skip processing if already handled
## Next Steps
* [**Creating a Webhook**](/docs/webhook-events/creating-a-webhook) — Step-by-step guide to setting up webhooks
* [**Invoice Status**](/docs/core-concepts/invoice/invoice-status) — Understand invoice statuses you'll receive in webhooks
* [**Subscriptions**](/docs/core-concepts/subscription/create-subscription) — Learn about subscription events
***