---
title: "Charges"
description: "4 operations, with parameters and examples."
url: https://docs.fluveo.com/api/charges/
---

> 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/charges.curl.md (cURL), https://docs.fluveo.com/api/charges.node.md (Node.js), https://docs.fluveo.com/api/charges.python.md (Python), https://docs.fluveo.com/api/charges.php.md (PHP).

# Charges

4 operations, with parameters and examples.

A Charge is the record of one attempt to move money for a PaymentIntent. Fluveo creates charges only through PaymentIntents: the legacy POST /v1/charges and POST /v1/charges/{charge}/capture answer a refusal that names the PaymentIntent to capture instead. You may read, list and search charges and change their description and metadata.

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.

## Lists charge objects, newest first

`GET /v1/charges`

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

**Query parameters**

- `created` (object, optional, preview): Filter on the creation time, a Unix timestamp: created=<t> for an exact match, or created[gt], created[gte], created[lt], created[lte].
- `customer` (string, optional): Only the charges of this customer.
- `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.
- `payment_intent` (string, optional): Only the charges of this PaymentIntent.
- `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 [`charge`](https://docs.fluveo.com/api/charges.md#object-charge) objects.

**Request**

cURL:

```bash
curl -G https://api.fluveo.com/v1/charges \
  -H "Authorization: Bearer sk_test_..." \
  --data-urlencode "payment_intent=pi_123"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/charges" + "?" + new URLSearchParams([["payment_intent","pi_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/charges",
    headers={"Authorization": "Bearer sk_test_..."},
    params=[("payment_intent", "pi_123")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/charges?payment_intent=pi_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
{
  "data": [
    {
      "amount": 2000,
      "amount_captured": 2000,
      "captured": true,
      "created": 1767225600,
      "currency": "usd",
      "id": "ch_123",
      "livemode": false,
      "metadata": {},
      "object": "charge",
      "paid": true,
      "payment_intent": "pi_123",
      "payment_method": "pm_123",
      "status": "succeeded"
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/charges"
}
```

## Updates a charge

`POST /v1/charges/{charge}`

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

**Path parameters**

- `charge` (string, required): The Charge'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): Free text for your own records.
- `fraud_details` (object, optional, preview): Your fraud report on the charge: fraud_details[user_report] is fraudulent or safe, and an empty value clears it. Fluveo passes the report on before the charge keeps it.
  - `user_report` (enum, optional): One of: ``, `fraudulent`, `safe`.
- `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.
- `receipt_email` (string, optional, preview): Email address that receives the payment receipt.
- `shipping` (object, optional, preview): Shipping name, address and phone for the order.
  - `address` (object, optional)
    - `city` (string, optional)
    - `country` (string, optional)
    - `line1` (string, optional)
    - `line2` (string, optional)
    - `postal_code` (string, optional)
    - `state` (string, optional)
  - `carrier` (string, optional)
  - `name` (string, optional)
  - `phone` (string, optional)
  - `tracking_number` (string, optional)

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 [`charge`](https://docs.fluveo.com/api/charges.md#object-charge) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/charges/ch_123 \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "description=Order 1042" \
  --data-urlencode "metadata[order_id]=1042"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/charges/ch_123", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: new URLSearchParams([["description","Order 1042"],["metadata[order_id]","1042"]]),
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/charges/ch_123",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
    data=[("description", "Order 1042"), ("metadata[order_id]", "1042")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/charges/ch_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 => "description=Order%201042&metadata%5Border_id%5D=1042",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "amount": 2000,
  "amount_captured": 2000,
  "captured": true,
  "created": 1767225600,
  "currency": "usd",
  "id": "ch_123",
  "livemode": false,
  "metadata": {},
  "object": "charge",
  "paid": true,
  "payment_intent": "pi_123",
  "payment_method": "pm_123",
  "status": "succeeded"
}
```

## Retrieves a charge

`GET /v1/charges/{charge}`

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

**Path parameters**

- `charge` (string, required): The Charge'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 [`charge`](https://docs.fluveo.com/api/charges.md#object-charge) object.

**Request**

cURL:

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

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/charges/ch_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/charges/ch_123",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/charges/ch_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
{
  "amount": 2000,
  "amount_captured": 2000,
  "captured": true,
  "created": 1767225600,
  "currency": "usd",
  "id": "ch_123",
  "livemode": false,
  "metadata": {},
  "object": "charge",
  "paid": true,
  "payment_intent": "pi_123",
  "payment_method": "pm_123",
  "status": "succeeded"
}
```

## Searches charge objects with a query, newest first (Preview)

`GET /v1/charges/search`

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

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

A query is one or more clauses, each a field, an operator and a value, such as status:"succeeded" or amount>1000. The charge fields are amount, created, currency, customer, disputed, refunded, status, billing_details.address.postal_code, payment_method_details.card.brand, exp_month, exp_year, fingerprint and last4 (and the same under card_present and interac_present), and metadata["key"]. amount and created take :, =, <, <=, > and >= with a whole number, quoted or not. Every other field takes only :, which matches the whole value in any case; disputed and refunded take true or false, status takes failed, pending or succeeded, and refunded:null finds the charges not fully refunded. A - before a clause negates it. field:null matches a field that is absent or empty, and -field:null one that is set. Join clauses with AND or OR (a space means AND), never both in one query and never with parentheses, up to 10 clauses. Quote text values with single or double quotes. A query Fluveo cannot read answers invalid_request_error with the reason. When has_more is true, send next_page as page with the same query for the next page. Add expand[]=total_count to get total_count, the number of matches. A charge is found as soon as its PaymentIntent's answer returns.

**Query parameters**

- `limit` (integer, optional): How many objects to return, from 1 to 100. Default 10.
- `page` (string, optional): The next_page of the previous answer, to get the page after it. Send the same query with it.
- `query` (string, required): The search query, in the language the description above gives.

**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 [`charge`](https://docs.fluveo.com/api/charges.md#object-charge) objects.

**Request**

cURL:

```bash
curl -G https://api.fluveo.com/v1/charges/search \
  -H "Authorization: Bearer sk_test_..." \
  --data-urlencode "query=status:\"succeeded\" AND metadata[\"order_id\"]:\"1042\""
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/charges/search" + "?" + new URLSearchParams([["query","status:\"succeeded\" AND metadata[\"order_id\"]:\"1042\""]]), {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/charges/search",
    headers={"Authorization": "Bearer sk_test_..."},
    params=[("query", "status:\"succeeded\" AND metadata[\"order_id\"]:\"1042\"")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/charges/search?query=status%3A%22succeeded%22%20AND%20metadata%5B%22order_id%22%5D%3A%221042%22");
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": [
    {
      "amount": 2000,
      "amount_captured": 2000,
      "captured": true,
      "created": 1767225600,
      "currency": "usd",
      "id": "ch_123",
      "livemode": false,
      "metadata": {},
      "object": "charge",
      "paid": true,
      "payment_intent": "pi_123",
      "payment_method": "pm_123",
      "status": "succeeded"
    }
  ],
  "has_more": false,
  "next_page": null,
  "object": "search_result",
  "url": "/v1/charges/search"
}
```

## The charge object

Ids start with `ch_`.

**Attributes**

- `amount` (integer)
- `amount_captured` (integer)
- `amount_refunded` (integer)
- `application` (string, nullable)
- `application_fee` (string, nullable)
- `application_fee_amount` (integer, nullable)
- `authorization_code` (string)
- `balance_transaction` (string, nullable, expandable): An id by default; send `expand[]=balance_transaction` to get the full balance_transaction object.
- `billing_details` (object)
- `calculated_statement_descriptor` (string, nullable)
- `captured` (boolean)
- `created` (integer)
- `currency` (string)
- `customer` (string, nullable, expandable): An id by default; send `expand[]=customer` to get the full customer or deleted_customer object.
- `description` (string, nullable)
- `disputed` (boolean)
- `failure_balance_transaction` (string, nullable, expandable): An id by default; send `expand[]=failure_balance_transaction` to get the full balance_transaction object.
- `failure_code` (string, nullable)
- `failure_message` (string, nullable)
- `fraud_details` (object, nullable)
- `id` (string)
- `level3` (object)
- `livemode` (boolean)
- `metadata` (object)
- `object` (enum): One of: `charge`.
- `on_behalf_of` (string, nullable, expandable): An id by default; send `expand[]=on_behalf_of` to get the full account object.
- `outcome` (object, nullable)
- `paid` (boolean)
- `payment_intent` (string, nullable, expandable): An id by default; send `expand[]=payment_intent` to get the full payment_intent object.
- `payment_method` (string, nullable)
- `payment_method_details` (object, nullable)
- `presentment_details` (object)
- `radar_options` (object)
- `receipt_email` (string, nullable)
- `receipt_number` (string, nullable)
- `receipt_url` (string, nullable)
- `refunded` (boolean)
- `refunds` (object, nullable)
- `review` (string, nullable)
- `shipping` (object, nullable)
- `source` (object, nullable)
- `source_transfer` (string, nullable)
- `statement_descriptor` (string, nullable)
- `statement_descriptor_suffix` (string, nullable)
- `status` (enum): One of: `failed`, `pending`, `succeeded`.
- `transfer` (string)
- `transfer_data` (object, nullable)
- `transfer_group` (string, nullable)
