> For the complete documentation index, see [llms.txt](https://docs.onelens.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.onelens.cloud/integrations/cloud-and-cost-sources/connecting-to-cloudflare.md).

# Connecting to Cloudflare

Connect your Cloudflare account to OneLens for cost intelligence, per-product and per-zone cost attribution, budget and anomaly alerting, and invoice reconciliation, using a read-only account-owned API token and Cloudflare's own billable usage data.

{% hint style="warning" %}
**Coverage limit, read this first.** This integration supports **pay-as-you-go (self-serve) Cloudflare accounts only.** Cloudflare's billable usage endpoints cover self-serve subscriptions only, so OneLens **cannot** ingest cost for accounts on an Enterprise contract. Cloudflare has said Enterprise support is in the works, with no published date. See [Before You Start: Is Your Account Supported?](#before-you-start-is-your-account-supported) to check which you have in under a minute.
{% endhint %}

## TL;DR

* **What this does:** Pulls billed cost per Cloudflare product from the Billable Usage API, the same system that generates your invoice, so Cloudflare spend reports next to AWS, GCP, Azure, and OCI in OneLens.
* **Time required:** \~10 minutes.
* **Who you need:** A **Super Administrator** on the Cloudflare account. Only Super Administrators can create account-owned API tokens.
* **What OneLens reads:** Billing records only, through exactly one read-only permission: `Billing → Read`. No traffic data, no analytics, no logs, no DNS records, no configuration, and nothing about how your services perform.

## Before You Start: Is Your Account Supported?

Cloudflare bills two different ways, and only one of them exposes cost programmatically. Find your row before you do anything else.

| Your account                                                                                                                 | What Cloudflare exposes                                                                     | OneLens support                                   |
| ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| **Pay-as-you-go (self-serve).** You signed up with a card and pay metered charges for Workers, R2, D1, and similar products. | Full cost rows via the Billable Usage API, from the same system that generates your invoice | ✅ **Fully supported**                             |
| **Enterprise (contract).** You have a negotiated annual agreement with committed spend and custom rates.                     | No cost data at all. No contract rates, no commit, no monthly charge, no discounts          | ❌ **Not supported**                               |
| **Mixed.** Some self-serve subscriptions sit alongside a contract.                                                           | Only the self-serve portion                                                                 | ⚠️ **Partially supported.** Self-serve spend only |

**Check in 30 seconds, no token needed.** In the Cloudflare dashboard go to **Manage Account → Billing → Billable Usage**. A populated daily cost chart with per-product rows means you are on pay-as-you-go and this integration will work. An empty page, or one saying the account is not eligible, means you are on an Enterprise contract.

{% hint style="info" %}
**Why we can't work around this.** Your negotiated rate card, commitment, and platform fee are not in any Cloudflare API. Most Enterprise spend is a flat negotiated fee with no meter behind it, so there is nothing to read and nothing to derive it from. Rather than show you an invented figure, we tell you the integration doesn't apply today. Cloudflare has said an Enterprise equivalent is in the works. When it ships, we will add it, and this page will change.
{% endhint %}

{% hint style="info" %}
**More than one Cloudflare account?** This flow connects one account. Cloudflare's account-owned tokens are scoped to the account that owns them, so run these five steps once per account, each with its own token. OneLens reports across all of them together, so you still get one consolidated Cloudflare view. Coverage is decided per account, which matters if some of yours are on contracts.
{% endhint %}

## What You'll Get Once Connected

| Capability                     | What it does for you                                                                                                                                                                                                                                                                            |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Unified Cost Explorer**      | Cloudflare spend sits next to your AWS, GCP, Azure, and OCI cost in one view, on the same date and currency basis                                                                                                                                                                               |
| **FOCUS-aligned ingestion**    | Cloudflare's billing fields are modelled on the FinOps Open Cost & Usage Specification, the same schema OneLens uses for AWS, GCP, and Azure, so it lands with little custom mapping. Cloudflare does not yet claim full FOCUS conformance, so OneLens fills the gaps rather than assuming them |
| **Per-Product Cost Breakdown** | Daily billed cost for each product you use, from Workers and R2 through to Zero Trust seats and Images                                                                                                                                                                                          |
| **Per-Zone Cost**              | Where Cloudflare attributes a charge to a specific domain, OneLens reports it against that zone. This is billed cost from Cloudflare, not an estimate                                                                                                                                           |
| **Free Allowance Visibility**  | Cloudflare reports metered quantity and billable quantity separately, so you can see how much of your usage the free tier absorbed and how close a product is to becoming a real line item                                                                                                      |
| **Discount Visibility**        | List cost and billed cost arrive as separate fields, so any difference between rate card and what you paid is visible rather than buried                                                                                                                                                        |
| **Anomaly Detection**          | Alerts when a product's daily spend breaks its own pattern, so you find the spike inside the month instead of on the invoice                                                                                                                                                                    |
| **Budget Tracking**            | Set Cloudflare budgets with OneLens alerting, at account or product level                                                                                                                                                                                                                       |
| **Multi-Account Reporting**    | Connect each Cloudflare account you own and OneLens reports across all of them, converted into one currency                                                                                                                                                                                     |
| **Invoice Reconciliation**     | Billed cost comes from the system that generates your invoice, so OneLens totals tie out to what you actually pay, minus the flat fees noted in step 4                                                                                                                                          |

## Security at a Glance

This is a cost-only integration, which makes the security story short: OneLens reads your bill and nothing else.

| Question                                                     | Answer                                                                                                                                                                                                                                                                                                                                                         |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Does OneLens read our traffic, requests, or responses?       | **No.** OneLens reads billing records. It does not request analytics permissions of any kind, so traffic data is not reachable with this token.                                                                                                                                                                                                                |
| Does OneLens read our usage or performance data?             | **No.** Request counts, CPU time, cache hit ratios and the like are analytics, and analytics is out of scope for this integration. The only quantities OneLens sees are the billable quantities printed on your bill.                                                                                                                                          |
| Does OneLens read our raw logs?                              | **No.** The `Logs: Read` scope is not on the token, so Logpull, Logpush, and Instant Logs are all out of reach.                                                                                                                                                                                                                                                |
| Can OneLens see or change our DNS records?                   | **No.** The token carries no zone-scoped permission at all. Zone names arrive inside the billing records, so OneLens never needs to read your zone configuration.                                                                                                                                                                                              |
| Can OneLens change our configuration, routing, or WAF rules? | **No.** The single scope on the token is `Read`. No write, edit, or admin permission is granted anywhere.                                                                                                                                                                                                                                                      |
| Can OneLens change our plan or payment method?               | **No.** That requires `Billing → Write`. OneLens requests `Billing → Read` only.                                                                                                                                                                                                                                                                               |
| Does OneLens see our billing address or card details?        | **No.** OneLens reads the billable usage endpoints, not the billing profile. Card metadata and address are not ingested.                                                                                                                                                                                                                                       |
| Can OneLens reach our other Cloudflare accounts?             | **No.** An account-owned token is scoped to the account that owns it. A token you create in one account cannot read another, even one you also own.                                                                                                                                                                                                            |
| What authentication is used?                                 | An **account-owned scoped API Token** created by you, carrying a single read permission. It is a service principal rather than a credential tied to a person. OneLens never asks for your Global API Key.                                                                                                                                                      |
| Can I restrict the token by IP?                              | **Yes.** Cloudflare supports Client IP Address Filtering on the token itself, which makes it unusable from anywhere else. If your security policy requires it, ask <support@astuto.ai> for our current egress ranges before you create the token. We do not publish them here because they change, and a stale list in a document breaks working integrations. |
| Can I set the token to expire?                               | **Yes.** Cloudflare tokens support a TTL. Set one to match your rotation policy, and OneLens will alert you before expiry.                                                                                                                                                                                                                                     |
| How is data transmitted and stored?                          | All API calls use HTTPS/TLS 1.2+. The token is encrypted at rest in OneLens using GCP KMS.                                                                                                                                                                                                                                                                     |
| What is the data retention policy?                           | OneLens retains ingested data for 12 months by default, configurable. On disconnection or a deletion request, data is purged within 30 days with confirmation.                                                                                                                                                                                                 |
| Where does the data live?                                    | OneLens infrastructure runs on GCP. See the OneLens Trust & Security page for region details, SOC 2 report, and DPA.                                                                                                                                                                                                                                           |

## Cost of the Integration

OneLens does not create any infrastructure in your Cloudflare account. Cloudflare does not charge for Billable Usage API calls, and OneLens makes two per day.

| Item                    | What it is                                                                            | Typical cost |
| ----------------------- | ------------------------------------------------------------------------------------- | ------------ |
| Cloudflare API calls    | Billing API calls are not metered or billed by Cloudflare                             | $0           |
| Compute in your account | None. No Worker deployed, no agent installed, no container run                        | $0           |
| Data egress             | JSON responses, typically well under 1 MB/day. API responses are not billed as egress | $0           |
| Storage in your account | None. OneLens stores ingested data in its own infrastructure                          | $0           |
| **Estimated total**     | Sum of the above                                                                      | **$0/month** |

## How It Works

Cloudflare's **Billable Usage API** (`/accounts/{account_id}/billable-usage`) returns one row per product per charge period. Each row carries the billed cost, the list cost, the billable quantity, and the unit it was priced in. The data comes from the same system that generates your monthly invoice, so the totals reconcile to what you actually pay rather than to an estimate.

The fields are modelled on the FinOps Open Cost & Usage Specification (FOCUS), the same schema OneLens already uses for AWS, GCP, and Azure. Cloudflare states it is not yet claiming full FOCUS conformance, so treat the shape as close but not identical. OneLens fills the gaps rather than assuming them.

OneLens calls two things, once a day:

1. `GET /accounts/{account_id}/billable-usage/info` to confirm the account still returns billing data.
2. `GET /accounts/{account_id}/billable-usage` for the cost rows themselves.

That is the whole integration. There is no agent, no webhook, no data pushed from your side.

### What granularity you get, and what you don't

Cost arrives at **product level**, plus **zone level** wherever Cloudflare attributes a charge to a specific domain. Zone-scoped charges such as domain plans and per-zone add-ons carry a zone ID and name in the billing record, so those report against the right domain automatically.

Account-level products do not break down further. Workers arrives as Workers, not per script. R2 arrives as R2 storage and R2 operations, not per bucket. The same applies to D1, KV, Durable Objects, and Queues. Cloudflare does not attribute those charges below the product, and this integration reads only what Cloudflare bills, so OneLens does not estimate a split.

{% hint style="info" %}
**Why we don't estimate the split.** Cloudflare's analytics API can tell you how many requests each Worker served, and we could apportion the product's cost across scripts in proportion. We don't, for two reasons. Cloudflare's own documentation warns that analytics datasets "should not be used as a measure for usage that Cloudflare uses for billing purposes", because they count traffic that billing excludes. And an apportioned number does not reconcile to an invoice line, which makes it a liability the moment someone builds a chargeback on it. Every figure in this integration is one Cloudflare billed you.
{% endhint %}

Cloudflare's billing data also carries no tag dimension. [Resource Tagging](https://developers.cloudflare.com/resource-tagging/) exists, in public beta on all plans, and Cloudflare lists billing attribution among its purposes, but the tags do not appear as a field in the billable usage response the way an activated AWS cost allocation tag appears as a CUR column. Group your Cloudflare accounts and zones into cost centres in OneLens instead.

## What OneLens Will Access

**One permission. That is the whole request.**

| Scope       | Level   | Access | Why OneLens needs it                                                                                                                                                                                                                                             |
| ----------- | ------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Billing** | Account | Read   | Every cost figure in the integration. Cloudflare describes this scope as granting "read access to billing profile, subscriptions, and access to fetch invoices and entitlements", which covers the cost rows and the subscription data behind the coverage check |

Nothing else is requested. Not analytics, not account settings, not zone permissions, not logs. If OneLens ever asks you for a second Cloudflare permission, ask us why before granting it.

### Endpoints

Both calls are covered by that single scope, and Cloudflare lists Billing as supported for account-owned tokens.

| API call                                         | Purpose                                                                                                                                        |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /accounts/{account_id}/billable-usage`      | Billed cost and billable quantity per product per charge period *(the cost source)*                                                            |
| `GET /accounts/{account_id}/billable-usage/info` | Coverage check, confirming the account returns billing data. Its response also carries the account's subscription IDs and billing cycle anchor |

{% hint style="warning" %}
**Note on API maturity.** Cloudflare labels its billing usage endpoints *Version 1, Alpha*, with a *Version 2, Alpha, Restricted* successor. Alpha means Cloudflare can change the shape without a deprecation cycle. Cloudflare's billing index also lists each billable-usage path twice, once plain Alpha and once marked Deprecated, so if you go browsing the reference yourself, expect to meet a deprecated twin of the exact path above. OneLens builds on the v1 endpoints because they are the ones open to self-serve accounts today, we monitor the reference for changes, and absorbing a schema change is our job rather than yours. We flag it because it is the one part of this integration that depends on an interface Cloudflare has not frozen.
{% endhint %}

## What OneLens Will NOT Access

* ❌ **Analytics of any kind.** No analytics permission is on the token, so request counts, CPU time, bandwidth, and cache statistics are unreachable
* ❌ **Raw logs.** `Logs: Read` is not requested, so Logpull, Logpush, and Instant Logs are out of reach
* ❌ **DNS records and zone configuration.** The token carries no zone-scoped permission at all
* ❌ **Worker source code and R2 object contents.** Neither `Workers Scripts Read` nor `Workers R2 Storage Read` is requested
* ❌ **Your billing profile.** OneLens reads the billable usage endpoints, not `/billing/profile`, so address and card metadata are not ingested
* ❌ **Account settings and membership.** `Account Settings → Read` is not requested, so OneLens cannot list your accounts, members, or account-level features
* ❌ **Your other Cloudflare accounts.** An account-owned token cannot reach beyond the account that owns it
* ❌ **Any write, edit, or admin scope.** The one permission on the token is `Read`
* ❌ **Billing writes.** OneLens cannot change your plan, add-ons, subscriptions, or payment method
* ❌ **Your Global API Key.** OneLens will refuse it if offered

## Prerequisites

* A Cloudflare account on a **pay-as-you-go (self-serve)** subscription. Confirm via [Before You Start: Is Your Account Supported?](#before-you-start-is-your-account-supported).
* A **Super Administrator** on that account. Account-owned tokens can only be created and managed by Super Administrators.
* Your **Account ID**, the 32-character string in the dashboard URL after `dash.cloudflare.com/`.
* `curl` and `jq` on the machine you run the validation calls from.

## Validate and Connect

{% stepper %}
{% step %}

## Create the Account-Owned API Token

Create an **account-owned** token, not a personal one. Account-owned tokens are service principals: they belong to the account rather than to you, so the integration keeps working when you change roles or leave the company. A user token dies with its owner's access.

1. In the Cloudflare dashboard, go to **Manage Account → API Tokens → Create Token**. Creating the token from the account's own API Tokens page, rather than from **My Profile**, is what makes it account-owned.
2. Under **Custom token**, select **Get started**.
3. Name it something traceable, such as `onelens-cost-readonly`.
4. Add one permission row, and only this one:

| Dropdown 1 | Dropdown 2 | Dropdown 3 |
| ---------- | ---------- | ---------- |
| Account    | Billing    | Read       |

5. Under **Account Resources**, leave the selection on this account. An account-owned token is scoped to its owning account, so there is nothing to widen here.
6. Leave **Zone Resources** unset. This integration needs no zone-scoped permission, because zone names arrive inside the billing records.
7. Under **TTL**, set an expiry matching your rotation policy. 90 days is common. Leave blank for no expiry.
8. Select **Continue to summary**, review, then **Create Token**.
9. Copy the token immediately. Cloudflare shows it once and never again.

{% hint style="danger" %}
**Do not use a Global API Key.** It grants full read and write access to every resource on every account and zone your user can reach, and it carries none of the scoping, IP filtering, or TTL that the token flow above gives you. OneLens will not accept one.
{% endhint %}
{% endstep %}

{% step %}

## Verify the Token

Confirm the token is active before testing anything else.

```bash
export CF_TOKEN="your_token_here"
export CF_ACCOUNT_ID="your_32_char_account_id"

curl -s "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer $CF_TOKEN" | jq
```

Expected:

```json
{
  "success": true,
  "result": {
    "id": "ed17574386854bf78a67040be0a770b0",
    "status": "active"
  }
}
```

A `success: false` with code `6111` means the token string is wrong.
{% endstep %}

{% step %}

## Confirm Your Account Is Covered

This is the decisive call. It tells you whether the Billable Usage API will return anything at all for this account.

```bash
curl -s "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/billable-usage/info" \
  -H "Authorization: Bearer $CF_TOKEN" | jq
```

Expected on a supported account:

```json
{
  "success": true,
  "result": {
    "covered": true,
    "subscriptions": [
      {
        "id": "ff2af59d0c9b4b1a9c9c4a...",
        "billing_cycle_anchor_timestamp": "2026-08-14T00:00:00Z",
        "start_timestamp": "2025-08-14T00:00:00Z",
        "end_timestamp": null
      }
    ]
  }
}
```

| `covered` value | What it means                                                     | What to do                                                                                  |
| --------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `true`          | The account has self-serve subscriptions and returns billing data | Continue to step 4                                                                          |
| `false`         | The account is entirely on an Enterprise contract                 | **Stop.** This integration cannot ingest cost for this account. Contact <support@astuto.ai> |

{% hint style="info" %}
**If you are connecting several accounts, check each one.** Coverage is a property of the account, not of your organization, and a mixed result is normal. It is especially common if an Enterprise account sits alongside self-serve ones.
{% endhint %}
{% endstep %}

{% step %}

## Validate the Cost Data

Pull last month's billed cost. Omitting `from` and `to` defaults to the current billing period, which may be nearly empty early in a cycle, so a closed month is the better test.

```bash
curl -s -G "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/billable-usage" \
  -H "Authorization: Bearer $CF_TOKEN" \
  -d 'from=2026-08-01T00:00:00Z' \
  -d 'to=2026-09-01T00:00:00Z' | jq '.result[0:3]'
```

Each row represents one product over one charge period:

```json
[
  {
    "ServiceName": "Workers",
    "ServiceFamilyName": "Developer Platform",
    "ChargePeriodStart": "2026-08-01T00:00:00Z",
    "ChargePeriodEnd": "2026-08-02T00:00:00Z",
    "ChargeDescription": "Workers Standard requests",
    "ConsumedQuantity": 41820000,
    "ConsumedUnit": "requests",
    "PricingQuantity": 31820000,
    "PricingUnit": "million requests",
    "ListCost": 9.55,
    "ContractedCost": 9.55,
    "BilledCost": 9.55,
    "EffectiveCost": 9.55,
    "BillingCurrency": "USD",
    "SubscriptionId": "ff2af59d0c9b4b1a9c9c4a...",
    "ZoneId": null,
    "ZoneName": null
  }
]
```

**What to check before moving on:**

| Field                                   | What good looks like                                                                                                                    |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Row count                               | More than zero. An empty `result` array on a `covered: true` account usually means no metered charges in the window, so widen the range |
| `ServiceName` spread                    | Should list the products you actually pay for, such as Workers, R2, D1, Images, Stream, and Zero Trust                                  |
| `BilledCost`                            | Non-zero, and summing close to your invoice for that month. Small differences are normal until a period closes                          |
| `PricingQuantity` vs `ConsumedQuantity` | These differ where a free allowance applies. `PricingQuantity` is post-allowance and is what you are charged on                         |
| `ListCost` vs `BilledCost`              | A gap means a discount or credit was applied. Both are ingested so the difference stays visible                                         |
| `ZoneId` / `ZoneName`                   | Populated on zone-scoped charges such as domain plans, and `null` on account-level products like Workers. Both are expected             |
| `BillingCurrency`                       | Matches your invoice currency                                                                                                           |

Sanity-check the total against your invoice:

```bash
curl -s -G "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/billable-usage" \
  -H "Authorization: Bearer $CF_TOKEN" \
  -d 'from=2026-08-01T00:00:00Z' \
  -d 'to=2026-09-01T00:00:00Z' \
  | jq '[.result[].BilledCost] | add'
```

{% hint style="warning" %}
**Fixed plan fees are not in here.** These endpoints return usage-based charges. Your flat monthly fees, meaning Pro or Business plans and per-zone add-ons like Bot Management, are not included. This total will read lower than your invoice by the sum of those fees. That is expected, not a bug, and step 5 covers how to represent them.
{% endhint %}
{% endstep %}

{% step %}

## Connect to OneLens

Provide the following, either through the OneLens dashboard or by emailing <support@astuto.ai>.

| Field                 | Value                                                 | Example                            |
| --------------------- | ----------------------------------------------------- | ---------------------------------- |
| API Token             | The token from step 1. Share securely, see note below | `Xy7...`                           |
| Cloudflare Account ID | The 32-character ID from the dashboard URL            | `023e105f4ecef8ad9ca31a8372d0c353` |
| Account label         | **Optional.** A friendlier name than the raw ID       | `acme-production`                  |

{% hint style="warning" %}
**Share the token securely.** Never send an API token over email or chat. Use a validated secure sharing tool such as [Password.link](https://password.link/en).
{% endhint %}

**Verification.** Once OneLens confirms the connection, typically within 24 hours, check the OneLens dashboard for:

* Cloudflare appearing as a cost source with a non-zero total for the last closed month
* A per-product breakdown listing the products you saw in step 4
* A total that matches your invoice once the flat fees are added

If you are connecting more than one account, repeat these five steps for each, then confirm all of them appear as separate sources in OneLens.
{% endstep %}
{% endstepper %}

## Data Refresh Schedule

* **Billable usage** is pulled once daily. Cloudflare updates billing data daily, so polling more often returns the same numbers.
* **Coverage check** re-runs weekly. This is how OneLens notices if the account moves onto an Enterprise contract, at which point cost ingestion will stop returning data and we will tell you rather than silently reporting zero.
* **New accounts** are added when you send us a token for them. OneLens holds no permission to list your accounts and its token cannot reach beyond the one that owns it, so it cannot discover them on its own.

Current-period figures shift until the billing period closes. Cloudflare also issues corrections against closed periods, so OneLens re-reads the previous period for several days after close and restates if a correction lands.

## Data Privacy & Security

* **Cost data only.** No analytics permission is on the token, so traffic, performance, and usage telemetry are unreachable by design rather than by policy.
* **One read scope.** `Billing → Read`, and nothing else. No analytics, no account settings, no zone permissions, no logs.
* **Scoped to one account.** An account-owned token cannot reach any account other than the one that owns it.
* **API-only.** No agent, no Worker deployed, no SSH, no database credentials, nothing installed in your environment.
* **No content.** No request or response bodies, no Worker source, no R2 objects, no DNS records, no logs.
* **No billing profile.** Address and card metadata are not ingested.
* **Not tied to a person.** An account-owned token is a service principal, so no employee's departure silently breaks or extends access.
* **Expiring credentials.** Set a token TTL matching your rotation policy, and OneLens alerts before expiry.
* **TLS in transit.** All calls use HTTPS/TLS 1.2+.
* **Encrypted at rest.** The token and ingested data are encrypted at rest using GCP KMS.
* **Data retention.** 12-month default, configurable. Deletion within 30 days on request, with confirmation.

## Troubleshooting

Since August 2026, Cloudflare's `403` responses include a `documentation_url` field pointing at the endpoint's reference page with its role requirements. Read that field first on any permission error, then come back to this table.

| #  | Symptom                                                        | Cause                                                                                                                                 | Fix                                                                                                                                                                                |
| -- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1  | `403` with code `9109` on any call                             | The token has Client IP Address Filtering set, and the call came from an IP outside that list                                         | Run from an allowlisted IP, or edit the token's IP filter in the dashboard. If you set a filter, make sure it includes OneLens's egress ranges as well as your own testing machine |
| 2  | `403` on `/billable-usage` but `/user/tokens/verify` succeeds  | Token is valid but missing `Billing → Read`                                                                                           | Edit the token and add the `Account → Billing → Read` row                                                                                                                          |
| 3  | `covered: false` from `/billable-usage/info`                   | The account is entirely on an Enterprise contract                                                                                     | Not fixable from either side today, since Cloudflare's usage endpoints are self-serve only. Contact <support@astuto.ai>                                                            |
| 4  | `success: true` but `result` is an empty array                 | No metered charges in the window, or the products in use are all on contract subscriptions                                            | Widen the date range to a full closed month. Cross-check **Manage Account → Billing → Billable Usage** in the dashboard                                                            |
| 5  | `403` when calling a different account with the same token     | An account-owned token is scoped to the account that owns it                                                                          | Expected. Create a separate token in that account and connect it as its own source                                                                                                 |
| 6  | You cannot find the option to create the token                 | Account-owned tokens can only be created by Super Administrators, and only from **Manage Account → API Tokens**, not **My Profile**   | Ask a Super Administrator on the account to create it                                                                                                                              |
| 7  | `429 Too Many Requests`                                        | Cloudflare's REST limit is 1,200 requests per 5 minutes per user, applied cumulatively across the dashboard, API keys, and tokens     | OneLens backs off automatically. If it persists, a script of yours or your own dashboard use is sharing the quota, since Cloudflare counts all three together                      |
| 8  | OneLens total is lower than the invoice                        | Fixed plan fees and per-zone add-ons are not usage-based and are not returned by these endpoints                                      | Expected. Send us your plan mix per step 5 so OneLens represents the flat charges alongside the metered ones                                                                       |
| 9  | Workers or R2 shows as a single line, not per script or bucket | Cloudflare bills those at product level and attributes nothing below it                                                               | Working as intended. This integration reports only what Cloudflare bills, and does not estimate a split                                                                            |
| 10 | Backfill returns less history than you asked for               | Cloudflare does not document a retention window for billable usage, and in practice the API stops returning rows past a certain depth | Not fixable from our side. OneLens persists every daily pull, so your history grows forward from the connection date regardless                                                    |
| 11 | Data stopped arriving after working fine                       | Token TTL expired, or the token was revoked                                                                                           | Check **Manage Account → API Tokens** for status. Create a replacement and send it to OneLens                                                                                      |
| 12 | Costs changed for a month that already closed                  | Cloudflare issued a correction or re-bill                                                                                             | Expected. OneLens restates the period to match                                                                                                                                     |

## Frequently Asked Questions

<details>

<summary>Can OneLens see our traffic, requests, or logs?</summary>

No, and not because of a policy commitment. The token carries exactly one permission, `Billing → Read`, which grants no access to analytics or logs. Traffic data is not reachable with this credential even if someone tried.

You can verify this yourself: open the token in **Manage Account → API Tokens** and confirm that is the only row on it.

</details>

<details>

<summary>Is Billing Read really the only permission you need?</summary>

Yes. Cloudflare describes that scope as granting "read access to billing profile, subscriptions, and access to fetch invoices and entitlements", and both calls this integration makes are covered by it.

We considered asking for `Account Settings → Read` as well, because it would let us call `GET /accounts` and discover your accounts instead of you telling us. We decided the convenience wasn't worth a permission you don't need. If a future OneLens release wants another Cloudflare permission, it will be in this document with a reason attached, and it will be your decision.

</details>

<details>

<summary>Why an account-owned token rather than a personal one?</summary>

Because a personal token is only as durable as its owner's access. User tokens act on behalf of a particular user and inherit a subset of that user's permissions, so when the person who created it changes role or leaves, the integration can break without anyone noticing until a cost report goes empty.

An account-owned token is a service principal. It belongs to the account, has its own permission set independent of any employee, and survives staff changes. Cloudflare confirms Billing is among the products that support account-owned tokens, so there is no functional trade-off here.

The one thing to know is that creating and managing them requires Super Administrator on the account.

</details>

<details>

<summary>We have several Cloudflare accounts. How does that work?</summary>

Run the five steps once per account, each producing its own token, and connect each as its own source. OneLens reports across all of them together and converts into a single currency, so you still get one consolidated Cloudflare view.

The reason it is per account rather than one token for all of them is that Cloudflare scopes an account-owned token to the account that owns it. We prefer that boundary: a token that can only read one account's bill is a smaller blast radius if it ever leaks, and it means revoking access to one account does not disturb the others.

Coverage is also decided per account, so check each one at step 3 rather than assuming they behave alike.

</details>

<details>

<summary>We're on an Enterprise contract. Can we use this integration?</summary>

Not today. Cloudflare's billable usage endpoints are self-serve only, and they expose none of what makes up an Enterprise bill: not the negotiated rate card, not the commitment, not the monthly platform fee, not discounts or credits. The API returns `covered: false` and no rows for a pure-contract account.

There is also no way to reconstruct it. Most Enterprise spend is a flat negotiated fee with no meter behind it, so no amount of other data derives it. Cloudflare has said an Enterprise equivalent is in the works, but it is not available now and we have no ship date. If you are on Enterprise, contact <support@astuto.ai> and we will tell you honestly what a manual arrangement would involve.

</details>

<details>

<summary>How do I tell which kind of Cloudflare account we have?</summary>

Fastest way, no token needed. In the dashboard go to **Manage Account → Billing → Billable Usage**. A populated daily cost chart means pay-as-you-go. An empty or ineligible page means Enterprise contract.

Programmatically, `GET /accounts/{account_id}/billable-usage/info` returns a `covered` boolean.

</details>

<details>

<summary>Why is Workers a single line instead of per script?</summary>

Because that is how Cloudflare bills it. Workers is an account-level product, and the billing record attributes the charge to the product, not to individual scripts. The same is true of R2 buckets, D1 databases, KV namespaces, and Durable Objects.

We could estimate a split from Cloudflare's analytics API, and we deliberately don't. Cloudflare's own documentation warns those datasets should not be used to measure billing usage, because they count traffic billing excludes. An estimated split also cannot be reconciled to an invoice line, which makes it dangerous the moment someone charges a team for it. Every number in this integration is one Cloudflare billed you.

</details>

<details>

<summary>Can we allocate Cloudflare cost to teams or cost centres?</summary>

At account and zone level, yes. Zone-scoped charges carry a zone ID and name, so domain-level cost is real billed cost, and you can group accounts and zones into cost centres in OneLens.

Below that, no. Cloudflare's billing data has no tag dimension. Resource Tagging exists in public beta and Cloudflare lists billing attribution among its purposes, but tags do not yet appear as a field in the billable usage response. If that changes we will pick it up. If your allocation needs to reach individual Workers or buckets, tell us during onboarding so we can be clear about what is and is not possible before you design a chargeback around it.

</details>

<details>

<summary>Can OneLens change our DNS, WAF rules, plan, or payment method?</summary>

No. The one permission on the token is `Read`, so there is no write, edit, or admin capability anywhere on it. Changing a plan or payment method needs `Billing → Write`, which we do not request. The token also carries no zone-scoped permission at all, so DNS and WAF configuration are not even readable.

</details>

<details>

<summary>Will this impact our Cloudflare performance or count against our limits?</summary>

Performance, no. These are read calls against Cloudflare's billing system, nothing in your request path.

Limits, marginally. Cloudflare's REST limit is 1,200 requests per 5 minutes, and OneLens makes two calls per day. Worth knowing: Cloudflare applies that limit cumulatively across the dashboard, API keys, and tokens, so heavy automation of your own contends with ours. If you are already close to the limit, tell us and we will stagger our pull window.

</details>

<details>

<summary>How do I rotate the token?</summary>

Create a replacement token with the same single scope, send it to OneLens securely, confirm ingestion continues on the next daily pull, then delete the old token in **Manage Account → API Tokens**. Overlapping them means no ingestion gap.

Cloudflare also supports rolling a token in place from the token list, which keeps the same token ID but issues a new secret. Either approach works, and the new secret still has to reach OneLens.

</details>

<details>

<summary>How do I disconnect OneLens?</summary>

Delete or roll the API token in **Manage Account → API Tokens**. Ingestion stops on the next attempted pull, immediately and unilaterally, so you do not need OneLens to act. Historical data already ingested remains in OneLens until you request deletion, which is completed within 30 days with confirmation.

</details>

<details>

<summary>Why is our OneLens Cloudflare total lower than our invoice?</summary>

These endpoints return usage-based charges only. Flat monthly fees are not usage-based and are not in the API, which covers Pro and Business plans and per-zone add-ons like Bot Management. Your OneLens total will read lower by the sum of those fees.

Send us your plan mix during step 5 and OneLens represents those flat charges alongside the metered ones, so the total matches your invoice.

</details>

## Need Help?

**Cloudflare official docs:**

* [Billing documentation, covering the billing lifecycle, charge types, and permissions](https://developers.cloudflare.com/billing/)
* [Monitor billable usage, the dashboard behind the API and its coverage limits](https://developers.cloudflare.com/billing/manage/billable-usage/)
* [Billing API reference, for the billable usage endpoints](https://developers.cloudflare.com/api/resources/billing/)
* [Introducing the Billable Usage API, on FOCUS alignment and coverage](https://blog.cloudflare.com/billable-usage-api/)
* [Account API tokens, including the product compatibility matrix](https://developers.cloudflare.com/fundamentals/api/get-started/account-owned-tokens/)
* [Create an API token, covering scopes, IP filtering, and TTL](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/)
* [API token permissions reference, for exact permission names](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)
* [API rate limits](https://developers.cloudflare.com/fundamentals/api/reference/limits/)
* [Resource Tagging, on tagging Cloudflare resources](https://developers.cloudflare.com/resource-tagging/)

**OneLens support:** <support@astuto.ai>


---

# 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.onelens.cloud/integrations/cloud-and-cost-sources/connecting-to-cloudflare.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.
