Developers

The Andalu partner API

Every Andalu offer with its all-in buyer price, your tracked link and the rules a buyer can buy it under. Version 2.0.0. Prices include every fee, and stock has two states, never a count.

Quickstart

Five commands, copy and paste. They run against the sandbox with your test key.

  1. 1. Put your test key in a variable

    Create an andalu_test_ key in your partner hub. It is shown once.

    export ANDALU_KEY="andalu_test_your_key_here"
  2. 2. Read the vocabulary and your limits

    Every platform, region, currency and profile code, plus your key's limits.

    curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/meta"
  3. 3. List offers

    The first page of every offer, all-in prices in EUR. Add currency=USD or kind=esim to narrow it.

    curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?limit=5"
  4. 4. Page with the cursor

    Pass meta.nextCursor back as after until hasNextPage is false.

    curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?limit=500&after=<meta.nextCursor>"
  5. 5. Sync only what changed

    Send the time of your last sync. G2A's own parameter name, so an existing sync job can keep it.

    curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?updatedAtFrom=2026-10-02T06:00:00Z"

The whole API as a file: openapi.json, openapi.yaml and a Postman collection.

Keys and sandbox

Send your key as X-Api-Key, or as Authorization: Bearer with the same key. Keys come from your partner hub and are shown once.

andalu_test_...
A test key. Real offers and prices, with sandbox: true in every answer and an Andalu-Sandbox header. Nothing a sandbox click or order does is paid.
andalu_live_...
A live key. It answers not_open until the program opens, then works the same as a test key, for real.
Scopes
offers (offers and meta), stats (your numbers) and feed (the snapshot, for approved comparison sites).
IP allowlist
Optional, per key, set in your hub. A call from any other address answers ip_not_allowed.
Rotation
Two live keys can be active at once: roll out the new one, then revoke the old one.

Endpoints

Base URL: https://andalu.com/api/partner/v2

GET /offers

List offers

Every offer matching the filters, paged. A full sync pages in the default order (listed); a change sync sends updatedAtFrom with the time of your last sync. Costs one request of your quota. Needs a key with the offers scope.

page (query)
1-based page number. Do not send with after.
limit (query)
Offers per page, at most 500.
after (query)
The nextCursor of the previous page. Stable when offers are added. Do not send with page.
kind (query)
Only game keys, or only eSIM plans.
platform (query)
A platform code from GET /meta (case-insensitive).
region (query)
A region code from GET /meta, or an eSIM destination or country code (case-insensitive).
currency (query)
The currency every price is stated in.
inStock (query)
Only offers that can be bought now (true) or that cannot (false).
updatedAtFrom (query)
Only offers changed at or after this time (ISO 8601). Use it to sync changes.
sort (query)
listed: first listed first, then sku (the stable order for full syncs). updatedAt_desc: most recently changed first.
profile (query)
Shape each offer for an importer you already run: allkeyshop, kinguin or g2a. Omit for the full v2 offer.

Answers: 200 A page of offers. With profile, each offer is in that profile's shape. 400 A query parameter is not valid. 401 No valid key. 403 The key is valid but may not do this. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 Briefly unavailable. Retry with backoff.

