---
title: "Exporting billing data to a bucket"
description: "Find out how to configure a daily export of your billing data — in the FOCUS format — to an S3-compatible bucket you own, using the OVHcloud API"
url: https://docs.ovhcloud.com/pt/guides/account-and-service-management/finops/export-billing-data-to-bucket
lang: pt
lastUpdated: 2026-07-21
---
# Exporting billing data to a bucket

## Objective

OVHcloud can push your billing data, converted to the **FOCUS**
 open standard, to an S31
-compatible object storage bucket that **you**
 own. Once configured, the export runs **automatically every day**
: no manual download, no portal click — your data lands in your bucket as a CSV file ready for your FinOps tooling.
**This guide shows you how to create, track, update and remove that export configuration through the OVHcloud API.**

:::info
This page covers the **bucket export configuration** only. It does not cover reading the exported columns or the FOCUS standard itself.
:::

## Requirements

- An active OVHcloud account with billing data.
- A **valid OVHcloud API authentication token** with permission to call the `/finops` routes. If needed, see [First Steps with the OVHcloud APIs](/pt/guides/manage-and-operate/api/first-steps.md) to create one. All requests below must be authenticated; the examples show the token as `$OVH_API_TOKEN`.
- An **S3-compatible bucket** you can write to, and a pair of credentials for it:
  - an **access key** and a **secret key**,
  - the bucket **endpoint host** (a host name **without** a `http://` / `https://` / `s3://` scheme, e.g. `s3.gra.io.cloud.ovh.net`) and its **region**.

