The `submit_delivery_report` endpoint generates a report from impression and request data. These reports are aggregated into discrete buckets of time, and are grouped by a subset of their fields called dimensions. Data from fired impressions, alongside requests made to the exchange server and requests that the exchange server makes, are collated to create the reports returned by this endpoint.

The body of this request is broken up into roughly four conceptual parts, made up of six top level fields.

## Time Range fields

These include `start_date`, `end_date`, and `time_group`. The start and end dates, which take the format `%Y-%m-%d %H:%M:%S` determine the start and end of the time range the report will be generated for. `time_group` represents how the report should partition the time.

For example: a `start_date` of "2023-09-20 05:00:00", an `end_date` of "2023-09-22 05:00:00", and a `time_group` of `hour` will return 48 sets of values for the metrics and dimensions requested. But if the `time_group` is changed to `day`, only 2 collections will be returned.

## Dimensions

Represented by the `dimensions` key, Dimensions are any field on the report which, when taken together, identify the data that [metrics](https://dev.kevel.com/reference/submit_delivery_report#metrics) should be aggregated over. For (an incomplete) example, if the supply_id, placement_id, domain, and country_code are all shared between two reports, the [metrics](https://dev.kevel.com/reference/submit_delivery_report#metrics) from those reports will be aggregated together.

The list of dimensions passed in through the `dimensions` key represents which of the previously described dimensions to include in the returned report(s).

## Metrics

Metrics are data aggregated across multiple chunks of reporting data for a given time period and set of matching dimensions. Some examples of metrics over the given time period, and matching dimensions include:

- number of outbound bid requests
- number of outbound bid responses
- number of inbound bid requests
- number of impressions
- avg bid price
- revenue

These metrics are aggregated differently depending on their type. {outbound | inbound} bid {requests| responses}, and impressions are simple sums; avg bid price is an average taken across the queried time period; revenue is the aggregation of impressions multiplied by their bid prices.

The `metrics` field in this request is a list of which of these Metrics to include in the generated report(s).

## Filters

Filters apply _positively_, meaning that any report which matches an expression _WILL BE INCLUDED_.

The `filters` field is an optional, user-defined query that determines which data to include in the report and to aggregate over. The value of `filters` deserves some special attention.

At the top level, `filters` is an array of similarly structured query objects which represent conditions. A simple example of a query object might be:

```json
{
  "domain": {
      "in": [
          "example.com",
          "kevel.com"
      ]
  }
}
```

Since reports which positively match the given filters are included, this filter will cause the report which has domains equal to either "example.com" or "kevel.com" to be included. In this example, `domain` could have been any Dimension. The value corresponding to this is always going to be in the form `{operation: value(s)}`. The `operation`s all compare the value of the dimension in the report to literal(s) given in `value(s)`. The operations include:

- "eq": equal to (takes a single literal)
- "lt": less than (takes a single literal)
- "gt": greater than (takes a single literal)
- "lte": less than or equal to (takes a single literal)
- "gte": greater than or equal to (takes a single literal)
- "in": contained within a list of literals (takes a list of literals)

These `operation: value` pairs can also be combined. The desired `{dimension: {domain: value(s)}}` objects can be wrapped in the logical operators "or" and "and". These top-level keys take, as values, a list of query objects. In the case of "or", if any of the queries match, the data will be included; in the case of "and", they all must match. Right now, "or" is much more useful, since "and" is the default behavior of having multiple `{domain: value}` pairs.

An example of using these logical operators might look like:

```json
{
    "or": [
        {
            "country_code": {
                "in": [
                    1,
                    44,
                    351,
                    852
                ]
            }
        },
        {
            "domain": {
                "in": [
                    "example.com",
                    "kevel.com"
                ]
            }
        }
    ]
}
```

### Required Fields

- Org ID
- `supply_id` (string, required)
- Reporting query to run
- `dimensions` (array of objects, required)
- `end_date` (date-time, required)
- `filters` (array of objects, required)
- `metrics` (array of objects, required)
- `start_date` (date-time, required)
- `time_group` (string, enum, required with allowed values: `hour`, `day`, `week`, `month`, `total`)

### Example API Request

```bash
curl --request POST \
     --url https://api.relay.bid/m/v1/report \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '{

"filters": [
    {
      "or": [
        {
          "country_code": {
            "in": [
              1,
              44,
              351,
              852
            ]
          }
        },
        {
          "domain": {
            "in": [
              "example.com",
              "kevel.com"
            ]
          }
        }
      ]
    }
  ],

"time_group": "hour"
}
'
```

### Example API Response

```json
{
  "records": [
    {
      "bidder": "string",
      "date": "2026-07-18T00:28:17.925Z",
      "domain": "string",
      "impressions": 0,
      "inbound_bid_requests": 0,
      "outbound_bid_requests": 0,
      "outbound_bid_responses": 0,
      "revenue": 0
    }
  ]
}
```
