Webhook Events
This page documents the various webhook events that can be triggered by the Payrix platform. Webhooks are used to notify your application when specific events occur.Table of Contents
- Payment Success
- Merchant Onboarding
- Merchant Approval
- Documents Signed
- ACH Update
- Void from EasyPay
- Partial Refund
- Payment Request (Preauth)
- Pre-Authorization Update
- Capture Pre-Authorization
Payment Success
Event: payment.success
Description
This event is triggered when a payment is successfully processed.Payload Example
Explanation
transaction_id: Unique identifier for the transaction.merchant_id: Unique identifier for the merchant.amount: Total amount of the payment.net_amount: Amount received after fees.fee_amount: Fee amount charged for the transaction.order_id: Identifier for the associated order.last_four: Last four digits of the card used.brand: Card brand (e.g. VISA, Mastercard).link_id: Associated pay link ID, if applicable.
Merchant Onboarding
Event: merchant.onboarding
Description
This event is triggered when a merchant completes the onboarding process.Payload Example
Explanation
merchant_key: Unique key assigned to the merchant.merchant_id: Unique identifier for the merchant.business_name: Name of the merchant’s business.email: Merchant’s contact email.public_key: Public key associated with the merchant.
Merchant Approval
Event: merchant.approval
Description
This event is triggered when a merchant’s application is approved.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.business_name: Name of the merchant’s business.email: Merchant’s contact email.company_id: Unique identifier for the associated company.
Testing Merchant Approval Webhooks in Sandbox
This guide walks through how to mock a merchant approval event in the sandbox environment to verify your webhook integration before going live.The mock approval endpoint is sandbox-only and will return an error if called in production.
Step 1: Set Up a Webhook Receiver
If you don’t already have a server endpoint ready to receive webhooks, use webhook.site to get a temporary public URL that logs all incoming requests. Copy the unique URL it generates — you’ll use it in Step 2.Step 2: Register Your Webhook URL
Register the URL where Fractal should send webhook events. This replaces any previously registered URL for your client account.Step 3: Trigger a Mock Merchant Approval
Send a POST request with the merchant’s GUID asmerchant_id. This fires a merchant.approval webhook to your registered URL immediately.
Step 4: Verify the Webhook Payload
Your registered endpoint will receive a POST request with the following payload:Finding Your merchant_id
Themerchant_id is the merchant’s GUID — not the API key. It can be found in the Fractal dashboard or from the response when the merchant was originally onboarded.
Documents Signed
Event: documents.signed
Description
This event is triggered when a merchant completes signing the required documents.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.business_name: Name of the merchant’s business.website: Merchant’s website URL.email: Merchant’s contact email.company_id: Unique identifier for the associated company.
ACH Update
Event: ach.update
Description
This event is triggered when an ACH transaction status changes — either approved or declined.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.status:ApprovedorDeclined.tran_id: The original ACH transaction ID.message:ApprovedorInsufficient Funds.return_transaction_id: ID of the reversal record — only present onDeclined.
Testing ACH Update Webhooks in Sandbox
This guide walks through how to mock an ACH payment status update in the sandbox environment to verify your webhook integration.The mock ACH update endpoint is sandbox-only and will return an error if called in production.
Prerequisites
Before testing you’ll need:- A merchant under your client account that has at least one ACH transaction in the system
- Your webhook URL registered (see the Merchant Approval Webhook guide for setup steps — same endpoint)
Step 1: Register Your Webhook URL
If not already set up from a previous test:Step 2: Trigger a Mock ACH Approval
Step 3: Trigger a Mock ACH Decline
Same endpoint,new_status set to "declined":
return_transaction_id is the ID of the reversal record created when an ACH is declined.
Finding a Valid transaction_id
Thetransaction_id must be the pos_guid of an existing ACH transaction for the merchant. Only approved and declined are valid values for new_status — anything else returns a 400.
Void from EasyPay
Event: payment.void
Description
This event is triggered when a transaction is successfully voided.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.transaction_id: ID of the void transaction record created.Status:SuccessorError.linked_txn_id: ID of the original transaction that was voided.sales_id: Same astransaction_id— the void record ID.order_createdfrom: Source of the original order (e.g.API).amount: Amount voided.txn_id: Gateway-level transaction reference ID.txn_date: Timestamp of the void.type: AlwaysVoid.
Testing in Sandbox
Step 1: Register your webhook URL (skip if already done)
Step 2: Trigger a void
The transaction must be voided before it settles. A settled transaction returns
"The transaction has been settled, a void is not allowed." Use a transaction created the same day for sandbox testing.Partial Refund
Event: payment.refund
Description
This event is triggered when a refund is successfully processed on a completed card transaction.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.transaction_id: ID of the new refund record created.Status:Success.linked_txn_id: Same astransaction_id— the refund record ID.parent_transaction_id: The original transaction that was refunded.sales_id: Same astransaction_id.order_createdfrom: Source of the original order (e.g.API).amount: Refund amount (positive decimal).txn_id: Gateway-level transaction reference ID.txn_date: ISO 8601 timestamp of the refund.type: AlwaysRefund.
How to Issue a Refund
Endpoint:POST /api/v1/order/sales-return
Auth: Basic Auth (client_id:secret_key)
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_key | string | Yes | Merchant API key |
transaction_id | string | Yes | pos_guid of the original completed transaction |
amount | string | Yes | Amount to refund — must not exceed the original or remaining refundable balance |
Step 1: Register your webhook URL (skip if already done)
Step 2: Issue the refund
Step 3: Verify the webhook payload
Your registered endpoint will receive a POST request with the following payload:parent_transaction_id to trace back to the original charge.
Error responses
| Scenario | Message |
|---|---|
| Transaction not found or not completed | "Payment method not found." |
| Amount exceeds original transaction | "Amount should not be greater than sales charge amount." |
| Amount exceeds remaining refundable balance | "The amount should not be greater than the remaining amount." |
| Transaction already fully refunded | "Refund already done. No refund allowed." |
Partial refunds can be issued multiple times against the same transaction as long as the cumulative total does not exceed the original charge amount. If the refund amount equals the full transaction amount and the transaction is older than 24 hours, the API automatically performs a void instead.
Payment Request (Preauth)
Event: preauth
Description
This event is triggered when a customer successfully completes a preauthorization via a payment request link. The customer’s card is authorized for the amount but not charged until you explicitly capture the preauth.Flow
- Your server calls
POST /api/v1/requestswithpreauth: true— returns apay_link - You send the
pay_linkto your customer (or the API sends it via SMS/email automatically) - The customer visits the link and enters their card details to authorize
- On successful authorization → your registered webhook URL receives the
preauthevent
Payload Example
Explanation
merchant_id: Unique identifier for the merchant.guid: Transaction ID of the preauthorization record.amount: Amount that was preauthorized.order_id: The order reference you provided in the original request.customer_id: Internal customer ID, or0if no customer profile was linked.
How to Create a Payment Request
Endpoint:POST /api/v1/requests
Auth: Basic Auth (client_id:secret_key)
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_key | string | Yes | Merchant API key |
amount | string | Yes | Payment amount |
order_id | string | Yes | Your unique order reference (max 100 characters) |
phone_number | string | No | Customer phone — triggers SMS with pay link |
email | string | No | Customer email — triggers email with pay link |
name | string | No | Customer name, used in the email template |
preauth | boolean | No | Set to true to issue a preauthorization instead of a charge |
pass_fee | boolean | No | Pass the processing fee to the customer |
require_3ds | boolean | No | Require 3D Secure authentication |
allow_card | boolean | No | Allow card payment (default: true) |
allow_ach | boolean | No | Allow ACH payment (default: true) |
invoice_number | string | No | Invoice reference (alphanumeric, max 100 characters) |
sub_merchant_key | string | No | Sub-merchant key, if applicable |
Step 1: Register your webhook URL (skip if already done)
Step 2: Create the payment request
Step 3: Customer completes preauth
Share thepay_link with your customer (or the API will send it automatically if phone_number or email was provided). When the customer authorizes, your webhook endpoint receives the preauth event.
Step 4: Verify the webhook payload
guid to capture or void the preauth via the /preauth/capture or /preauth/void endpoints.
At least one of
allow_card or allow_ach must be true. If phone_number or email is provided, the API automatically sends the pay link — you do not need to deliver it manually.Partial refunds can be issued multiple times against the same transaction as long as the cumulative total does not exceed the original charge amount. If the refund amount equals the full transaction amount and the transaction is older than 24 hours, the API automatically performs a void instead.
Pre-Authorization Update
Events: preauth.increment / preauth.decrement
Description
These events are triggered when the authorized amount on an existing preauthorization is changed. The same endpoint handles both directions — the direction is determined by comparingnew_authorized_amount to last_authorized_amount.
| Condition | Event fired |
|---|---|
new_authorized_amount > last_authorized_amount | preauth.increment |
new_authorized_amount < last_authorized_amount | preauth.decrement |
Payload Example
preauth.decrement payload has the same shape — only event_type and amount differ.
Explanation
merchant_id: Unique identifier for the merchant.guid: Transaction ID of the preauthorization record.amount: The new authorized amount after the update.order_id: The order reference associated with the preauth.customer_id: Internal customer ID, or0if no customer profile was linked.
How to Update a Pre-Authorization
Endpoint:POST /api/v1/preauth/update
Auth: Basic Auth (client_id:secret_key)
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_key | string | Yes | Merchant API key |
transaction_id | string | Yes | guid of the existing preauthorization |
last_authorized_amount | string | Yes | Current authorized amount — must match the amount on record |
new_authorized_amount | string | Yes | Target authorized amount — determines increment or decrement |
order_id | string | No | Your order reference |
Step 1: Register your webhook URL (skip if already done)
Step 2: Submit the update
Increment (raise the authorization):new_authorized_amount less than last_authorized_amount.
Response:
Step 3: Verify the webhook payload
Error responses
| Scenario | Message |
|---|---|
last_authorized_amount doesn’t match current record | "Amount mismatch" |
| Trying to increment an already-decremented auth | "Authorization can only be decreased, captured, or voided." |
| Trying to decrement an already-incremented auth | "Authorization can only be increased, captured, or voided." |
| Preauth not found | "Authorization not found" |
The
last_authorized_amount must exactly match the current authorized amount stored on the preauthorization record. If the amount has changed since you last queried it, the request will return an "Amount mismatch" error.Capture Pre-Authorization
Event: preauth.charge
Description
This event is triggered when a preauthorization is successfully captured — the customer’s card is charged for the authorized amount and the preauth is converted into a completed transaction.Payload Example
Explanation
merchant_id: Unique identifier for the merchant.link_id: The preauthorization transaction ID that was captured (thetransaction_idyou passed in the request).guid: The resulting completed transaction ID created by the capture.amount: Amount that was captured.order_id: The order reference associated with the preauth.net_amount: Amount received after fees.
How to Capture a Pre-Authorization
Endpoint:POST /api/v1/preauth/capture
Auth: Basic Auth (client_id:secret_key)
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_key | string | Yes | Merchant API key |
transaction_id | string | Yes | guid of the preauthorization to capture |
Step 1: Register your webhook URL (skip if already done)
Step 2: Capture the preauthorization
Step 3: Verify the webhook payload
link_id is the preauth transaction_id you passed in — use it to correlate the capture back to the original preauth. guid is the new completed transaction ID.
Error responses
| Scenario | Message |
|---|---|
| Preauth not found | "Authorization not found" |
The
last_authorized_amount must exactly match the current authorized amount stored on the preauthorization record. If the amount has changed since you last queried it, the request will return an "Amount mismatch" error.