:::warning
Connections to your bucket always use **HTTPS** — do not prefix the endpoint with a scheme. See the [Frequent errors](#frequent-errors) section.
:::

:::info
The export works with any S3-compatible bucket — it does not have to be OVHcloud Object Storage. You provide the endpoint, region and credentials; OVHcloud writes to it.
:::

## How the export works

The configuration is a **declarative resource**. You describe the _target_ you want (your bucket, the daily hour, the file policy) and OVHcloud reconciles toward it:

1. You **create** the configuration with the bucket details (`POST`).
2. OVHcloud **validates** it by actually connecting to your bucket and checking it is reachable with the credentials you gave.
3. When validation succeeds, the resource becomes **`READY`**; if OVHcloud cannot reach your bucket, it becomes **`ERROR`**.
4. Every day, at the **hour you chose**, OVHcloud regenerates your data for the current month and uploads the file to your bucket.

Because validation involves a real connection test, OVHcloud handles creation and updates **asynchronously**: the API answers immediately with a status of `CREATING` (or `UPDATING`), and you **poll** the resource until it reaches `READY`.

All examples use the OVHcloud European API endpoint `https://eu.api.ovh.com/v2`. If your account is hosted in another region, use your regional API endpoint instead (for example `https://ca.api.ovh.com/v2` for Canada).

## Step 1 — Create the export configuration

Send a `POST` to `/finops/bucketExport` with your target specification.


🇪🇺EU▾

[POST/finops/bucketExport](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#post-/finops/bucketExport)

:::tip
**Prefer a graphical interface?** The API console above builds and signs the request for you — the `curl` examples below show the equivalent raw call.
:::

```bash
curl -X POST "https://eu.api.ovh.com/v2/finops/bucketExport" \
  -H "Authorization: Bearer $OVH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "targetSpec": {
      "exportHour": 6,
      "filePolicy": "CREATE",
      "bucketConfiguration": {
        "accessKey": "MY_ACCESS_KEY",
        "secretKey": "MY_SECRET_KEY",
        "bucketName": "my-finops-export",
        "endpointURL": "s3.gra.io.cloud.ovh.net",
        "region": "gra",
        "pathPrefix": "./"
      }
    }
  }'
```

:::info
The `endpointURL` and `region` above use OVHcloud Object Storage values as an example. Replace them with the endpoint host (no scheme) and region of your own S3-compatible provider.
:::

### `targetSpec` fields

| Field                             | Required | Description                                                                                                                                                                                            |
| --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `exportHour`                      | **Yes**  | Hour of the day, `0`–`23` (UTC), when the daily export runs.                                                                                                                                           |
| `filePolicy`                      | No       | `CREATE` (default) keeps one file per day; `REPLACE` keeps a single file per month, overwritten on each run. See [File layout](#file-layout-in-your-bucket).                                           |
| `bucketConfiguration.accessKey`   | **Yes**  | Access key for your bucket.                                                                                                                                                                            |
| `bucketConfiguration.secretKey`   | **Yes**  | Secret key for your bucket.                                                                                                                                                                            |
| `bucketConfiguration.bucketName`  | No       | Target bucket name.                                                                                                                                                                                    |
| `bucketConfiguration.endpointURL` | No       | Your bucket's endpoint **host only**, without any scheme (e.g. `s3.gra.io.cloud.ovh.net`, **not** `https://s3.gra.io.cloud.ovh.net` nor `s3://s3.gra.io.cloud.ovh.net`). Connections always use HTTPS. |
| `bucketConfiguration.region`      | No       | Region / location code of your bucket.                                                                                                                                                                 |
| `bucketConfiguration.pathPrefix`  | No       | Prefix prepended to every object key written. Use `"./"` to write at the bucket root (recommended).                                                                                                    |

:::warning
Your **secret key is write-only**: OVHcloud encrypts it on receipt and **never returns** it. In every response the `secretKey` field is masked as `"***"`, whereas OVHcloud returns the access key in clear.
:::

### The response

The API answers `201 Created` with the resource. Note the `id` (you will use it to track and manage the configuration) and the `resourceStatus`, which starts at `CREATING`:

```json
{
  "id": "f556df9c-a52e-4bc1-8895-e3589cbba0be",
  "resourceStatus": "CREATING",
  "checksum": "9b2c5d6e0f1a2b3c4d5e6f7a8b9c0d1e",
  "targetSpec": {
    "exportHour": 6,
    "filePolicy": "CREATE",
    "bucketConfiguration": {
      "accessKey": "MY_ACCESS_KEY",
      "secretKey": "***",
      "bucketName": "my-finops-export",
      "endpointURL": "s3.gra.io.cloud.ovh.net",
      "region": "gra",
      "pathPrefix": "./"
    }
  },
  "currentState": { "...": "same shape as targetSpec" },
  "currentTasks": [
    {
      "id": "5a1b...",
      "type": "CREATE_BUCKET_EXPORT",
      "status": "PENDING",
      "link": "/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be"
    }
  ]
}
```

## Step 2 — Follow the provisioning until it is ready

Creation is asynchronous. Poll the resource by its `id` until `resourceStatus` is no longer `CREATING`:


🇪🇺EU▾

[GET/finops/bucketExport/{id}](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#get-/finops/bucketExport/-id-)

```bash
curl "https://eu.api.ovh.com/v2/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be" \
  -H "Authorization: Bearer $OVH_API_TOKEN"
```

- **`READY`** — OVHcloud reached your bucket and the configuration is live. The next daily run will upload your data.
- **`ERROR`** — validation failed (most often OVHcloud could not reach your bucket with the credentials you provided). See the [Frequent errors](#frequent-errors) section.

### Inspecting the provisioning detail

Two read-only sub-resources let you see exactly what happened.

List the tasks (the units of work OVHcloud ran, including finished ones):


🇪🇺EU▾

[GET/finops/bucketExport/{id}/task](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#get-/finops/bucketExport/-id-/task)

```bash
curl "https://eu.api.ovh.com/v2/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be/task" \
  -H "Authorization: Bearer $OVH_API_TOKEN"
```

List the lifecycle events (a human-readable timeline):


🇪🇺EU▾

[GET/finops/bucketExport/{id}/event](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#get-/finops/bucketExport/-id-/event)

```bash
curl "https://eu.api.ovh.com/v2/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be/event" \
  -H "Authorization: Bearer $OVH_API_TOKEN"
```

A task carries an `errors` array; when a connection test fails, its message tells you why.

## Step 3 — Retrieve your exported files

Once the configuration is `READY`, OVHcloud uploads a CSV file to your bucket **once a day, at the `exportHour` you set (UTC)**.

- **Content**: your billing data converted to the **FOCUS 1.3** standard, as CSV.
- **Window**: each run covers the **current calendar month up to that moment** (from the 1st of the month to now). The file therefore grows through the month as OVHcloud ingests new billing data.

### File layout in your bucket [](#)
The object key depends on your `filePolicy`:

| `filePolicy`       | Object key                                              | Behaviour                                                            |
| ------------------ | ------------------------------------------------------- | -------------------------------------------------------------------- |
| `CREATE` (default) | `[<pathPrefix>/]<nichandle>/<YYYY>/<MM>/<DD>/focus.csv` | A **new dated file each day**; OVHcloud keeps previous days.         |
| `REPLACE`          | `[<pathPrefix>/]<nichandle>/<YYYY>/<MM>/focus.csv`      | A **single file per month**, which OVHcloud overwrites on every run. |

A `pathPrefix` of `"./"` writes at the **bucket root** (no extra folder). For example, with `pathPrefix: "./"` and the default `CREATE` policy, your data for 15 June 2026 lands at:

```text
<your-nichandle>/2026/06/15/focus.csv
```

## Managing an existing configuration

### Update it [](#)
Send a `PUT` to `/finops/bucketExport/{id}` with the **complete** `targetSpec` you want (the new spec fully replaces the previous one). As with creation, OVHcloud validates the update asynchronously: the response comes back as `UPDATING`, and you poll until `READY`.


🇪🇺EU▾

[PUT/finops/bucketExport/{id}](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#put-/finops/bucketExport/-id-)

```bash
curl -X PUT "https://eu.api.ovh.com/v2/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be" \
  -H "Authorization: Bearer $OVH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "targetSpec": {
      "exportHour": 8,
      "filePolicy": "CREATE",
      "bucketConfiguration": {
        "accessKey": "MY_ACCESS_KEY",
        "secretKey": "MY_SECRET_KEY",
        "bucketName": "my-finops-export",
        "endpointURL": "s3.gra.io.cloud.ovh.net",
        "region": "gra",
        "pathPrefix": "./"
      }
    }
  }'
```

:::info
While OVHcloud validates an update, the response keeps your **previous** configuration in `currentState` and shows the **requested** configuration in `targetSpec`. OVHcloud does not change your live export until the new configuration reaches `READY`. If validation fails, the resource goes to `ERROR` and the previous configuration remains in effect.
:::

### List your configurations


🇪🇺EU▾

[GET/finops/bucketExport](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#get-/finops/bucketExport)

```bash
curl "https://eu.api.ovh.com/v2/finops/bucketExport" \
  -H "Authorization: Bearer $OVH_API_TOKEN"
```

The list is paginated. When more results are available, the response carries an `X-Pagination-Cursor-Next` header; pass it back as the `X-Pagination-Cursor` header to fetch the next page.

### Delete it


🇪🇺EU▾

[DELETE/finops/bucketExport/{id}](https://api.eu.ovhcloud.com/console/?section=/finops&branch=v2#delete-/finops/bucketExport/-id-)

```bash
curl -X DELETE "https://eu.api.ovh.com/v2/finops/bucketExport/f556df9c-a52e-4bc1-8895-e3589cbba0be" \
  -H "Authorization: Bearer $OVH_API_TOKEN"
```

Deletion stops the daily export. OVHcloud does **not** remove the files already written to your bucket.

## Reference: resource status values

| Status     | Meaning                                                                |
| ---------- | ---------------------------------------------------------------------- |
| `CREATING` | OVHcloud accepted the configuration and is validating it.              |
| `UPDATING` | OVHcloud accepted an update and is validating it.                      |
| `READY`    | The configuration is valid and live; daily exports run.                |
| `ERROR`    | The last create or update failed validation (e.g. bucket unreachable). |
| `DELETING` | OVHcloud is removing the configuration.                                |

## Frequent errors [](#)
Most failures show up as a resource stuck in **`ERROR`** after create or update, because OVHcloud validates the configuration by actually connecting to your bucket. Always start by reading the task `errors` (Step 2) — the message names the cause. The most common ones:

| Symptom                                                                        | Likely cause                                                                                                                                                                                      | How to fix                                                                                                                                                                       |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Status goes to `ERROR` right after create/update                               | **A scheme in `endpointURL`** — the value contains `http://`, `https://` or `s3://`. The endpoint must be a **bare host** (e.g. `s3.gra.io.cloud.ovh.net`); any scheme makes the connection fail. | Remove the scheme and keep the host only. Connections always use HTTPS.                                                                                                          |
| Status goes to `ERROR`, message mentions access denied / signature / forbidden | **Wrong or insufficient credentials** — the access key or secret key is incorrect, or the credentials lack write access to the bucket.                                                            | Re-check the **access key** and **secret key**, and confirm they can write to the bucket. OVHcloud never echoes the secret key back, so re-send it in full when you `PUT` a fix. |
| Status goes to `ERROR`, message mentions the bucket                            | **Wrong `bucketName` or `region`**, or the bucket does not exist / is not reachable.                                                                                                              | Verify the bucket name and region, and that the bucket exists for those credentials.                                                                                             |
| `404 Not Found` on a configuration `id`                                        | The configuration does not exist, or it belongs to another account.                                                                                                                               | Confirm the `id` and that you authenticate with the account that owns it.                                                                                                        |
| No file appears in the bucket                                                  | The daily run has not happened yet, or the status is not `READY`.                                                                                                                                 | The export runs once a day at `exportHour` (UTC); confirm the resource is `READY` and wait for the next run.                                                                     |
| `400 Bad Request` on create/update                                             | A required field is missing (`accessKey`, `secretKey`) or the body has no `targetSpec`.                                                                                                           | Send a complete `targetSpec`, including the bucket credentials.                                                                                                                  |

:::info
After fixing a configuration in `ERROR`, send a corrected `PUT` (see [Update it](#update-it)) and poll again until it reaches `READY`. The previous configuration stays in effect until OVHcloud validates the new one.
:::

## Go further

The exported file follows the [FOCUS 1.3 CSV standard](https://focus.finops.org) — refer to the official FOCUS specification to interpret each column.

Join our [Discord community](https://discord.gg/ovhcloud) to ask questions and share feedback.

1
: S3 is a trademark of Amazon Technologies, Inc. OVHcloud's service is not sponsored by, endorsed by, or otherwise affiliated with Amazon Technologies, Inc.