Get product offers (list)
Returns a paginated list of products with their individual offers, including per-offer price and quantity. This endpoint is the primary way to discover which products are available and at what prices, and to poll for changes — by filtering on updatedAtFrom/updatedAtTo you receive only products whose offer data changed within a given time window.
Typical use cases:
- Build or refresh a local product catalog with current pricing.
- Monitor price or availability changes by polling with a sliding
updatedAtFromwindow. - Look up offer IDs to use as
offerIdwhen placing a manual order item.
Endpoint: GET /export/v1/product-offers
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token obtained from the OAuth2 token endpoint. Format: Bearer <access_token>. See Authentication. |
Query parameters
updatedAtFrom and updatedAtTo are date-time bounds (RFC 3339 / ISO 8601 date-time), not plain calendar dates. Contrast with dateFrom / dateTo on Get orders history; see Date vs date-time filters.
| Parameter | Type | Required | Description |
|---|---|---|---|
productIds[] | array of strings | No | Filter by specific product IDs. Each value must be exactly 14 numeric digits (e.g. 10000004439009). Up to 20 IDs per request. |
updatedAtFrom | string (RFC 3339 date-time) | No | Inclusive lower bound on last offer update. Example: 2026-03-01T00:00:00Z. Must be a full date-time, not YYYY-MM-DD alone. |
updatedAtTo | string (RFC 3339 date-time) | No | Inclusive upper bound on last offer update. Example: 2026-03-31T23:59:59Z. When both bounds are set, updatedAtFrom must not be after updatedAtTo. |
page | string | No | Page number, starting at 1. Defaults to 1. Maximum: 100000. |
itemsPerPage | string | No | Number of results per page. Allowed values: 10, 20, 50, 100. Defaults to 20. |
Sandbox
curl --location 'https://sandboxapi.g2a.com/export/v1/product-offers' \
--header 'Authorization: Bearer rfC3vIi6zoVqZSHAlhTXslTfvMZYwWPZ'
Result ordering
Results are returned in insertion order — the order in which products were first added to the offers cache. This is not the same as updatedAt.
Custom sorting is not supported.
Example requests
Paginated feed — all products, page 2
GET /export/v1/product-offers?page=2&itemsPerPage=50
Poll for recently updated products
GET /export/v1/product-offers?updatedAtFrom=2026-03-01T00:00:00Z&updatedAtTo=2026-03-31T23:59:59Z
Fetch specific products by ID
GET /export/v1/product-offers?productIds[]=10000004439009&productIds[]=10000004439010
Success response (200)
{
"data": [
{
"id": "10000004439009",
"name": "Grand Theft Auto San Andreas Steam Key GLOBAL",
"totalQuantity": 156,
"minPrice": "1.49",
"updatedAt": "2026-03-20T10:00:00Z",
"currency": "EUR",
"offers": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"price": "1.49",
"quantity": 50
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"price": "1.89",
"quantity": 106
}
]
}
],
"meta": {
"page": 2,
"itemsPerPage": 20,
"totalResults": 150,
"hasNext": true,
"hasPrevious": true
}
}
Response fields
| Field | Type | Description |
|---|---|---|
data | array | List of products on the current page |
data[].id | string | Product identifier (e.g. 10000004439009) |
data[].name | string | Product name |
data[].totalQuantity | integer | Total number of available items across all offers for this product |
data[].minPrice | string (decimal) | Lowest offer price across all offers (e.g. 9.99) |
data[].updatedAt | string (ISO 8601) | UTC timestamp of the last offer update for this product |
data[].currency | string | Currency code for all prices in this product object. Always "EUR". |
data[].offers | array | Up to 3 cheapest offers for this product, sorted by price ascending |
data[].offers[].id | string (UUID) | Offer identifier — use as offerId in a manual order item |
data[].offers[].price | string (decimal) | Price per unit for this offer |
data[].offers[].quantity | integer | Number of items available from this offer |
meta.page | integer | Current page number |
meta.itemsPerPage | integer | Number of items returned per page |
meta.totalResults | integer | Total number of products matching the query |
meta.hasNext | boolean | Whether a next page exists |
meta.hasPrevious | boolean | Whether a previous page exists |
Error responses
| Status | Description | Possible error codes |
|---|---|---|
| 400 | Bad request | validation-error — one or more query parameters failed validation; see message for details |
| 401 | Unauthorized | unauthorized — missing or invalid Bearer token |
| 500 | Internal server error | internal-server-error — unexpected server-side error; contact your Key Account Manager and include the traceId from the response |
validation-error (400) — the message field identifies the specific parameter and problem. Possible causes:
productIds[]— any supplied identifier is not exactly 14 characters longproductIds[]— any supplied identifier is non-numericproductIds[]— any supplied identifier is below the minimum value (10000000000000)productIds[]— any supplied identifier is an empty stringpage— value is not a valid integer, or outside the allowed range1–100000itemsPerPage— value is not one of the allowed values:10,20,50,100updatedAtFromorupdatedAtTo— value is not a valid RFC 3339 date-time (e.g.2026-03-01T00:00:00Z)updatedAtFromis afterupdatedAtTo
Example — invalid itemsPerPage:
{
"error": {
"code": "validation-error",
"message": "invalid itemsPerPage value: 15, itemsPerPage must be one of: 10, 20, 50, 100",
"status": 400
}
}
Example — invalid date-time format:
{
"error": {
"code": "validation-error",
"message": "Validation errors: updatedAtFrom must be a valid RFC3339 date-time",
"status": 400
}
}
Example — date range conflict:
{
"error": {
"code": "validation-error",
"message": "Validation errors: updatedAtFrom cannot be greater than updatedAtTo",
"status": 400
}
}