---
title: "Webhook endpoints"
description: "5 operations, with parameters and examples."
url: https://docs.fluveo.com/api/webhook_endpoints/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/api/webhook_endpoints.curl.md (cURL), https://docs.fluveo.com/api/webhook_endpoints.node.md (Node.js), https://docs.fluveo.com/api/webhook_endpoints.python.md (Python), https://docs.fluveo.com/api/webhook_endpoints.php.md (PHP).

# Webhook endpoints

5 operations, with parameters and examples.

A webhook endpoint is a URL of the store's that receives events. Each endpoint has its own signing secret and its own list of event types. The secret is shown in full only when the endpoint is created. Every delivery is a POST with a Fluveo-Signature header, t=<unix seconds>,v1=<signature>, where the signature is the hex HMAC-SHA256 of <t>.<raw body> keyed with the endpoint's whsec_ secret. Check it against the raw body, and refuse a delivery whose t is more than 5 minutes old. When the secret is rotated in the Dashboard with an expiration (up to 7 days), the old secret keeps signing until then: the header carries one v1 per secret still valid, the current first, as t=<unix seconds>,v1=<new>,v1=<old>. Accept the delivery when any v1 matches.

Send every request to `https://api.fluveo.com/v1` with your secret key as a Bearer token. This page lists only what Fluveo serves; [the OpenAPI file](https://docs.fluveo.com/openapi.json) holds the same operations.

An operation or a parameter marked **Preview** works, but it is not locked yet and may change: [what Preview means](https://docs.fluveo.com/api.md#preview).

> **For AI agents:**
>
> Use plain HTTP; install no payments SDK. Send `Authorization: Bearer sk_test_...` and a fresh `Idempotency-Key` on every POST; reuse the same key only when you retry that same POST. Send only the documented parameters. An operation or a parameter marked Preview may change: prefer the ones without the mark.

## Creates a webhook endpoint. The answer is the only one that carries the full signing secret (Preview)

`POST /v1/webhook_endpoints`

Permission: [`rak_webhook_write`](https://docs.fluveo.com/permissions.md#webhook).

**Preview:** this operation works, but it is not locked yet; it may change.

**Headers**

- `Idempotency-Key` (string, optional): Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

**Body parameters**

- `api_version` (enum, optional): Only 2026-05-27.dahlia, the one API version Fluveo serves. Leave it out to get that version.

  One of: `2011-01-01`, `2011-06-21`, `2011-06-28`, `2011-08-01`, `2011-09-15`, `2011-11-17`, `2012-02-23`, `2012-03-25`, `2012-06-18`, `2012-06-28`, `2012-07-09`, `2012-09-24`, `2012-10-26`, `2012-11-07`, `2013-02-11`, `2013-02-13`, `2013-07-05`, `2013-08-12`, `2013-08-13`, `2013-10-29`, `2013-12-03`, `2014-01-31`, `2014-03-13`, `2014-03-28`, `2014-05-19`, `2014-06-13`, `2014-06-17`, `2014-07-22`, `2014-07-26`, `2014-08-04`, `2014-08-20`, `2014-09-08`, `2014-10-07`, `2014-11-05`, `2014-11-20`, `2014-12-08`, `2014-12-17`, `2014-12-22`, `2015-01-11`, `2015-01-26`, `2015-02-10`, `2015-02-16`, `2015-02-18`, `2015-03-24`, `2015-04-07`, `2015-06-15`, `2015-07-07`, `2015-07-13`, `2015-07-28`, `2015-08-07`, `2015-08-19`, `2015-09-03`, `2015-09-08`, `2015-09-23`, `2015-10-01`, `2015-10-12`, `2015-10-16`, `2016-02-03`, `2016-02-19`, `2016-02-22`, `2016-02-23`, `2016-02-29`, `2016-03-07`, `2016-06-15`, `2016-07-06`, `2016-10-19`, `2017-01-27`, `2017-02-14`, `2017-04-06`, `2017-05-25`, `2017-06-05`, `2017-08-15`, `2017-12-14`, `2018-01-23`, `2018-02-05`, `2018-02-06`, `2018-02-28`, `2018-05-21`, `2018-07-27`, `2018-08-23`, `2018-09-06`, `2018-09-24`, `2018-10-31`, `2018-11-08`, `2019-02-11`, `2019-02-19`, `2019-03-14`, `2019-05-16`, `2019-08-14`, `2019-09-09`, `2019-10-08`, `2019-10-17`, `2019-11-05`, `2019-12-03`, `2020-03-02`, `2020-08-27`, `2022-08-01`, `2022-11-15`, `2023-08-16`, `2023-10-16`, `2024-04-10`, `2024-06-20`, `2024-09-30.acacia`, `2024-10-28.acacia`, `2024-11-20.acacia`, `2024-12-18.acacia`, `2025-01-27.acacia`, `2025-02-24.acacia`, `2025-03-01.dashboard`, `2025-03-31.basil`, `2025-04-30.basil`, `2025-05-28.basil`, `2025-06-30.basil`, `2025-07-30.basil`, `2025-08-27.basil`, `2025-09-30.clover`, `2025-10-29.clover`, `2025-11-17.clover`, `2025-12-15.clover`, `2026-01-28.clover`, `2026-02-25.clover`, `2026-03-25.dahlia`, `2026-04-22.dahlia`, `2026-05-27.dahlia`.
- `description` (string, optional): A note for your own records.
- `enabled_events` (array of string, required): The event types this endpoint receives, as enabled_events[]=..., or ["*"] for all. Any event type of API version 2026-05-27.dahlia: a type not on the event types page is taken and never sent; any other type is refused with 400 on enabled_events[i].
- `metadata` (object, optional): Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.
- `url` (string, required): The address that receives the events. It must use https in live mode; a test-mode endpoint may also use plain http.

Use only the documented body parameters. Send a new `Idempotency-Key` with each new request, and the same key again only to retry that request.

Returns a [`webhook_endpoint`](https://docs.fluveo.com/api/webhook_endpoints.md#object-webhook_endpoint) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "enabled_events[]=payment_intent.succeeded" \
  --data-urlencode "enabled_events[]=charge.refunded" \
  --data-urlencode "url=https://example.com/fluveo/webhooks"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/webhook_endpoints", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: new URLSearchParams([["enabled_events[]","payment_intent.succeeded"],["enabled_events[]","charge.refunded"],["url","https://example.com/fluveo/webhooks"]]),
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/webhook_endpoints",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
    data=[("enabled_events[]", "payment_intent.succeeded"), ("enabled_events[]", "charge.refunded"), ("url", "https://example.com/fluveo/webhooks")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/webhook_endpoints");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => "enabled_events%5B%5D=payment_intent.succeeded&enabled_events%5B%5D=charge.refunded&url=https%3A%2F%2Fexample.com%2Ffluveo%2Fwebhooks",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "api_version": "2026-05-27.dahlia",
  "created": 1767225600,
  "enabled_events": [
    "payment_intent.succeeded",
    "charge.refunded"
  ],
  "id": "we_123",
  "livemode": false,
  "metadata": {},
  "object": "webhook_endpoint",
  "status": "enabled",
  "url": "https://example.com/fluveo/webhooks"
}
```

## Lists the store's webhook endpoints (Preview)

`GET /v1/webhook_endpoints`

Permission: [`rak_webhook_read`](https://docs.fluveo.com/permissions.md#webhook).

**Preview:** this operation works, but it is not locked yet; it may change.

**Query parameters**

- `ending_before` (string, optional): Cursor: the id of the first object of the current page, to get the previous page. Do not send it with starting_after.
- `limit` (integer, optional): How many objects to return, from 1 to 100. Default 10.
- `starting_after` (string, optional): Cursor: the id of the last object of the previous page, to get the next page. Do not send it with ending_before.

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Returns a list of [`webhook_endpoint`](https://docs.fluveo.com/api/webhook_endpoints.md#object-webhook_endpoint) objects.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/webhook_endpoints", {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/webhook_endpoints",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/webhook_endpoints");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "data": [
    {
      "api_version": "2026-05-27.dahlia",
      "created": 1767225600,
      "enabled_events": [
        "payment_intent.succeeded",
        "charge.refunded"
      ],
      "id": "we_123",
      "livemode": false,
      "metadata": {},
      "object": "webhook_endpoint",
      "status": "enabled",
      "url": "https://example.com/fluveo/webhooks"
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/webhook_endpoints"
}
```

## Updates a webhook endpoint's url, event types, description, metadata or disabled flag (Preview)

`POST /v1/webhook_endpoints/{webhook_endpoint}`

Permission: [`rak_webhook_write`](https://docs.fluveo.com/permissions.md#webhook).

**Preview:** this operation works, but it is not locked yet; it may change.

**Path parameters**

- `webhook_endpoint` (string, required): The webhook endpoint's id.

**Headers**

- `Idempotency-Key` (string, optional): Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

**Body parameters**

- `description` (string, optional): A note for your own records.
- `disabled` (boolean, optional): true stops deliveries to this endpoint; false starts them again.
- `enabled_events` (array of string, optional): The event types this endpoint receives, as enabled_events[]=..., or ["*"] for all. Any event type of API version 2026-05-27.dahlia: a type not on the event types page is taken and never sent; any other type is refused with 400 on enabled_events[i].
- `metadata` (object, optional): Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.
- `url` (string, optional): The address that receives the events. It must use https in live mode; a test-mode endpoint may also use plain http.

Use only the documented body parameters. Send a new `Idempotency-Key` with each new request, and the same key again only to retry that request.

Returns a [`webhook_endpoint`](https://docs.fluveo.com/api/webhook_endpoints.md#object-webhook_endpoint) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/webhook_endpoints/we_123 \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "disabled=true"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/webhook_endpoints/we_123", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: new URLSearchParams([["disabled","true"]]),
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/webhook_endpoints/we_123",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
    data=[("disabled", "true")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/webhook_endpoints/we_123");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => "disabled=true",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "api_version": "2026-05-27.dahlia",
  "created": 1767225600,
  "enabled_events": [
    "payment_intent.succeeded",
    "charge.refunded"
  ],
  "id": "we_123",
  "livemode": false,
  "metadata": {},
  "object": "webhook_endpoint",
  "status": "enabled",
  "url": "https://example.com/fluveo/webhooks"
}
```

## Retrieves a webhook endpoint (Preview)

`GET /v1/webhook_endpoints/{webhook_endpoint}`

Permission: [`rak_webhook_read`](https://docs.fluveo.com/permissions.md#webhook).

**Preview:** this operation works, but it is not locked yet; it may change.

**Path parameters**

- `webhook_endpoint` (string, required): The webhook endpoint's id.

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Returns a [`webhook_endpoint`](https://docs.fluveo.com/api/webhook_endpoints.md#object-webhook_endpoint) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/webhook_endpoints/we_123 \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/webhook_endpoints/we_123", {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/webhook_endpoints/we_123",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/webhook_endpoints/we_123");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "api_version": "2026-05-27.dahlia",
  "created": 1767225600,
  "enabled_events": [
    "payment_intent.succeeded",
    "charge.refunded"
  ],
  "id": "we_123",
  "livemode": false,
  "metadata": {},
  "object": "webhook_endpoint",
  "status": "enabled",
  "url": "https://example.com/fluveo/webhooks"
}
```

## Deletes a webhook endpoint; no more events go to it (Preview)

`DELETE /v1/webhook_endpoints/{webhook_endpoint}`

Permission: [`rak_webhook_write`](https://docs.fluveo.com/permissions.md#webhook).

**Preview:** this operation works, but it is not locked yet; it may change.

**Path parameters**

- `webhook_endpoint` (string, required): The webhook endpoint's id.

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

**Request**

cURL:

```bash
curl -X DELETE https://api.fluveo.com/v1/webhook_endpoints/we_123 \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/webhook_endpoints/we_123", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.delete(
    "https://api.fluveo.com/v1/webhook_endpoints/we_123",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/webhook_endpoints/we_123");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "deleted": true,
  "id": "we_123",
  "object": "webhook_endpoint"
}
```

## The webhook_endpoint object

Ids start with `we_`.

**Attributes**

- `api_version` (string, nullable)
- `application` (string, nullable)
- `created` (integer)
- `description` (string, nullable)
- `enabled_events` (array)
- `id` (string)
- `livemode` (boolean)
- `metadata` (object)
- `object` (enum): One of: `webhook_endpoint`.
- `secret` (string)
- `status` (string)
- `url` (string)