{
  "data": [
    {
      "sku": "KSV-MWDDYETFMD",
      "kind": "game",
      "name": "Real Heroes: Firefighter HD (PC) Steam Key GLOBAL",
      "productName": "Real Heroes: Firefighter HD",
      "slug": "real-heroes-firefighter-hd-steam-global",
      "platform": "STEAM",
      "region": "GLOBAL",
      "edition": "Standard",
      "isAddOn": false,
      "image": "https://andalu.com/img/cover/real-heroes-firefighter-hd.jpg",
      "url": "https://andalu.com/go/MAYA10/KSV-MWDDYETFMD",
      "currency": "EUR",
      "price": 4.49,
      "priceMinor": 449,
      "priceStatus": "available",
      "feesIncluded": true,
      "prices": {
        "card": {
          "currency": "EUR",
          "price": 4.49,
          "priceMinor": 449
        },
        "ideal": {
          "currency": "EUR",
          "price": 4.12,
          "priceMinor": 412
        }
      },
      "rails": [
        {
          "id": "card",
          "name": "Credit / Debit Card",
          "currency": "EUR",
          "price": 4.49,
          "priceMinor": 449
        },
        {
          "id": "ideal",
          "name": "iDEAL",
          "currency": "EUR",
          "price": 4.12,
          "priceMinor": 412
        }
      ],
      "voucher": null,
      "stock": "in_stock",
      "inStock": true,
      "updatedAt": "2026-10-02T07:00:00.000Z",
      "priceValidUntil": "2026-10-03",
      "purchaseRules": {
        "maxPerOrder": 10,
        "minOrderEur": 2,
        "activationRegions": null,
        "platform": "STEAM",
        "deviceRequirement": null,
        "deliveryMethod": "email",
        "returnable": false
      }
    },
    {
      "sku": "esim-JP_3_30",
      "kind": "esim",
      "name": "Japan eSIM 3 GB 30 Days - Prepaid Travel Data",
      "productName": "Japan eSIM",
      "slug": "japan",
      "platform": "ESIM",
      "region": "JP",
      "edition": null,
      "isAddOn": false,
      "image": "https://andalu.com/esim/japan/opengraph-image",
      "url": "https://andalu.com/go/MAYA10/esim-JP_3_30",
      "currency": "EUR",
      "price": 6.9,
      "priceMinor": 690,
      "priceStatus": "available",
      "feesIncluded": true,
      "prices": {
        "card": {
          "currency": "EUR",
          "price": 6.9,
          "priceMinor": 690
        }
      },
      "rails": [
        {
          "id": "card",
          "name": "Credit / Debit Card",
          "currency": "EUR",
          "price": 6.9,
          "priceMinor": 690
        }
      ],
      "voucher": null,
      "stock": "in_stock",
      "inStock": true,
      "updatedAt": "2026-10-02T07:00:00.000Z",
      "priceValidUntil": "2026-10-03",
      "purchaseRules": {
        "maxPerOrder": 10,
        "minOrderEur": null,
        "activationRegions": null,
        "platform": null,
        "deviceRequirement": "esim_unlocked_phone",
        "deliveryMethod": "email",
        "returnable": false
      },
      "destination": "Japan",
      "country": "JP",
      "regionCodes": [
        "JP"
      ],
      "dataGb": 3,
      "dataType": "total",
      "days": 30
    }
  ],
  "meta": {
    "totalResults": 2,
    "page": 1,
    "limit": 100,
    "nextCursor": null,
    "hasNextPage": false
  },
  "sandbox": true
}

GET /offers/{sku}

Get one offer

One offer by sku. Costs one request of your quota. Needs a key with the offers scope.

sku (path)
The offer sku.
currency (query)
The currency every price is stated in.
profile (query)
Shape each offer for an importer you already run: allkeyshop, kinguin or g2a. Omit for the full v2 offer.

Answers: 200 The offer. 400 A query parameter is not valid. 401 No valid key. 403 The key is valid but may not do this. 404 Not found. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 Briefly unavailable. Retry with backoff.

{
  "data": {
    "sku": "KSV-MWDDYETFMD",
    "kind": "game",
    "name": "Real Heroes: Firefighter HD (PC) Steam Key GLOBAL",
    "productName": "Real Heroes: Firefighter HD",
    "slug": "real-heroes-firefighter-hd-steam-global",
    "platform": "STEAM",
    "region": "GLOBAL",
    "edition": "Standard",
    "isAddOn": false,
    "image": "https://andalu.com/img/cover/real-heroes-firefighter-hd.jpg",
    "url": "https://andalu.com/go/MAYA10/KSV-MWDDYETFMD",
    "currency": "EUR",
    "price": 4.49,
    "priceMinor": 449,
    "priceStatus": "available",
    "feesIncluded": true,
    "prices": {
      "card": {
        "currency": "EUR",
        "price": 4.49,
        "priceMinor": 449
      },
      "ideal": {
        "currency": "EUR",
        "price": 4.12,
        "priceMinor": 412
      }
    },
    "rails": [
      {
        "id": "card",
        "name": "Credit / Debit Card",
        "currency": "EUR",
        "price": 4.49,
        "priceMinor": 449
      },
      {
        "id": "ideal",
        "name": "iDEAL",
        "currency": "EUR",
        "price": 4.12,
        "priceMinor": 412
      }
    ],
    "voucher": null,
    "stock": "in_stock",
    "inStock": true,
    "updatedAt": "2026-10-02T07:00:00.000Z",
    "priceValidUntil": "2026-10-03",
    "purchaseRules": {
      "maxPerOrder": 10,
      "minOrderEur": 2,
      "activationRegions": null,
      "platform": "STEAM",
      "deviceRequirement": null,
      "deliveryMethod": "email",
      "returnable": false
    }
  },
  "sandbox": true
}

