Create order
Creates an order with one or more products. Each item can be either auto (selected by product ID) or manual (selected by offer ID).
After order creation, the API automatically attempts payment using the payment method previously configured on the account.
Endpoint: POST /export/v1/orders
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token obtained from the OAuth2 token endpoint. Format: Bearer <access_token>. See Authentication. |
Idempotency-Key | Yes | UUID that uniquely identifies this create-order request (e.g. 550e8400-e29b-41d4-a716-446655440000). Each request must use a different key. See below for how idempotency works. |
Idempotency-Key
How idempotency works — The Idempotency-Key prevents duplicate order creation (for example after timeout/retry).
Use one key for one logical create-order operation.
When you send the same Idempotency-Key again:
| Situation | Same payload? | Result |
|---|---|---|
| First request is still being processed (or just finished and is still in the short processing cooldown window) | Yes | 409 Conflict with code idempotency-key-processing |
| First request finished and key is no longer in processing window | Yes | Request is treated as a safe retry: API returns the previously persisted result (for successful flow this is the same created order, status 200) |
| Key was already used with a different payload | No | 422 Unprocessable Entity with code idempotency-key-already-used |
So for a new order attempt always generate a new UUID key.
Example — same key sent again while first request is still processing (409 Conflict):
{
"error": {
"code": "idempotency-key-processing",
"message": "idempotency key '3912bbc1-a346-4798-9c64-a29e4292f799' is being processed",
"status": 409
}
}
Example — same key reused with different payload (422 Unprocessable Entity):
{
"error": {
"code": "idempotency-key-already-used",
"message": "idempotency key '3912bbc1-a346-4798-9c64-a29e4292f799' has been already used for different parameters",
"status": 422
}
}
Request body
| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | One order item (current limit: 1 item per request). Each item is either auto or manual. |
currency | string | No | Transaction currency for the checkout. Must be EUR. (Order history from Get orders history may show other currencies for past orders.) |
With auto, you identify the product by productId and the service automatically chooses a suitable offer (subject to constraints such as maxPrice). With manual, you identify the exact offer by offerId - use this when you want to buy a specific listing (for example from catalog or search). Both approaches require quantity and maxPrice parameters to be set.
Each order line must use only one of these strategies: the item object must contain either an auto object or a manual object, never both. Sending both in the same item is rejected with a validation error.
Order item: auto
Select by product ID - service will automatically choose a suitable offer.
{
"auto": {
"productId": "10000004439009",
"quantity": 2,
"maxPrice": "29.99"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
productId | string | Yes | Product identifier. Must be exactly 14 digits and numeric (e.g. 10000004439009). |
quantity | integer | Yes | Number of items (minimum 1) |
maxPrice | string (decimal) | Yes | Maximum price willing to pay per unit (must be > 0 and < 100000000000). Dot-separated decimal, e.g. 29.99 |
Order item: manual
Select a specific offer by ID.
{
"manual": {
"offerId": "660e8400-e29b-41d4-a716-446655440001",
"quantity": 1,
"maxPrice": "19.99"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
offerId | string (UUID) | Yes | Specific offer identifier |
quantity | integer | Yes | Number of items (minimum 1) |
maxPrice | string (decimal) | Yes | Maximum price; format as above |
Example request
{
"items": [
{
"auto": {
"productId": "10000004439009",
"quantity": 2,
"maxPrice": "29.99"
}
}
],
"currency": "EUR"
}
Sandbox
Sandbox behavior matches production. Each request must use a different Idempotency-Key (see Idempotency-Key).
For example, generate a new key with uuidgen (or any other UUID generator tool) and use the generated value in the request header.
curl --location 'https://sandboxapi.g2a.com/export/v1/orders' \
--header 'Authorization: Bearer rfC3vIi6zoVqZSHAlhTXslTfvMZYwWPZ' \
--header 'Idempotency-Key: 1751ecdf-7e1a-4963-ab25-e64fdcba5d1f' \
--header 'Content-Type: text/plain' \
--data '{
"items": [
{
"auto": {
"productId": "10000001788001",
"quantity": 1,
"maxPrice": "10.00"
}
}
],
"currency": "EUR"
}'
curl --location 'https://sandboxapi.g2a.com/export/v1/orders' \
--header 'Authorization: Bearer rfC3vIi6zoVqZSHAlhTXslTfvMZYwWPZ' \
--header 'Idempotency-Key: 1751ecdf-7e1a-4963-ab25-e64fdcba5d1f' \
--header 'Content-Type: text/plain' \
--data '{
"items": [
{
"manual": {
"offerId": "6dc3caa1-78f1-4986-82c6-07baf9f82ac0",
"quantity": 1,
"maxPrice": "21.11"
}
}
],
"currency": "EUR"
}'
Success response (201)
The data object uses the same JSON shape as each element of GET /export/v1/orders (Get orders history): status, timestamps, order-level totals (discount, totalPrice, currency), and nested transactions.
Each transaction has id, seller (id, name), and items. Each item includes product, offer, quantity, and monetary fields.
For a successful create, currency is EUR because the request must use EUR.
data.id is the numeric order id as a string (digits only), not a UUID.
{
"data": {
"id": "30000001029303",
"status": "complete",
"createdAt": "2026-04-16T12:00:00Z",
"discount": "0.00",
"totalPrice": "59.98",
"currency": "EUR",
"transactions": [
{
"id": "7d703b67-2fa4-481c-9ad7-409e85b03a1f",
"seller": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "GamesSeller"
},
"items": [
{
"id": "120023",
"product": {
"id": "10000004439009",
"name": "Grand Theft Auto San Andreas Steam Key GLOBAL"
},
"offer": {
"id": "660e8400-e29b-41d4-a716-446655440001"
},
"quantity": {
"ordered": 2,
"invoiced": 0,
"shipped": 0,
"refunded": 0
},
"price": "29.99",
"totalPrice": "59.98"
}
]
}
]
}
}
| Field | Type | Description |
|---|---|---|
data | object | Newly created order (same schema as Get orders history data[] entries). |
data.id | string | Order identifier |
data.status | string | Order status (pending, processing, complete, canceled, closed, held, pending_payment) |
data.createdAt | string | Order creation date in ISO 8601 format |
data.discount | string | Discount amount in currency |
data.totalPrice | string | Total order amount in currency |
data.currency | string | Order currency code (ISO 4217), e.g. USD, PLN, COP — all monetary strings on the row use this currency |
data.transactions | array | List of transactions in this order |
data.transactions[].id | string | Transaction identifier |
data.transactions[].seller | object | Seller for this transaction (id required; name when available) |
data.transactions[].seller.id | string | Seller identifier UUID |
data.transactions[].seller.name | string | Seller store name (may be omitted if not available) |
data.transactions[].items | array | List of items in the transaction |
data.transactions[].items[].id | string | Order item identifier |
data.transactions[].items[].product | object | Product information |
data.transactions[].items[].product.id | string | Product identifier (e.g. 10000004439009). |
data.transactions[].items[].product.name | string | Product name |
data.transactions[].items[].offer | object | Offer information |
data.transactions[].items[].offer.id | string | Offer identifier (UUID) |
data.transactions[].items[].quantity | object | Quantity information |
data.transactions[].items[].quantity.ordered | integer | Quantity ordered |
data.transactions[].items[].quantity.invoiced | integer | Quantity invoiced |
data.transactions[].items[].quantity.shipped | integer | Quantity shipped |
data.transactions[].items[].quantity.refunded | integer | Quantity refunded |
data.transactions[].items[].price | string | Unit price in currency |
data.transactions[].items[].totalPrice | string | Line total in currency |
Line items match Get orders history (data[].transactions[].items[]): product.id / product.name, offer.id, quantity.ordered / invoiced / shipped / refunded, and decimal string price / totalPrice in the order currency.
Error responses
| Status | Description | Possible error codes |
|---|---|---|
| 400 | Bad request | See 400 error codes for create order below (this endpoint does not return order-not-complete or order-expired; those apply to Get order keys). |
| 401 | Unauthorized | unauthorized |
| 402 | Payment required | insufficient-funds, payment-went-wrong, payment-not-configured, order-not-paid |
| 409 | Conflict | idempotency-key-processing (request with same idempotency key is still being processed) |
| 422 | Unprocessable entity | idempotency-key-already-used (idempotency key was already used with a different payload) |
| 500 | Internal server error | internal-server-error |
400 error codes for create order
error.code | Meaning |
|---|---|
validation-error | Request body or headers failed validation (e.g. invalid UUID for offerId, quantity below minimum, idempotency header invalid). Often includes an errors array with field paths. |
cart-validation-error | Cart or checkout validation failed (e.g. try another offerId / productId, or lower quantity). |
offer-not-available | No offer could be selected for the request — for auto items, no product/offer matched quantity and maxPrice; for manual, the chosen offer is not available. |
max-price-exceeded | After an offer is matched, its price is higher than the maxPrice you sent for that line. |
product-excluded | The product cannot be sold via this API. See Product exclusion rules. |
Product exclusion rules
product-excluded is returned when the selected product belongs to categories that are intentionally blocked for API checkout.
Common examples of excluded products:
- in-game top-ups and balance top-ups,
- game/accounts listings,
- eSIM products,
- G2A Plus subscriptions.
These exclusions are enforced by catalog policy and cannot be bypassed by changing maxPrice, quantity, offerId, or productId within the same excluded product class.
To proceed, choose a different product that is eligible for API checkout.
Example — validation error (400 Bad Request):
When request data is invalid (e.g. quantity below minimum), the response includes an errors array with details per field:
{
"error": {
"code": "validation-error",
"message": "quantity must be 1 or greater",
"status": 400,
"errors": [
{
"code": "validation-error",
"field": "body.items[0].manual.quantity",
"message": "quantity must be 1 or greater"
}
]
}
}
After a successful create, use Get order keys with the returned order.id to retrieve product keys.