> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qobra.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Migration guide v1 → v2

> What moves to v2, what stays on v1, and how to migrate your reporting integration

## Do you need to migrate?

Only the **reporting** endpoints have a v2. v2 is not a new version of the
whole API — it is a reporting-focused subset.

<Info>
  If your integration does not call `GET /v1/reporting` or `GET
      /v1/reporting/{data_table_id}/records`, you have nothing to migrate.
</Info>

## Support status of every endpoint

| Endpoint                                        | Status           | Action                                                                                   |
| ----------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------- |
| `GET /v1/reporting`                             | Deprecated       | Migrate to [fetch statements records](/api_reference/v2/endpoints/data/fetch_statements) |
| `GET /v1/reporting/{data_table_id}/records`     | Deprecated       | Migrate to [fetch reporting records](/api_reference/v2/endpoints/data/fetch_records)     |
| `GET /v1/users`                                 | Maintained on v1 | Nothing to do                                                                            |
| `PUT /v1/users/bulk`                            | Maintained on v1 | Nothing to do                                                                            |
| `DELETE /v1/users/archive/bulk`                 | Maintained on v1 | Nothing to do                                                                            |
| `PUT /v1/users/groups/bulk`                     | Maintained on v1 | Nothing to do                                                                            |
| `PUT /v1/users/managers/bulk`                   | Maintained on v1 | Nothing to do                                                                            |
| `GET /v1/tables/{data_table_key}/records`       | Maintained on v1 | Nothing to do                                                                            |
| `POST /v1/tables/{data_table_key}/records/bulk` | Maintained on v1 | Nothing to do                                                                            |
| `GET /v1/imports/{import_id}`                   | Maintained on v1 | Nothing to do                                                                            |

<Info>
  The deprecated reporting endpoints are still served today and no removal date
  is announced. As with any breaking change on the Qobra API, you would be
  notified by email two months in advance. The endpoints maintained on v1 have
  no end-of-life date — there is no v2 equivalent to move to.
</Info>

## What changes on reporting

<CardGroup cols={2}>
  <Card title="Tables are addressed by ID" icon="table">
    Statements now take a `table_id`, discovered through `/v2/data-structures`
  </Card>

  <Card title="Fields are discoverable" icon="magnifying-glass">
    `/v2/data-structures/{table_id}/fields` returns the exact keys, types and
    formats of your data
  </Card>

  <Card title="ID-based pagination" icon="forward">
    `offset` is replaced by `start_id`, and the response hands you a ready-made
    `next_url`
  </Card>

  <Card title="Incremental syncs" icon="arrows-rotate">
    `last_modified_after` / `last_modified_before` let you pull only what moved
  </Card>
</CardGroup>

### Endpoint mapping

| v1                                          | v2                                        |
| ------------------------------------------- | ----------------------------------------- |
| `GET /v1/reporting`                         | `GET /v2/reporting/{table_id}/statements` |
| `GET /v1/reporting/{data_table_id}/records` | `GET /v2/reporting/{table_id}/records`    |

The v1 statements endpoint took no table in its path. In v2 both endpoints do,
so start by listing your data structures to get the `table_id` to call.

### Parameter mapping

| v1       | v2                     | Notes                                                              |
| -------- | ---------------------- | ------------------------------------------------------------------ |
| `offset` | `start_id`             | Pass the ID of the last record received, or follow `meta.next_url` |
| `limit`  | `limit`                | Unchanged in meaning, accepts 1 to 2000                            |
| —        | `last_modified_after`  | New. ISO 8601 datetime, for incremental syncs                      |
| —        | `last_modified_before` | New. ISO 8601 datetime                                             |

### Response shape

The envelope changes and the record keys are prefixed.