GET /feed.json

The snapshot as JSON

Every offer in one JSON document, rebuilt hourly, EUR, with your tracked links. Needs the feed scope (approved comparison sites). Send If-None-Match with the last ETag: an unchanged snapshot answers 304 and costs nothing. A full download counts against your quota and the 12 an hour snapshot allowance. Served gzip when you send Accept-Encoding: gzip. Needs a key with the feed scope.

If-None-Match (header)
The ETag of the snapshot you hold. If it is still current the answer is 304 with no body, and costs no quota.

Answers: 200 The snapshot. 304 Your snapshot is current. No body, no quota. 401 No valid key. 403 The key is valid but may not do this. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 The snapshot is not built yet, or a dependency is briefly down.

{
  "version": "2.0.0",
  "currency": "EUR",
  "data": [
    {
      "sku": "KSV-MWDDYETFMD",
      "kind": "game",
      "name": "Real Heroes: Firefighter HD (PC) Steam Key GLOBAL",
      "productName": "Real Heroes: Firefighter HD",
      "slug": "real-heroes-firefighter-hd-steam-global",
      "platform": "STEAM",
      "region": "GLOBAL",
      "edition": "Standard",
      "isAddOn": false,
      "image": "https://andalu.com/img/cover/real-heroes-firefighter-hd.jpg",
      "url": "https://andalu.com/go/MAYA10/KSV-MWDDYETFMD",
      "currency": "EUR",
      "price": 4.49,
      "priceMinor": 449,
      "priceStatus": "available",
      "feesIncluded": true,
      "prices": {
        "card": {
          "currency": "EUR",
          "price": 4.49,
          "priceMinor": 449
        },
        "ideal": {
          "currency": "EUR",
          "price": 4.12,
          "priceMinor": 412
        }
      },
      "rails": [
        {
          "id": "card",
          "name": "Credit / Debit Card",
          "currency": "EUR",
          "price": 4.49,
          "priceMinor": 449
        },
        {
          "id": "ideal",
          "name": "iDEAL",
          "currency": "EUR",
          "price": 4.12,
          "priceMinor": 412
        }
      ],
      "voucher": null,
      "stock": "in_stock",
      "inStock": true,
      "updatedAt": "2026-10-02T07:00:00.000Z",
      "priceValidUntil": "2026-10-03",
      "purchaseRules": {
        "maxPerOrder": 10,
        "minOrderEur": 2,
        "activationRegions": null,
        "platform": "STEAM",
        "deviceRequirement": null,
        "deliveryMethod": "email",
        "returnable": false
      }
    }
  ],
  "meta": {
    "totalResults": 1,
    "page": null,
    "limit": 1,
    "nextCursor": null,
    "hasNextPage": false
  },
  "updatedAt": "2026-10-02T07:00:00.000Z"
}

GET /feed.xml

The snapshot as XML

Every offer in one XML document, rebuilt hourly, EUR, with your tracked links. Needs the feed scope (approved comparison sites). Send If-None-Match with the last ETag: an unchanged snapshot answers 304 and costs nothing. A full download counts against your quota and the 12 an hour snapshot allowance. Served gzip when you send Accept-Encoding: gzip. Needs a key with the feed scope.

If-None-Match (header)
The ETag of the snapshot you hold. If it is still current the answer is 304 with no body, and costs no quota.

Answers: 200 The snapshot. 304 Your snapshot is current. No body, no quota. 401 No valid key. 403 The key is valid but may not do this. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 The snapshot is not built yet, or a dependency is briefly down.

<?xml version="1.0" encoding="UTF-8"?>
<offers version="2.0.0" currency="EUR">
<offer><sku>KSV-MWDDYETFMD</sku><kind>game</kind><name>Real Heroes: Firefighter HD (PC) Steam Key GLOBAL</name><price>4.49</price><priceMinor>449</priceMinor><inStock>true</inStock><url>https://andalu.com/go/MAYA10/KSV-MWDDYETFMD</url></offer>
<meta><totalResults>1</totalResults><updatedAt>2026-10-02T07:00:00.000Z</updatedAt></meta>
</offers>

