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 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
2xxanswer, Failed is everything else. - Filter by path. Type the start of a path, such as
/v1/customers, and press Enter. - Method.
GET,POSTorDELETE, 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 ascus_....
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
GETcall is kept for 31 days. - A
POSTorDELETEcall 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
401for a missing or unknown key, or a publishable key'ssecret_key_required. - A replayed answer, one that comes back with
Idempotent-Replayed: true, is a call of its own: its link names its ownRequest-Id, not the first call's. The first call's id is in itsOriginal-Requestheader. - The link is only on the answer. A PaymentIntent's
last_payment_errorand 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 |
Example: a failed call and its log#
Send a call that fails#
Create a PaymentIntent with an amount that is not a whole number. The
-iflag prints the answer's headers too.cURLcurl -i https://api.fluveo.com/v1/payment_intents \ -H "Authorization: Bearer sk_test_..." \ -d amount=abc \ -d currency=usd \ -d "payment_method_types[]=card"Read the error#
The answer is
400with aRequest-Idheader, such asRequest-Id: req_8Kd2mPq7XzT4bN. The error names the field at fault and carriesrequest_log_url, whoseobjectis that same id.400 Bad Request{ "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" } }Open the log#
Open
request_log_urlwhile signed in to the Dashboard in test mode. The log opens with the titlePOST /v1/payment_intentsand a400badge. Request ID isreq_8Kd2mPq7XzT4bN, Source is API and API key shows Secret key with your key's hint. Error shows typeinvalid_request_error, codeparameter_invalid_integerand parameteramount.Request parameters shows what you sent, as JSON. Response body shows the error above, link included.
Request parameters{ "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 lists every error and what to do about it.
- Authentication covers keys and the
Request-Idheader. - Idempotency explains replayed answers.
- Support says what to send when you need help.