> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fractalpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

# 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

1. [Payment Success](#payment-success)
2. [Merchant Onboarding](#merchant-onboarding)
3. [Merchant Approval](#merchant-approval)
4. [Documents Signed](#documents-signed)
5. [ACH Update](#ach-update)
6. [Void from EasyPay](#void-from-easypay)
7. [Partial Refund](#partial-refund)
8. [Payment Request (Preauth)](#payment-request-preauth)
9. [Pre-Authorization Update](#pre-authorization-update)
10. [Capture Pre-Authorization](#capture-pre-authorization)

## Payment Success

### Event: `payment.success`

#### Description

This event is triggered when a payment is successfully processed.

#### Payload Example

```json theme={null}
{
    "event_type": "payment.success",
    "data": {
        "transaction_id": "txn_a7f0b5340a",
        "merchant_id": "m_xxxxxxxxxx",
        "amount": 1.00,
        "net_amount": 0.95,
        "fee_amount": 0.05,
        "order_id": "example-order-id",
        "last_four": "0043",
        "brand": "VISA",
        "link_id": ""
    }
}
```

#### 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

```json theme={null}
{
    "event_type": "merchant.onboarding",
    "data": {
        "merchant_key": "example-merchant-api-key",
        "merchant_id": "m_xxxxxxxxxx",
        "business_name": "Example Business",
        "email": "merchant@example.com",
        "public_key": "example-public-key"
    }
}
```

#### 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

```json theme={null}
{
    "event_type": "merchant.approval",
    "data": {
        "merchant_id": "m_xxxxxxxxxx",
        "business_name": "Example Business",
        "email": "merchant@example.com",
        "company_id": "example-company-id"
    }
}
```

#### 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.

<Note>The mock approval endpoint is sandbox-only and will return an error if called in production.</Note>

#### Step 1: Set Up a Webhook Receiver

If you don't already have a server endpoint ready to receive webhooks, use [webhook.site](https://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.

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

**Response:**

```json theme={null}
{
  "status": true,
  "message": "Webhook url updated successfully"
}
```

#### Step 3: Trigger a Mock Merchant Approval

Send a POST request with the merchant's GUID as `merchant_id`. This fires a `merchant.approval` webhook to your registered URL immediately.

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/approve-merchant \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_id": "m_xxxxxxxxxx"
  }'
```

**Response:**

```json theme={null}
{
  "status": true,
  "message": "Webhook dispatch started"
}
```

#### Step 4: Verify the Webhook Payload

Your registered endpoint will receive a POST request with the following payload:

```json theme={null}
{
  "event_type": "merchant.approval",
  "data": {
    "merchant_id": "m_xxxxxxxxxx",
    "business_name": "Example Business",
    "email": "merchant@example.com",
    "company_id": "example-company-id"
  }
}
```

This matches the payload your integration will receive when a merchant's application is approved.

#### Finding Your merchant\_id

The `merchant_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

```json theme={null}
{
    "event_type": "documents.signed",
    "data": {
        "merchant_id": "m_xxxxxxxxxx",
        "business_name": "Example Business",
        "website": "https://example.com",
        "email": "merchant@example.com",
        "company_id": "example-company-id"
    }
}
```

#### 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

```json theme={null}
{
  "event_type": "ach.update",
  "data": {
    "merchant_id": "m_xxxxxxxxxx",
    "status": "Approved",
    "tran_id": "txn_xxxxxxxx",
    "message": "Approved"
  }
}
```

#### Explanation

* `merchant_id`: Unique identifier for the merchant.
* `status`: `Approved` or `Declined`.
* `tran_id`: The original ACH transaction ID.
* `message`: `Approved` or `Insufficient Funds`.
* `return_transaction_id`: ID of the reversal record — only present on `Declined`.

### 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.

<Note>The mock ACH update endpoint is sandbox-only and will return an error if called in production.</Note>

#### 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:

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

#### Step 2: Trigger a Mock ACH Approval

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/update-ach \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_xxxxxxxx",
    "new_status": "approved"
  }'
```

**Response:**

```json theme={null}
{ "result": true, "message": "Success." }
```

**Webhook payload received:**

```json theme={null}
{
  "event_type": "ach.update",
  "data": {
    "merchant_id": "m_xxxxxxxxxx",
    "status": "Approved",
    "tran_id": "txn_xxxxxxxx",
    "message": "Approved"
  }
}
```

#### Step 3: Trigger a Mock ACH Decline

Same endpoint, `new_status` set to `"declined"`:

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/update-ach \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_xxxxxxxx",
    "new_status": "declined"
  }'
```

**Webhook payload received:**

```json theme={null}
{
  "event_type": "ach.update",
  "data": {
    "merchant_id": "m_xxxxxxxxxx",
    "status": "Declined",
    "tran_id": "txn_xxxxxxxx",
    "message": "Insufficient Funds",
    "return_transaction_id": "txn_yyyyyyyyyy"
  }
}
```

`return_transaction_id` is the ID of the reversal record created when an ACH is declined.

#### Finding a Valid transaction\_id

The `transaction_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

```json theme={null}
{
  "event_type": "payment.void",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "transaction_id": "txn_454e460495",
    "Status": "Success",
    "linked_txn_id": "txn_c3b9865e78",
    "sales_id": "txn_454e460495",
    "order_createdfrom": "API",
    "amount": 2,
    "txn_id": "txn_Y9tiwFkMbv9vcHHwAZVE",
    "txn_date": "2026-06-15T16:31:44.000Z",
    "type": "Void"
  }
}
```

#### Explanation

* `merchant_id`: Unique identifier for the merchant.
* `transaction_id`: ID of the void transaction record created.
* `Status`: `Success` or `Error`.
* `linked_txn_id`: ID of the original transaction that was voided.
* `sales_id`: Same as `transaction_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`: Always `Void`.

### Testing in Sandbox

#### Step 1: Register your webhook URL (skip if already done)

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

#### Step 2: Trigger a void

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/order/sales-void \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_xxxxxxxx",
    "amount": "2.00"
  }'
```

**Response:**

```json theme={null}
{
  "result": true,
  "message": "Transaction voided successfully",
  "data": {
    "sales_id": "txn_454e460495",
    "order_createdfrom": "API",
    "amount": 2,
    "txn_id": "txn_Y9tiwFkMbv9vcHHwAZVE",
    "txn_date": "2026-06-15T16:31:44.000Z",
    "linked_txn_id": "txn_c3b9865e78",
    "transaction_id": "txn_454e460495",
    "Status": "Success",
    "type": "Void"
  }
}
```

<Note>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.</Note>

## Partial Refund

### Event: `payment.refund`

#### Description

This event is triggered when a refund is successfully processed on a completed card transaction.

#### Payload Example

```json theme={null}
{
  "event_type": "payment.refund",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "transaction_id": "txn_a8f83189a5",
    "Status": "Success",
    "linked_txn_id": "txn_a8f83189a5",
    "parent_transaction_id": "txn_b65f37d127",
    "sales_id": "txn_a8f83189a5",
    "order_createdfrom": "API",
    "amount": 1,
    "txn_id": "txn_lyWexIP9z2MJkrBBtscY",
    "txn_date": "2026-06-15T19:13:03.000Z",
    "type": "Refund"
  }
}
```

#### Explanation

* `merchant_id`: Unique identifier for the merchant.
* `transaction_id`: ID of the new refund record created.
* `Status`: `Success`.
* `linked_txn_id`: Same as `transaction_id` — the refund record ID.
* `parent_transaction_id`: The original transaction that was refunded.
* `sales_id`: Same as `transaction_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`: Always `Refund`.

### 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)

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

**Response:**

```json theme={null}
{
  "status": true,
  "message": "Webhook url updated successfully"
}
```

#### Step 2: Issue the refund

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/order/sales-return \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_xxxxxxxx",
    "amount": "1.00"
  }'
```

**Response:**

```json theme={null}
{
  "result": true,
  "message": "Transaction refunded successfully",
  "data": {
    "sales_id": "txn_a8f83189a5",
    "order_createdfrom": "API",
    "amount": 1,
    "txn_id": "txn_lyWexIP9z2MJkrBBtscY",
    "txn_date": "2026-06-15T19:13:03.000Z",
    "linked_txn_id": "txn_xxxxxxxx",
    "transaction_id": "txn_a8f83189a5",
    "Status": "Success",
    "type": "Refund"
  }
}
```

#### Step 3: Verify the webhook payload

Your registered endpoint will receive a POST request with the following payload:

```json theme={null}
{
  "event_type": "payment.refund",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "transaction_id": "txn_a8f83189a5",
    "Status": "Success",
    "linked_txn_id": "txn_a8f83189a5",
    "parent_transaction_id": "txn_xxxxxxxx",
    "sales_id": "txn_a8f83189a5",
    "order_createdfrom": "API",
    "amount": 1,
    "txn_id": "txn_lyWexIP9z2MJkrBBtscY",
    "txn_date": "2026-06-15T19:13:03.000Z",
    "type": "Refund"
  }
}
```

Use `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."`                     |

<Note>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.</Note>

## 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

1. Your server calls `POST /api/v1/requests` with `preauth: true` — returns a `pay_link`
2. You send the `pay_link` to your customer (or the API sends it via SMS/email automatically)
3. The customer visits the link and enters their card details to authorize
4. On successful authorization → your registered webhook URL receives the `preauth` event

#### Payload Example

```json theme={null}
{
  "event_type": "preauth",
  "data": {
    "merchant_id": "m_f2d5caadab",
    "guid": "txn_b71af1a75f",
    "amount": 10,
    "order_id": "5467",
    "customer_id": 0
  }
}
```

#### 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, or `0` if 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)

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

#### Step 2: Create the payment request

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/requests \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "amount": "10.00",
    "order_id": "5467",
    "phone_number": "7777771234",
    "email": "customer@example.com",
    "preauth": true,
    "pass_fee": true,
    "require_3ds": false,
    "invoice_number": "345",
    "allow_card": true,
    "allow_ach": true
  }'
```

**Response:**

```json theme={null}
{
  "message": "Authorization request has been sent",
  "data": {
    "order_id": "5467",
    "link_id": "gsgqll4xfa7",
    "pay_link": "https://testapi.fractalpay.com/authcheck-paymentlink/gsgqll4xfa7"
  }
}
```

#### Step 3: Customer completes preauth

Share the `pay_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

```json theme={null}
{
  "event_type": "preauth",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "guid": "txn_b71af1a75f",
    "amount": 10,
    "order_id": "5467",
    "customer_id": 0
  }
}
```

Use the `guid` to capture or void the preauth via the `/preauth/capture` or `/preauth/void` endpoints.

<Note>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.</Note>

<Note>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.</Note>

## 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 comparing `new_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

```json theme={null}
{
  "event_type": "preauth.increment",
  "data": {
    "merchant_id": "m_f2d5caadab",
    "guid": "txn_f84144f73a",
    "amount": "11.00",
    "order_id": "5467",
    "customer_id": 0
  }
}
```

The `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, or `0` if 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)

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

#### Step 2: Submit the update

**Increment (raise the authorization):**

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/preauth/update \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_77c9a625a3",
    "last_authorized_amount": "10.00",
    "new_authorized_amount": "11.00",
    "order_id": "5467"
  }'
```

**Decrement (partial reversal):** same endpoint, `new_authorized_amount` less than `last_authorized_amount`.

**Response:**

```json theme={null}
{
  "result": true,
  "message": "Amount Updated Successfully",
  "data": {
    "Status": "Approved",
    "Account": "0043",
    "Brand": "Visa",
    "AuthCode": "",
    "Authorized": "11.00",
    "transaction_id": "txn_77c9a625a3",
    "orderid": "5467"
  }
}
```

#### Step 3: Verify the webhook payload

```json theme={null}
{
  "event_type": "preauth.increment",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "guid": "txn_xxxxxxxx",
    "amount": "11.00",
    "order_id": "5467",
    "customer_id": 0
  }
}
```

#### 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"`                                   |

<Note>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.</Note>

## 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

```json theme={null}
{
  "event_type": "preauth.charge",
  "data": {
    "merchant_id": "m_f2d5caadab",
    "link_id": "txn_f84144f73a",
    "guid": "txn_77c9a625a3",
    "amount": "11.00",
    "order_id": "5467",
    "net_amount": 10.64
  }
}
```

#### Explanation

* `merchant_id`: Unique identifier for the merchant.
* `link_id`: The preauthorization transaction ID that was captured (the `transaction_id` you 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)

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/client/update-webhooks-url \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-endpoint.com/webhook"
  }'
```

#### Step 2: Capture the preauthorization

```bash theme={null}
curl -X POST https://testapi.fractalpay.com/api/v1/preauth/capture \
  -u "{client_id}:{secret_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_key": "your-merchant-api-key",
    "transaction_id": "txn_f84144f73a"
  }'
```

**Response:**

```json theme={null}
{
  "result": true,
  "message": "Payment captured successfully.",
  "data": {
    "Status": "Approved",
    "Account": "0043",
    "Brand": "Visa",
    "AuthCode": "",
    "amount": "11.00",
    "Authorized": 11,
    "orderid": "5467",
    "transaction_id": "txn_77c9a625a3",
    "net_amount": 10.64
  }
}
```

#### Step 3: Verify the webhook payload

```json theme={null}
{
  "event_type": "preauth.charge",
  "data": {
    "merchant_id": "m_xxxxxxxx",
    "link_id": "txn_f84144f73a",
    "guid": "txn_77c9a625a3",
    "amount": "11.00",
    "order_id": "5467",
    "net_amount": 10.64
  }
}
```

Note that `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"` |

<Note>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.</Note>