GET /meta

The vocabulary and your limits

Every code a filter takes (platforms, regions, eSIM destinations, currencies), the sorts and profiles, and your key's limits and scopes. Costs one request of your quota. Needs a key with the offers scope.

Answers: 200 The vocabulary. 401 No valid key. 403 The key is valid but may not do this. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 Briefly unavailable. Retry with backoff.

{
  "data": {
    "version": "2.0.0",
    "kinds": [
      "game",
      "esim"
    ],
    "platforms": [
      {
        "code": "STEAM",
        "name": "Steam",
        "kind": "game"
      },
      {
        "code": "ESIM",
        "name": "eSIM",
        "kind": "esim"
      }
    ],
    "regions": [
      {
        "code": "GLOBAL",
        "name": "Global"
      }
    ],
    "esimDestinations": [
      {
        "code": "JP",
        "name": "Japan"
      }
    ],
    "currencies": [
      {
        "code": "EUR",
        "minorUnit": 2
      }
    ],
    "stockStates": [
      "in_stock",
      "out_of_stock"
    ],
    "sorts": [
      "listed",
      "updatedAt_desc"
    ],
    "profiles": [
      "allkeyshop",
      "kinguin",
      "g2a"
    ],
    "pageLimitMax": 500,
    "offerCount": 2,
    "limits": {
      "tier": "marketer",
      "perMinute": 30,
      "perDay": 5000,
      "snapshotsPerHour": 0
    },
    "scopes": [
      "offers"
    ]
  },
  "sandbox": true
}

GET /stats

Your clicks, earnings and API use

Your daily clicks (all, and valid ones), your earnings by state, and your API requests per day. Needs the stats scope. Costs one request of your quota. Needs a key with the stats scope.

from (query)
First UTC day, YYYY-MM-DD. Default: 29 days before to.
to (query)
Last UTC day, YYYY-MM-DD. Default: today. At most 400 days from from.

Answers: 200 Your numbers. 400 A query parameter is not valid. 401 No valid key. 403 The key is valid but may not do this. 429 Over a rate limit or the daily quota. Wait for Retry-After. 503 Briefly unavailable. Retry with backoff.

{
  "data": {
    "period": {
      "from": "2026-09-03",
      "to": "2026-10-02"
    },
    "clicks": [
      {
        "day": "2026-10-01",
        "clicks": 120,
        "validClicks": 97
      }
    ],
    "totals": {
      "clicks": 120,
      "validClicks": 97
    },
    "earnings": [
      {
        "state": "pending",
        "count": 3,
        "currency": "EUR",
        "amount": 1.24,
        "amountMinor": 124
      }
    ],
    "apiRequests": [
      {
        "day": "2026-10-01",
        "requests": 412
      }
    ]
  },
  "sandbox": false
}

GET /openapi.json

openapi.json

This document, as JSON. Public: no key needed.

Answers: 200 This document, as JSON.

{
  "info": {
    "title": "Andalu Partner Offer API"
  }
}

GET /openapi.yaml

openapi.yaml

This document, as YAML. Public: no key needed.

Answers: 200 This document, as YAML.

openapi: 3.1.0

GET /postman.json

postman.json

A Postman collection generated from this document. Set the apiKey variable to your test key. Public: no key needed.

Answers: 200 A Postman collection generated from this document. Set the apiKey variable to your test key.

{
  "info": {
    "title": "Andalu Partner Offer API"
  }
}

Offer fields

A game key and an eSIM plan share these fields. Every money value has price, priceMinor and currency.

