# Projected billing report

`GET /v2/reports/projected-billing`

Core API v2, Reports.

Projects upcoming rebill and recycle (retry) attempts for active subscriptions in the queried period, using user-supplied approval-rate inputs (`rebillProjections` and `recycleProjections`, each a comma-separated list of 4 percentages 0..100 corresponding to Rebill/Recycle #1, #2, #3 and #4+).

**Authentication:** Send `Authorization: Bearer <token>`. To authenticate, generate a Secret API Key from your ODUS Dashboard and include it in the `Authorization` header as follows: `Authorization: Bearer <YOUR_SECRET_API_KEY>`

## Parameters

### Query parameters

- `groupBy` (string, required): Field to group results by. **Available fields:** `billingDate`, `currency`, `gatewayProfile`, `product.name` Example: `billingDate`.
- `granularity` (string): Date granularity for `groupBy` when it is a date field. Defaults to `day`. `hour` additionally requires the query to be bounded to a `createdAt` range of at most two days. Accepts `hour`, `day`, `week`, `month`, `quarter`, `year`; anything else falls back to the default.
- `secondaryGroupBy` (string): Optional second axis for pivoting (must differ from groupBy). Each row will then carry both the primary `groupBy` value and a `secondaryGroupBy` value. **Available fields:** `billingDate`, `currency`, `gatewayProfile`, `product.name`
- `secondaryGranularity` (string): Date granularity for `secondaryGroupBy` when it is a date field. Defaults to `day`.
- `measures` (string): Metrics to include in the results. Multiple measures can be specified as comma-separated values. If `measures` is not provided, all metrics specified in the config will be calculated. **Available metrics:** `rebillsCount`, `projectedRevenue`, `rebillBucket1Count`, `rebillBucket1BaseAmount`, `rebillBucket2Count`, `rebillBucket2BaseAmount`, `rebillBucket3Count`, `rebillBucket3BaseAmount`, `rebillBucketAdditionalCount`, `rebillBucketAdditionalBaseAmount`, `recycleBucket1Count`, `recycleBucket1BaseAmount`, `recycleBucket2Count`, `recycleBucket2BaseAmount`, `recycleBucket3Count`, `recycleBucket3BaseAmount`, `recycleBucketAdditionalCount`, `recycleBucketAdditionalBaseAmount` Example: `rebillsCount,projectedRevenue,rebillBucket1Count,rebillBucket1BaseAmount,rebillBucket2Count,rebillBucket2BaseAmount,rebillBucket3Count,rebillBucket3BaseAmount,rebillBucketAdditionalCount,rebillBucketAdditionalBaseAmount,recycleBucket1Count,recycleBucket1BaseAmount,recycleBucket2Count,recycleBucket2BaseAmount,recycleBucket3Count,recycleBucket3BaseAmount,recycleBucketAdditionalCount,recycleBucketAdditionalBaseAmount`.
- `withTotal` (boolean): Whether to include a rollup row aggregating every group. Pass `false` to omit it. Default `true`.
- `billingDate` (filter): Send as `billingDate[<operator>]=<value>`. Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`.
- `currency` (filter): Send as `currency[<operator>]=<value>`. Operators: `eq`, `ne`, `like`, `ilike`, `in`, `nin`.
- `gatewayProfile` (filter): Send as `gatewayProfile[<operator>]=<value>`. Operators: `eq`, `ne`, `like`, `ilike`, `in`, `nin`.
- `dueAmount` (filter): Send as `dueAmount[<operator>]=<value>`. Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`.
- `attemptType` (filter): Send as `attemptType[<operator>]=<value>`. Operators: `eq`, `ne`, `like`, `ilike`, `in`, `nin`.
- `attemptBucket` (filter): Send as `attemptBucket[<operator>]=<value>`. Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`.
- `price` (filter): Send as `price[<operator>]=<value>`. Operators: `eq`, `ne`, `like`, `ilike`, `in`, `nin`.
- `product` (filter): Send as `product[<operator>]=<value>`. Operators: `eq`, `ne`, `like`, `ilike`, `in`, `nin`.
- `recycleProjections` (string): Comma-separated list of exactly 4 approval-rate percentages (0..100) for upcoming Recycle #1, #2, #3 and #4+ attempts. Example: `25,15,10,5`. Defaults to `0,0,0,0`. Example: `25,15,10,5`.
- `rebillProjections` (string): Comma-separated list of exactly 4 approval-rate percentages (0..100) for upcoming Rebill #1, #2, #3 and #4+ attempts. Example: `45,30,20,10`. Defaults to `0,0,0,0`. Example: `45,30,20,10`.

## Responses

### `200`

OK

Type: object (ProjectedBillingReportResponseDTO).

- `data` (array of object, required)
  - `groupBy` (string, required, nullable): The value of the groupBy field (field name varies based on groupBy parameter) Example: `usd`.
  - `secondaryGroupBy` (string, nullable): The value of the secondaryGroupBy field (present only when secondaryGroupBy was supplied) Example: `2026-05-21T00:00:00.000Z`.
  - `rebillsCount` (number): Total number of upcoming rebill + recycle attempts in the bucket. Example: `128`.
  - `projectedRevenue` (number): Projected revenue across all upcoming attempts, in the merchant display currency's minor units (integer). Both rebills and recycles apply the per-attempt approval rate directly. Example: `1834200`.
  - `rebillBucket1Count` (number): Number of upcoming Rebill #1 attempts.
  - `rebillBucket1BaseAmount` (number): Total invoice amount of upcoming Rebill #1 attempts.
  - `rebillBucket2Count` (number): Number of upcoming Rebill #2 attempts.
  - `rebillBucket2BaseAmount` (number): Total invoice amount of upcoming Rebill #2 attempts.
  - `rebillBucket3Count` (number): Number of upcoming Rebill #3 attempts.
  - `rebillBucket3BaseAmount` (number): Total invoice amount of upcoming Rebill #3 attempts.
  - `rebillBucketAdditionalCount` (number): Number of upcoming Rebill #4+ (additional) attempts.
  - `rebillBucketAdditionalBaseAmount` (number): Total invoice amount of upcoming Rebill #4+ (additional) attempts.
  - `recycleBucket1Count` (number): Number of upcoming Recycle #1 attempts.
  - `recycleBucket1BaseAmount` (number): Total invoice amount of upcoming Recycle #1 attempts.
  - `recycleBucket2Count` (number): Number of upcoming Recycle #2 attempts.
  - `recycleBucket2BaseAmount` (number): Total invoice amount of upcoming Recycle #2 attempts.
  - `recycleBucket3Count` (number): Number of upcoming Recycle #3 attempts.
  - `recycleBucket3BaseAmount` (number): Total invoice amount of upcoming Recycle #3 attempts.
  - `recycleBucketAdditionalCount` (number): Number of upcoming Recycle #4+ (additional) attempts.
  - `recycleBucketAdditionalBaseAmount` (number): Total invoice amount of upcoming Recycle #4+ (additional) attempts.
- `total` (object)
  - `groupBy` (string, nullable): The value of the groupBy field (field name varies based on groupBy parameter) Example: `usd`.
  - `secondaryGroupBy` (string, nullable): The value of the secondaryGroupBy field (present only when secondaryGroupBy was supplied) Example: `2026-05-21T00:00:00.000Z`.
  - `rebillsCount` (number): Total number of upcoming rebill + recycle attempts in the bucket. Example: `128`.
  - `projectedRevenue` (number): Projected revenue across all upcoming attempts, in the merchant display currency's minor units (integer). Both rebills and recycles apply the per-attempt approval rate directly. Example: `1834200`.
  - `rebillBucket1Count` (number): Number of upcoming Rebill #1 attempts.
  - `rebillBucket1BaseAmount` (number): Total invoice amount of upcoming Rebill #1 attempts.
  - `rebillBucket2Count` (number): Number of upcoming Rebill #2 attempts.
  - `rebillBucket2BaseAmount` (number): Total invoice amount of upcoming Rebill #2 attempts.
  - `rebillBucket3Count` (number): Number of upcoming Rebill #3 attempts.
  - `rebillBucket3BaseAmount` (number): Total invoice amount of upcoming Rebill #3 attempts.
  - `rebillBucketAdditionalCount` (number): Number of upcoming Rebill #4+ (additional) attempts.
  - `rebillBucketAdditionalBaseAmount` (number): Total invoice amount of upcoming Rebill #4+ (additional) attempts.
  - `recycleBucket1Count` (number): Number of upcoming Recycle #1 attempts.
  - `recycleBucket1BaseAmount` (number): Total invoice amount of upcoming Recycle #1 attempts.
  - `recycleBucket2Count` (number): Number of upcoming Recycle #2 attempts.
  - `recycleBucket2BaseAmount` (number): Total invoice amount of upcoming Recycle #2 attempts.
  - `recycleBucket3Count` (number): Number of upcoming Recycle #3 attempts.
  - `recycleBucket3BaseAmount` (number): Total invoice amount of upcoming Recycle #3 attempts.
  - `recycleBucketAdditionalCount` (number): Number of upcoming Recycle #4+ (additional) attempts.
  - `recycleBucketAdditionalBaseAmount` (number): Total invoice amount of upcoming Recycle #4+ (additional) attempts.

### `202`

The merchant is entitled but its environment is not provisioned yet. Provisioning has been kicked off (exactly once) and is in progress; retry the request — it succeeds once the environment is ready. Returned only for identity-token (dashboard) requests bound to a merchant, not for secret-key API calls; any such endpoint can return it while provisioning is underway.

Type: object (ProvisioningInProgress).

- `status` (string, required): Signals the merchant environment is still being provisioned. One of `provisioning`.
- `merchantAccountId` (string, required): The merchant account whose environment is being provisioned. Example: `dAI3aa87ROOeupeBCjNSKCOBOisBCYjB`.

### Errors

- `400`: The request was rejected. `type` is `invalid_request_error` when the request itself is at fault — `errors` then lists every problem found, with field-attributable entries prefixed by the field’s path; or `invalid_state_error` when the request was well-formed but the resource is not in a state that allows it.
- `401`: No API key was supplied, or the key is not valid. `type` is `authentication_error`.
- `403`: The API key is valid but lacks the permission this operation requires. `type` is `permission_error`.
- `429`: Too many requests. A limit applies per operation; requests to other operations are unaffected. `type` is `rate_limit_error`. Use the `Retry-After-global` header to know when to retry.
- `500`: The request could not be completed because of an unexpected error. `type` is `api_error`.
- `503`: The request could not be served right now: the API is temporarily at capacity, or a dependency needed to authorize the request is unavailable — the auth service that verifies credentials, or the entitlement lookup behind it. `type` is `api_error`. It is raised before the operation runs, so the request had no effect, and unlike a plain 500 the condition is transient: retry with backoff.
- `504`: The request exceeded the processing time limit and was abandoned. `type` is `api_error` and `code` is `timeout` — unlike a plain 500 the request may still have taken effect, so retry with the same idempotency key rather than blindly.

Every error response has the same body: see [Errors](https://docs.odus.com/docs/guides/api-features/errors.md).

---

Generated from the Core API v2 OpenAPI document, https://api.odus.com/openapi.v2.json. Interactive page: https://docs.odus.com/docs/api/core/v2/reporting-controller-get-projected-billing-report
