---
title: "Request logs"
description: "See each API call your store made, what it sent and got, and open a failed call's log."
url: https://docs.fluveo.com/dashboard/request-logs/
---

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

# Request logs

See each API call your store made, what it sent and got, and open a failed call's log.

Fluveo keeps a log of the calls your store makes to the API. Each log shows the request, the answer and how long it took, so you can see what your code sent without adding logging of your own. When a call fails, its error carries `request_log_url`, a link straight to that call's log.

## Where to find it

Open [Settings > Developers > Logs](https://dash.fluveo.com/settings?section=logs) in the Dashboard. The list shows the newest call first. Logs follow the mode you are in: test mode shows the calls made with test keys, live mode the calls made with live keys.

The list does not update by itself. Press **Refresh** to read it again.

## What a log shows

Each row of the list shows the call's status, its method and path, and its time. Open a row to see the whole log:

| On the screen | What it holds |
| --- | --- |
| **Request ID** | The call's `Request-Id` header (`req_...`). It is the log's id. |
| **Time** | When Fluveo received the call. |
| **Duration** | How long the answer took, in milliseconds. |
| **Source** | **API** for a call made with one of your keys, **Dashboard** for a change made in the Dashboard. |
| **Resource** | The id of the object the call returned, such as `pi_...` or `cus_...`, or else the id in its path. |
| **IP address** | The address the call came from. |
| **API version** | The `Fluveo-Version` the answer used. |
| **API key** | **Secret key** or **Restricted key**, and a hint of the key: its first 8 and last 4 characters, such as `sk_test_...4fQz`. Never the whole key. |
| **Idempotency key** | The `Idempotency-Key` you sent, if any. |
| **User agent** | The `User-Agent` header you sent, up to 256 characters. |
| **Error** | On a failed call: the error's `type`, `code` and `param`. |
| **Request parameters** | The query string and the request body, both shown as JSON. A form body such as `card[exp_month]=12` shows as nested JSON. |
| **Response body** | The JSON the API answered. |

A field the call did not have shows as a dash.

## Filter the list

- **All**, **Succeeded** and **Failed** tabs. Succeeded is any `2xx` answer, Failed is everything else.
- **Filter by path.** Type the start of a path, such as `/v1/customers`, and press Enter.
- **Method.** `GET`, `POST` or `DELETE`, one at a time.
- **Date.** A range of whole days.
- **More filters.** **IP address** (a whole IPv4 or IPv6 address), **Source** (API or Dashboard), **Error code**, such as `card_declined`, and **Resource ID**, such as `cus_...`.

## What is logged

| Logged | Not logged |
| --- | --- |
| Every call made with your secret or restricted keys: `GET`, `POST` and `DELETE` | A call refused before Fluveo knows your store: a missing or unknown key (`401`), an unknown `Fluveo-Version`, a body that is not a form |
| Every change made in the Dashboard (`POST` and `DELETE`), with source **Dashboard** | A call made with a publishable key (`pk_test_...`), which answers `403` with code `secret_key_required` |
| A call your key makes without the permission it needs (`403`), such as a restricted key that can only read PaymentIntents creating a customer. Its request body is kept, masked like every other body | What the Dashboard reads to show its screens |
|  | Payment pages your buyers open, such as Checkout and payment links |

Logging never slows down or fails a call. When Fluveo cannot keep a log in time, it skips that one log and the call still gets its normal answer.

## What is hidden

A log is a copy of what your code sent, so Fluveo masks it before it keeps it. Sensitive values are never stored, and nobody can read them back from a log:

| Value | In the log |
| --- | --- |
| Card numbers | Left out of the body. A card number typed into `metadata` (a key or a value) or into a text field, such as a description, a name or an address line, is masked as the call arrives, before Fluveo keeps it anywhere, so the log shows each of its digits as `X`, such as `XXXX XXXX XXXX XXXX`; in a `metadata` key, some of those `X` are letters. On a Checkout Session or a payment link, every field is masked this way. A card number in any other field shows as `[redacted_card_number]`. |
| Card security codes (CVC) | Left out. In text, `[redacted_card_check]`. |
| Card expiry dates you send | Left out of the request. |
| Secrets: a PaymentIntent's or SetupIntent's `client_secret`, a webhook endpoint's `secret` (`whsec_...`), any field whose name contains `secret` | Left out. In text, `[redacted_secret]`. |
| API keys | The `Authorization` header is never stored, only the key hint. A key pasted into a body or a query shows as `[redacted_secret]`. |
| Passwords | Any field whose name contains `password` or `passwd`, `metadata` included, is left out. A web address with a user name and password in it shows as `[redacted_secret]`. |
| Wallet tokens | Apple Pay payment data (`pk_token` and its companion fields) and any field whose name ends in `token` are left out. |
| Bank account numbers | Every `account_number` field is left out. Any run of 12 or more digits in text shows as `[redacted_card_number]`. |

A field that is left out is not in the stored body at all; there is no placeholder in its place. Masking changes only the log: the answer your code gets is never changed by it.

## Bodies that are not kept

Some bodies are not stored, and the log says why in one sentence where the body would be:

| The log says | When |
| --- | --- |
| This request sent no body. / This answer had no body. | There was no body. |
| A read keeps no response body. | The call was a `GET`. Its query and, on a failed `GET`, its error `type`, `code` and `param` are still kept. |
| This body was *n* bytes, more than a log keeps, so it was not kept. | The request body was over 32 KiB, or the answer over 64 KiB. The size is kept. |
| This body could not be shown safely, so it was not kept. | Fluveo could not read the whole body to mask it, for example a body that is not JSON or a form. |

## How long logs are kept

- A `GET` call is kept for 31 days.
- A `POST` or `DELETE` call is kept for 15 months.

After that the log is deleted and its link opens a message that says it isn't available.

## Who can see logs

Only people who are members of your store and sign in to its Dashboard can read its logs, and only in the mode they are in. There is no API endpoint that reads logs and no API key can open one. A log of another store is never shown, not even with its exact `req_...` id.

## Open a log from an error

Every error of a logged call carries `error.request_log_url`, a link to that call's log in the Dashboard:

| Mode | Link |
| --- | --- |
| Test | `https://dash.fluveo.com/<store id>/test/logs?object=<request id>` |
| Live | `https://dash.fluveo.com/<store id>/logs?object=<request id>` |

`<store id>` is your store's id (`mch_...`) and `<request id>` is the answer's own `Request-Id` header.

- The link is there exactly when the call is logged. An error of a call that is not logged has none, such as a `401` for a missing or unknown key, or a publishable key's `secret_key_required`.
- A replayed answer, one that comes back with `Idempotent-Replayed: true`, is a call of its own: its link names its own `Request-Id`, not the first call's. The first call's id is in its `Original-Request` header.
- The link is only on the answer. A PaymentIntent's `last_payment_error` and the events Fluveo sends never carry it.
- A successful answer never carries it. To find a successful call, filter the list by its path or resource id.

Open the link in a browser. If you are signed out, the Dashboard asks you to sign in and then opens the log. It shows the log only when the link is of the store and mode you are in:

| The link is | The Dashboard shows |
| --- | --- |
| Of the store and mode you are in | The log |
| Of another store you are a member of | **This log belongs to another account**, with **Switch account** |
| Of a store you are not a member of | **This log isn't in an account you can open** |
| Of the other mode | **This log is from test mode** or **This log is from live mode**: switch mode, then open the link again |
| Of a log that expired or was not kept | **This log isn't available** |

> **For AI agents:**
>
> error.request_log_url is a link for a person: it opens only in a signed-in Dashboard session, so never fetch it from code and never try to read a log through the API (there is no endpoint). Log it next to the Request-Id and show it to the developer. Its absence is normal on a 401 and on secret_key_required. Never put a card number, CVC, secret or full key in metadata, a description or any other field to see it in a log: the log masks it, and it should not be sent at all.

## Example: a failed call and its log

### Step 1: Send a call that fails

Create a PaymentIntent with an amount that is not a whole number. The `-i` flag prints the answer's headers too.

```bash
curl -i https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -d amount=abc \
  -d currency=usd \
  -d "payment_method_types[]=card"
```

### Step 2: Read the error

The answer is `400` with a `Request-Id` header, such as `Request-Id: req_8Kd2mPq7XzT4bN`. The error names the field at fault and carries `request_log_url`, whose `object` is that same id.

*400 Bad Request*

```json
{
  "error": {
    "code": "parameter_invalid_integer",
    "doc_url": "https://docs.fluveo.com/errors#parameter_invalid_integer",
    "message": "Invalid integer: abc",
    "param": "amount",
    "request_log_url": "https://dash.fluveo.com/mch_.../test/logs?object=req_8Kd2mPq7XzT4bN",
    "type": "invalid_request_error"
  }
}
```

### Step 3: Open the log

Open `request_log_url` while signed in to the Dashboard in test mode. The log opens with the title `POST /v1/payment_intents` and a `400` badge. **Request ID** is `req_8Kd2mPq7XzT4bN`, **Source** is **API** and **API key** shows **Secret key** with your key's hint. **Error** shows type `invalid_request_error`, code `parameter_invalid_integer` and parameter `amount`.

**Request parameters** shows what you sent, as JSON. **Response body** shows the error above, link included.

*Request parameters*

```json
{
  "amount": "abc",
  "currency": "usd",
  "payment_method_types": ["card"]
}
```

Fix the amount (`2000` is 20.00 in the currency's smallest unit) and send the call again. The new call has its own log, under **Succeeded**.

## Next

- [Errors](https://docs.fluveo.com/errors.md) lists every error and what to do about it.
- [Authentication](https://docs.fluveo.com/start/authentication.md) covers keys and the `Request-Id` header.
- [Idempotency](https://docs.fluveo.com/start/idempotency.md) explains replayed answers.
- [Support](https://docs.fluveo.com/support.md) says what to send when you need help.