sku
Our id for the offer. It never changes, whoever supplies the product. Games: the storefront variant id. eSIM plans: esim-<plan code>.
kind
What it is.
name
The full listing title: what it is, on what, for where.
productName
The product's own name.
slug
The product page slug (games) or destination slug (eSIM).
platform
Upper-case platform code, for example STEAM, XBOX, PLAYSTATION; ESIM for an eSIM plan. GET /meta lists them.
region
Upper-case region code a game key activates in (GLOBAL, EUROPE, NORTH-AMERICA); for an eSIM plan, the destination code (JP, EU-42).
edition
The edition (Standard, Deluxe Edition ...), or null for an eSIM plan.
isAddOn
True when the product needs the base game (DLC, a soundtrack).
image
The product image, served from andalu.com.
url
Your own tracked link to the product page. Send buyers here: it credits the sale to you.
currency
ISO 4217 code of every price in this offer (the currency you asked for, EUR by default).
price
The all-in buyer price, decimal. Nothing is added at checkout. Null when priceStatus is unavailable.
priceMinor
The same price in minor units. Null when priceStatus is unavailable.
priceStatus
available, or unavailable when today's exchange rates cannot be read: then every price is null rather than guessed. Try again later.
feesIncluded
Always true: payment fees are already in every price.
prices
The all-in price per payment method. A method can only be cheaper than price, never dearer. A method is absent when it is not offered for this product.
rails
The same per-method prices as a list, with the method's id and name.
voucher
Your code and the price with it, when the program gives code buyers a discount. Null otherwise.
memberPrice
The member price. Present only while Andalu membership is open. Optional.
stock
Two states only. Never a count.
inStock
True when it can be bought now (a pre-order included).
updatedAt
When the offer last changed (price input, stock, words or rules), ISO 8601 UTC.
priceValidUntil
The day the price holds until (the next UTC day), as product pages state it.
purchaseRules
The rules checkout applies, so a click never lands on something that cannot be bought.
steamAppId
The Steam app id, when the catalog records one for this exact product. Absent otherwise. Optional.

eSIM plans also carry

destination
The destination's name.
country
ISO 3166-1 alpha-2 code when the plan covers one country.
regionCodes
Every country the plan covers (ISO 3166-1 alpha-2).
dataGb
Data in GB: the whole allowance (total) or per day (daily).
dataType
total: one allowance for the whole plan. daily: a fresh allowance every day.
days
How many days the plan runs.

purchaseRules

maxPerOrder
Most units of this product in one order.
minOrderEur
The smallest order in EUR for this kind of product, or null.
activationRegions
Upper-case region codes the key activates in; null means anywhere.
platform
Upper-case platform code, or null for an eSIM plan.
deviceRequirement
A device the buyer needs, as a code: esim_unlocked_phone (an eSIM-capable phone not locked to a carrier), or null.
deliveryMethod
Always email: codes and QR codes are sent by email, never shown on a page.
returnable
Always false: a delivered digital code cannot be returned.

Paging and sync

page and limit
page counts from 1; limit is 1 to 500 (100 by default). The default order lists each offer where it was first listed, so a new offer is added at the end and earlier pages never shift.
after
Pass meta.nextCursor as after for the next page. Send page or after, not both.
meta
totalResults, page, limit, nextCursor and hasNextPage, on every list.
updatedAtFrom
Only offers changed at or after a time: price, stock, words or buying rules. Keep the time of your last sync and send it next time.
sort=updatedAt_desc
Most recently changed first.
The snapshot
GET /feed.json or /feed.xml: every offer, rebuilt hourly, EUR. Send If-None-Match with the last ETag; an unchanged snapshot answers 304 and costs nothing.

Limits

Published, and sent on every answer in the IETF RateLimit-Policy and RateLimit headers. A 429 carries Retry-After.

Marketer keys
30 requests a minute and 5000 a day (UTC). No snapshot.
Feed keys
60 requests a minute, 20000 a day, and 12 snapshot downloads an hour.
A 304
Costs nothing.
Wrong keys
Too many requests with a wrong key from one address are refused for 10 minutes.
The demo key
The key Swagger UI uses is shared by every reader, so it allows a few calls a minute per reader and reads offers and meta only.

Errors

Every error is an RFC 9457 problem document (application/problem+json). Switch on type or code, never on the text; instance is the request's id, also in the Request-Id header.

401 invalid_key

No key, a malformed key, an unknown key or a revoked one. Send a key from your hub in X-Api-Key, or as Authorization: Bearer.

403 forbidden_scope

The key lacks the scope the endpoint needs (offers, feed or stats). Use a key with that scope. The feed scope is granted to approved comparison sites.

403 ip_not_allowed

The key has an IP allowlist and the caller is not on it. Call from an allowed address, or change the allowlist in your hub.

403 partner_inactive

The partner account is paused, under review or suspended. Check your hub, or write to partners support.

403 not_open

A live key before the program opens. Use your andalu_test_ key until then. Test answers are real data with sandbox: true.