<CodeGroup>
  ```json v1 theme={null}
  {
    "count": 4570,
    "next": "https://api.qobra.co/v1/reporting?offset=100&limit=100",
    "data": [
      {
        "id": "6545110915808dbcc34531ef",
        "date": "2023-11-30",
        "payment": 8500.0,
        "payment_currency": "USD",
        "user": { "id": "5537a5b0...", "email": "john-doe@company.com" }
      }
    ]
  }
  ```

  ```json v2 theme={null}
  {
    "data": [
      {
        "standard.id": "65a1b2c3d4e5f6g7h8i9j0k1",
        "standard.date": "2024-01-01",
        "standard.total_commission": { "value": 8500.0, "currency": "USD" },
        "standard.user": { "id": "507f191e...", "email": "sarah@company.com" }
      }
    ],
    "meta": {
      "next_start_id": "65a1b2c3d4e5f6g7h8i9j999",
      "has_more": true,
      "next_url": "https://api.qobra.co/v2/reporting/507f.../statements?start_id=65a1b2c3d4e5f6g7h8i9j999&limit=1000"
    }
  }
  ```
</CodeGroup>

Three differences to handle in your parser:

* **Envelope**: `count` / `next` / `data` becomes `data` / `meta`. Page forward
  with `meta.next_url` and stop on `meta.has_more`.
* **Prefixed keys**: every field is namespaced by its origin — `standard.` for
  built-in fields, `custom.` for your custom metrics, `datatable.` for data
  table fields.
* **Currency amounts**: the v1 pair `<field>` + `<field>_currency` becomes a
  single object `{ "value": …, "currency": … }`.

<Warning>
  Field keys are specific to your account. Do not guess them from this page —
  read them from [the fields
  endpoint](/api_reference/v2/endpoints/discovery/get_fields_schema), which
  returns every `api_key` with its type, format, currencies and enum values.
</Warning>

## Migrate in three steps

<Steps>
  <Step title="Find your table_id">
    Call `GET /v2/data-structures`. Each entry carries its `id`, its `type`
    (`statement_reporting` or `record_reporting`) and `links` pointing at the
    endpoints to call next.
  </Step>

  <Step title="Map your fields">
    Call `GET /v2/data-structures/{table_id}/fields` and match each v1 key you
    consume to its v2 `api_key`. Store the returned `schema_hash` to detect
    later schema changes.
  </Step>

  <Step title="Switch your extraction loop">
    Replace the `offset` loop with `meta.next_url`, and unwrap currency objects
    where your v1 code read a `_currency` sibling key.
  </Step>
</Steps>

The [quickstart](/api_reference/v2/quickstart) runs these three calls end to
end, with cURL, Python and JavaScript snippets you can copy.

Your API key is unchanged — the same `X-API-Key` header authenticates both
versions, and v1 and v2 can run side by side while you test.

## Checklist

<AccordionGroup>
  <Accordion title="My ETL reads /v1/reporting with offset pagination">
    Call `/v2/data-structures` once to resolve the statement reporting
    `table_id`, then paginate with `meta.next_url` instead of incrementing
    `offset`.
  </Accordion>

  <Accordion title="My warehouse schema has <field>_currency columns">
    Those columns disappear. Read `value` and `currency` from the field's
    object instead, or flatten it back to two columns in your transformation
    layer.
  </Accordion>

  <Accordion title="I only push users, groups and managers to Qobra">
    Nothing to migrate. Those endpoints stay on v1 and are maintained.
  </Accordion>

  <Accordion title="I need to detect when fields change">
    Compare the `schema_hash` returned by the fields endpoint between two runs.
    This has no v1 equivalent.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart Guide" icon="rocket" href="/api_reference/v2/quickstart">
    Run the three v2 calls end to end in 5 minutes
  </Card>

  <Card title="Endpoints Reference" icon="code" href="/api_reference/v2/endpoints/discovery/list_data_structures">
    Every v2 parameter and response field
  </Card>
</CardGroup>

Need a hand? Reach us at [support@qobra.co](mailto:support@qobra.co) or through
the in-app chat.
