> For the complete documentation index, see [llms.txt](https://docs.loomgate.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.loomgate.io/en/webhooks/webhook-events.md).

# Event types

Webhook event types, when they are sent and sample payloads.

Every webhook has the same shape:

```json
{
  "id": "evt_…",
  "object": "event",
  "type": "payment_intent.succeeded",
  "created": 1790000000,
  "data": { "object": { } }
}
```

`created` is in unix seconds; `data.object` is the object as it was when the event happened, in the same shape the API returns.

| Event                      | `data.object`                                           | When                                                                                                 | What to do                                                                |
| -------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `payment_intent.succeeded` | [payment\_intent](/en/api-reference/payment-intents.md) | The payment was collected successfully                                                               | Mark the order as paid, fulfill it                                        |
| `payment_intent.canceled`  | payment\_intent                                         | The payment was canceled and can no longer be paid                                                   | Cancel the order, or create a new payment if the buyer still wants to pay |
| `refund.succeeded`         | [refund](/en/api-reference/refunds.md)                  | The refund has completed                                                                             | Record the refund, notify the buyer                                       |
| `refund.failed`            | refund                                                  | The refund was created but could not be completed                                                    | Investigate, and refund again with a new request if needed                |
| `adjustment.created`       | adjustment                                              | Loomgate recorded an adjustment on your balance (for example a bank dispute)                         | Reconcile your accounts                                                   |
| `unlock_step.available`    | unlock\_step                                            | An unlock step of a payment just moved to your available balance (only when something remains in it) | Reconcile your available balance                                          |

{% hint style="info" %}
When a request to create a refund is rejected right away (an error in the response), `refund.failed` is only sent if the request had an `Idempotency-Key`: in that case, a concurrent request with the same key may already have received the refund in `pending` status.
{% endhint %}

## payment\_intent.succeeded

```json
{
  "id": "evt_9fK2mQ7xR4tL1vB8nC3d",
  "object": "event",
  "type": "payment_intent.succeeded",
  "created": 1790000125,
  "data": {
    "object": {
      "id": "lg_pi_4Qx9ZcM2LwT8rKv1bN3a",
      "object": "payment_intent",
      "status": "succeeded",
      "currency": "usd",
      "amount": 10000,
      "fee_buyer": 320,
      "amount_total": 10320,
      "processing_fee": 290,
      "bank_fee": 30,
      "fee_bearer": "buyer",
      "amount_refunded": 0,
      "amount_refundable": 10000,
      "confirmation_attempts": 1,
      "description": null,
      "metadata": { "order_id": "1042" },
      "order_reference": "1042",
      "goods_type": "physical",
      "buyer": { "name": "Jane Doe" },
      "shipping_details": {
        "name": "Jane Doe",
        "phone": null,
        "address": { "line1": "1 Market St", "line2": null, "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }
      },
      "items": [{ "name": "T-shirt", "quantity": 2, "unit_amount": 4500, "amount": 9000 }],
      "shipping_amount": 1000,
      "tax_amount": 0,
      "discount_amount": 0,
      "items_difference": 0,
      "billing_details": {
        "email": "buyer@example.com",
        "name": "Jane Doe",
        "address": { "line1": "1 Market St", "line2": null, "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }
      },
      "created": 1790000000,
      "succeeded_at": 1790000120,
      "unlock_schedule": [
        { "step": 1, "days": 14, "percent_bps": 8000, "available_at": 1791210600, "amount": 8000, "deducted": 0, "remaining": 8000, "rescheduled": false },
        { "step": 2, "days": 30, "percent_bps": 2000, "available_at": 1792593000, "amount": 2000, "deducted": 0, "remaining": 2000, "rescheduled": false }
      ]
    }
  }
}
```

Webhooks never include `client_secret`. The buyer pays the fees here, so the payment brings you exactly `amount` (10320 − 290 − 30 = 10000), split by an example unlock schedule of 80 % after 14 days and 20 % after 30 days; see [Balance and unlock times](/en/concepts/balance.md).

## refund.succeeded

```json
{
  "id": "evt_2hD8sP5wK1yN6qZ3tF9g",
  "object": "event",
  "type": "refund.succeeded",
  "created": 1790100300,
  "data": {
    "object": {
      "id": "lg_re_8Hs2PzQ1YtR5nWc7mK0d",
      "object": "refund",
      "payment_intent": "lg_pi_4Qx9ZcM2LwT8rKv1bN3a",
      "amount": 2500,
      "refund_fee": 25,
      "status": "succeeded",
      "reason": "requested_by_customer",
      "created": 1790100000
    }
  }
}
```

## adjustment.created

```json
{
  "id": "evt_6mV3cX8bN2kJ7pL4rT1q",
  "object": "event",
  "type": "adjustment.created",
  "created": 1790500000,
  "data": {
    "object": {
      "id": "adj_7Tn2KqL9WmX4cV8bR1sD",
      "object": "adjustment",
      "currency": "usd",
      "amount": -1500,
      "reason": "Chargeback for order 1042",
      "payment_intent": "lg_pi_4Qx9ZcM2LwT8rKv1bN3a",
      "created": 1790500000
    }
  }
}
```

`amount` is signed: negative is deducted from your balance, positive is added to it. `payment_intent` is `null` when the adjustment is not tied to a payment.

## unlock\_step.available

```json
{
  "id": "evt_3sR7vB2nK9qL5xM1cT8w",
  "object": "event",
  "type": "unlock_step.available",
  "created": 1791210601,
  "data": {
    "object": {
      "object": "unlock_step",
      "payment_intent": "lg_pi_4Qx9ZcM2LwT8rKv1bN3a",
      "currency": "usd",
      "step": 1,
      "days": 14,
      "percent_bps": 8000,
      "available_at": 1791210600,
      "amount": 8000,
      "deducted": 2525,
      "remaining": 5475
    }
  }
}
```

Sent once per step, when its funds actually move to `available`. `remaining` is what just reached your available balance: in this example, the 2500 refund above and its 25 fee were taken from step 1 because it was still locked when the refund was made. A step with nothing left (refunded in full) sends no event. When Loomgate changes the unlock time of a step, no separate webhook is sent: the event comes when the step unlocks at its new time.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.loomgate.io/en/webhooks/webhook-events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