404 not_found

The sku is not in the catalog, or the path does not exist. List skus with GET /offers.

400 invalid_parameter

A query parameter has a value the endpoint does not take. The problem's parameter field names it; detail says what it takes.

429 rate_limited

Over the per-minute limit, the hourly snapshot allowance, or too many bad keys from one address. Wait for Retry-After seconds. Pace with the RateLimit header.

429 quota_exceeded

Over the daily quota (UTC day). Wait until midnight UTC, or sync from the snapshot with If-None-Match.

503 snapshot_not_ready

Your feed snapshot has not been built yet. Try again after Retry-After, or page through GET /offers meanwhile.

503 unavailable

A dependency is briefly unreachable. Retry with backoff.

Links and attribution

Every offer's url is your own tracked link (/go/<you>/<sku>). A buyer who clicks it is credited to you for 30 days, and stays linked to you for 12 months. Send buyers to that url as it is: it lands on the product page with nothing added.

Postbacks

Each time a sale is made or changes state we can send a signed server-to-server postback to your URL, with an Andalu-Signature header (t= and v1=, HMAC-SHA256 with your secret). Set the URL in your hub. How to verify a postback.

Migrating an importer

If you already import from a key marketplace, ask for its profile and map nothing, or map these fields from the full offer.

From AllKeyShop

Ask for profile=allkeyshop and each row arrives in the merchant feed shape, prices all-in with feesCard 0. There is no PayPal method, so there is no pricePaypal.

id
sku
region, edition, activationPlatform
region, edition, platform
originalPrice, price
price (no voucher)
priceCard, feesCard
prices.card.price, always 0
voucher_code, voucher_discount_value
voucher.code, price minus voucher.price
dispo
inStock (1 or 0, never a count)
url
url (your tracked link)
curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?profile=allkeyshop&limit=100"

From Kinguin

If your importer reads the Kinguin product export, ask for profile=kinguin, or map these fields from the full offer.

kinguinId, productId
sku
name
name
platform
platform
regionalLimitations
region
price
price (all-in, decimal), or priceMinor
the stock count field
inStock (we publish no count)
page, limit, item_count
page, limit, meta.totalResults
updatedAt
updatedAt
curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?profile=kinguin&limit=100"

From G2A

If your importer reads the G2A product export, ask for profile=g2a, or map these fields from the full offer.

id
sku
name, slug
name, slug
platform, region
platform, region
retail_min_price
price (the all-in buyer price)
minPrice
none: there is one buyer price
thumbnail
image
updated_at, updatedAtFrom
updatedAt, updatedAtFrom
docs, data, meta.totalResults
data, meta.totalResults
curl -s -H "X-Api-Key: $ANDALU_KEY" "https://andalu.com/api/partner/v2/offers?profile=g2a&limit=100"

From Eneba

There is no Eneba profile: its API is a cursor-paged graph. The full offer maps directly.

product.id
sku
first, after, pageInfo.endCursor
limit, after, meta.nextCursor
pageInfo.hasNextPage
meta.hasNextPage
sort UPDATED_AT_DESC
sort=updatedAt_desc
price.amount (cents)
priceMinor

Changelog

2.0.0 (2026-10-02)

  • First release of v2: /offers, /offers/{sku}, /feed.json, /feed.xml, /meta and /stats.
  • Keys are andalu_live_ and andalu_test_ keys from your partner hub, sent as X-Api-Key or Bearer.
  • Page with page and limit, or with the after cursor. Sync changes with updatedAtFrom or sort=updatedAt_desc.
  • Every price has price, priceMinor and currency. Stock has two states.
  • Import profiles: allkeyshop, kinguin and g2a.
  • Errors are RFC 9457 problem documents; rate limits use the IETF RateLimit headers.

Versioning

  • The major version is in the path (/api/partner/v2). Inside a major version we only add: new endpoints, new optional parameters, new fields and new values in lists we document as open (platforms, regions, destinations, currencies).
  • We never remove or rename a field, change a field's type or meaning, or tighten a limit inside a major version without 30 days' notice by email and in this changelog.
  • Ignore fields you do not know; that keeps your importer working through every minor release.
  • A new major version runs beside the old one for at least 6 months. The old one then answers with Deprecation and Sunset headers (RFC 9745, RFC 8594) until it is switched off, as v1 does now.

Partner guides