Sellers API Documentation
  • 21 Minutes to read
  • PDF

Sellers API Documentation

  • PDF

Article summary

How to connect to Sellers API?

Documentation Version

0.0.3 - link to swagger doc added

0.0.4 - Cancel webhook added, webhook statuses values changed: RESERVE -> BUYING, GIVE -> BOUGHT, (new) CANCELED

0.0.5 - deliveredwebhook added

0.0.6 - removed reserve and give names

0.0.7 - webhooks documentation added

0.0.9 - offer price calculator endpoint added

0.0.9 - download and remove stock endpoint added

0.0.10 - modified part how to login using curl

0.0.11 - described where to find client_secret and client_id

0.0.12 - events description added

0.0.13 - releasedStockIdand releasedExternalStockId added to webhook with state DELIVERED , updated examples

0.0.14 - popularityBid added to webhook, updated examples

0.0.15 - added information how use merchant panel to set up webhooks

0.0.16 - information about sandbox environment

0.0.17 - updated information about changed requests limits

0.0.18 - FAQ added

0.0.19 - Information how to manage wholesale tiers added

0.0.20 - webhooks documentation updated (new endpoints)

0.0.21 - add information about uploading images

0.0.22 - webhooks version2, new functionality webhook request re-try

0.0.23 - download and remove stock endpoint removed

0.0.24 - ability to declare a text stock, added reservationId field to uploaded stock

0.0.25 - added new offer position changed webhook

0.0.26 - Sandbox login update to CAS

0.0.27 - Temporary blocking of the offer

0.0.28 - Introducing Smart Pricing Assistant and Sales Booster

0.0.29 - Maximum Price for Smart Pricing Assistant

0.0.30 - Blocking and unblocking webhooks

Sales Manager Version

0.3.0 and above

Requests limits:

  • 2000 POST/PATCH per minute

  • 4000 GET per minute

Documentation have production addresses. Before you run on production please test your integration on sandbox environment. To create sandbox account proceed with the same steps like for production. Needed links are in table below

Sandbox application is on same domain as production, so you can encounter problems with logging (sessions are stored in cookies). To solve this issue you have to clear you cookies or use other browser than you use for production environment.

Address

Production

Sandbox

Swagger documentation

https://gateway.kinguin.net/sales-manager-api/api/swagger-ui.html

https://gateway.sandbox.kinguin.net/sales-manager-api/api/swagger-ui/index.html

Gateway main domain

https://gateway.kinguin.net

https://gateway.sandbox.kinguin.net

Kinguin ID

https://id.kinguin.net

https://sandbox.kinguin.net and click “Sign In” in the top-right corner to create account

1. Requirements

  1. To get access to API you have to have an account in Kinguin. Click “Sign In” in the top-right corner of the website to create an account.

  2. Send a message to api@kinguin.io requesting access to Kinguin public API.
    Example message:

Hello,
I would like to request access to Kinguin public API for Sellers:

Environment: production or sandbox
Kinguin account email: [your-kinguin-account@email.com]
Application name: [alias name for this access]

Declared Stock: yes or no

  1. In a response you will receive your individual client ID and secret which will be need to retrieve authorization token as oAuth 2.0 client credentials flow

2. Authorization

A client credentials flow is used for oAuth 2.0 authorization. All authorized requests require passing a Bearer code.
To retrieve your bearer code you have to send a request with grant type client_credentials.

To be allow create proper request you have to have:

  • client_id which is Public ID

  • client_secret which is Secret ID.

Both values you will receive as a response for your grant access request

  1. Acquiring an access token

curl https://id.kinguin.net/auth/token \

--header 'Content-Type: application/x-www-form-urlencoded' \

-d 'grant_type=client_credentials' \

-d 'client_id=${CLIENT_ID}' \

-d 'client_secret=${CLIENT_SECRET}'

response:

{

"access_token":"MWE5NjJiNjkzNzU2NTU5ZjVhNjUzOTk3MmExOGUxMThiYWQ3YjA0NzY1MzBkNDRkMTczOWYzOWY3MzEyYjI0Nw",

"expires_in":3600, # seconds

"token_type":"bearer",

"scope":null,

}

Token has expiration time and have to be acquire again before expiration

  1. To acquire new / refresh access token (previous one has expired) repeat point 1.

3. Up Front stock upload

Bearer is needed. Take a look on Authorization for information on how to get it.

ProductId is needed. Take a look on the appendix for information on how to match a product or find productId by name or catalog_id.

Test productID: 5c9b71292539a4e8f1809707. Can be used on production environment and is available here

Price amount is in cents

To use this flow you have to create an offer and then upload Stock

Creating an offer

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"productId": "${PRODUCT_ID}", "price": {"amount": 2, "currency": "EUR"}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers

response:

{

"id":"${OFFER_ID}",

"productId":"${PRODUCT_ID}",

"name":"Testowe CD Key",

"sellerId":"xxx",

"status":"ACTIVE",

"block":null,

"priceIWTR":{

"amount":2, #cents

"currency":"EUR"

},

"declaredStock":0,

"reservedStock":0,

"availableStock":0,

"updatedAt":"2020-03-06T10:58:49.088+0000",

"createdAt":"2020-03-06T10:58:48.951+0000",

"buyableStock":0,

"wholesale":{

"name":"Default",

"enabled":true,

"tiers":[

{

"discount":0,

"level":1,

"price":{

"amount":2,

"currency":"EUR"

},

"priceIWTR":{

"amount":2,

"currency":"EUR"

}

},

{

"discount":0,

"level":2,

"price":{

"amount":2,

"currency":"EUR"

},

"priceIWTR":{

"amount":2,

"currency":"EUR"

}

},

{

"discount":0,

"level":3,

"price":{

"amount":2,

"currency":"EUR"

},

"priceIWTR":{

"amount":2,

"currency":"EUR"

}

},

{

"discount":0,

"level":4,

"price":{

"amount":2,

"currency":"EUR"

},

"priceIWTR":{

"amount":2,

"currency":"EUR"

}

}

]

}

}

Uploading stock

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"body": "cd key", "mimeType": "text/plain"}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}/stock

# to upload image send payload where body is base64 string

# '{"body": "[image-base64]", "mimeType": "image/jpeg"}'

response:

{

"id":"f64e66d5-e26c-426a-ba8b-cfeb220972ff",

"productId":"${PRODUCT_ID}",

"offerId":"${OFFER_ID}",

"sellerId":5005408,

"status":"AVAILABLE"

}

4. Declared Stock approach integration

Bearer is needed. Take a look on Authorization for information on how to get it.

ProductId is needed. Take a look on the appendix for information on how to match a product or find productId by name or catalog_id.

Test productID: 5c9b71292539a4e8f1809707. Can be used on production environment and is available here

Price amount is in cents

To have access to using this approach you have to get privilege. Please send a message to api@kinguin.io with a request for Declared Stock approach activation.

To support this flow you have to set webhooks addresses by sending a request,

curl -i -X POST \

https://gateway.kinguin.net/envoy/api/v1/subscription \

-H 'authorization: Bearer ${BEARER}' \

-H 'content-type: application/json' \

-d '{

"endpoints": {

"reserve": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"give": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"cancel": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"delivered": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"outofstock": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"returned": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"reversed": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"refunded": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c",

"processingpreorder": "https://webhook.site/6e8ab695-872b-46a2-affe-218ac3b35c5c"

},

"headers": [{"name":"X-Auth-Token", "value":"xxxx"}]

}'

We suggest you set up the header with token to validate requests from Kinguin

more info about webhooks and event statuses in section - Appendix: Events

or using your Merchant Panel where you can set webhooks.

Due to design we are not able to provide order of events, e.g. network delays. That why subscriber system should be proof against “invalid” order of events.

1. Create an offer or with declared stock or update existing one

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"declaredStock": 1, "declaredTextStock": 1}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

Field declaredTextStock is optional. The field means how much of the stock set in the declared stock is of the text type. More in the section “4.1 declared text stock”

2. Listen on reservation event (BUYING)

{

"name": "Testowe CD Key",

"price": {

"amount":2,

"currency":"EUR"

},

"priceIWTR": {

"amount":2,

"currency":"EUR"

},

"commissionRule": {"fixedAmount":0,"percentValue":0.0,"ruleName":"Zero"},

"productId": "${PRODUCT_ID}",

"offerId": "${OFFER_ID}",

"status": "BUYING",

"reservationId": "8a9de902-ac4b-4531-b207-cf9e74aaa2b8",

"availableStock": 0,

"buyableStock": 0,

"declaredStock": 1,

"reservedStock": 1,

"requestedKeyType": null,

"updatedAt": "2020-03-06T15:58:49.088+0000",

"popularityBid":{

"amount": 0,

"currency": "EUR"

}

}

3. Listen on give event (BOUGHT)

Depending on the specifics of your system you may need to make sure that BUYING event came before the BOUGHT event. In order to achieve this, you should respond with 4xx HTTP status if you received BOUGHT event for specific reservationId before BUYING event. It will result in retrying to send the BOUGHT event for as long as you decide you have information from BUYING event. Then you should respond with 2xx HTTP status in order to accept this information.

{

"name": "Testowe CD Key",

"price": {

"amount":2,

"currency":"EUR"

},

"priceIWTR": {

"amount":2,

"currency":"EUR"

},

"commissionRule": {"fixedAmount":0,"percentValue":0.0,"ruleName":"Zero"},

"productId": "${PRODUCT_ID}",

"offerId": "${OFFER_ID}",

"status": "BOUGHT",

"reservationId": "8a9de902-ac4b-4531-b207-cf9e74aaa2b8",

"availableStock": 0,

"buyableStock": 0,

"declaredStock": 1,

"reservedStock": 1,

"requestedKeyType": null,

"updatedAt": "2020-03-06T16:00:12.088+0000",

"popularityBid":{

"amount": 0,

"currency": "EUR"

}

}

4. Listen on cancel event

{

"name": "Testowe CD Key",

"price": {

"amount":2,

"currency":"EUR"

},

"priceIWTR": {

"amount":2,

"currency":"EUR"

},

"commissionRule": {"fixedAmount":0,"percentValue":0.0,"ruleName":"Zero"},

"productId": "${PRODUCT_ID}",

"offerId": "${OFFER_ID}",

"status": "CANCELED",

"reservationId": "8a9de902-ac4b-4531-b207-cf9e74aaa2b8",

"availableStock": 0,

"buyableStock": 1,

"declaredStock": 1,

"reservedStock": 0,

"requestedKeyType": null,

"updatedAt": "2020-03-06T16:00:12.088+0000",

"popularityBid":{

"amount": 0,

"currency": "EUR"

}

}

5. Upload stock after receiving BOUGHT event

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"body": "cd key", "mimeType": "text/plain"}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}/stock

6. Listen on delivered event

{

"name": "Testowe CD Key",

"price": {

"amount":2,

"currency":"EUR"

},

"priceIWTR": {

"amount":2,

"currency":"EUR"

},

"commissionRule": {"fixedAmount":0,"percentValue":0.0,"ruleName":"Zero"},

"productId": "${PRODUCT_ID}",

"offerId": "${OFFER_ID}",

"status": "DELIVERED",

"reservationId": "8a9de902-ac4b-4531-b207-cf9e74aaa2b8",

"releasedStockId": "${STOCK_ID}",

"releasedExternalStockId": "${EXTERNAL_STOCK_ID}",

"availableStock": 0,

"buyableStock": 1,

"declaredStock": 1,

"reservedStock": 0,

"updatedAt": "2020-03-06T16:00:12.088+0000",

"popularityBid":{

"amount": 0,

"currency": "EUR"

}

}

4.1 Declared text stock

Some of our clients and sales channels require keys to be delivered in text form. In order to properly handle such cases, we need not only to provide information on the amount of available text stock, but also to provide this type of key, if the customer request this type of key, when placing the order. In order to properly handle this process, when defining the amount of available stock, additionally set the value in the declaredTextStock field. If the customer orders a text stock (this can be recognized by the requestedKeyType=TEXT field in the webhook events), you should provide a text stock, additionally providing the reservation reference via the reservationId field.

  1. Create an offer or with declaredStockand declaredTextStock. declaredTextStock should be lower or equal (when all the available stock is text) than declaredStock

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"declaredStock": 1, "declaredTextStock": 1}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

2. Upload stock with reservationId. You can use this field always when you want to fully control how keys are distributed across all orders.

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"body": "cd key", "mimeType": "text/plain", "reservationId": ${RESERVATION_ID}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}/stock

5. Introducing Smart Pricing Assistant (SPA)

The Smart Pricing Assistant (SPA) is a feature designed to empower merchants by automating the process of adjusting offer prices. With SPA, merchants can optimize their pricing strategies effortlessly, ensuring competitiveness and profitability. This chapter provides an in-depth look into the main features and processes of the SPA tool, along with examples of how to use it effectively.

5.1 Key Features

5.1.1 Automated Price Adjustments

SPA allows merchants to automate the adjustment of their offer prices based on predefined criteria. By utilizing the provided APIs, merchants can set specific conditions under which prices should be modified. SPA then continuously monitors these conditions and applies the necessary price changes, freeing merchants from the manual price adjustment process.

5.1.2 Precise Control

Merchants have full control over the price adjustment parameters. These parameters include:

  • the key cost

  • minimum profit

which sum up to your I Want To Receive (IWTR) value. Merchants can fine-tune these parameters to align with their business goals and strategies, ensuring that the automated price adjustments reflect their pricing preferences.

5.1.3 Real-time Updates

SPA operates in real-time, ensuring that price adjustments are promptly applied whenever the predefined conditions are met. This guarantees that merchants remain competitive and responsive to market dynamics without delays.

5.2 Pricing Logic

The Smart Pricing Assistant (SPA) operates on a sophisticated logic designed to optimize the position of a merchant's offer on tKinguin. SPA's primary objective is to enhance the competitiveness and profitability of the merchant by automating price adjustments based on market conditions. The key pricing principles of SPA are outlined below.

5.2.1 Competitive Positioning

SPA aims to position the merchant's offer as competitively as possible. It achieves this by pricing the offer just 0,01 Euro below the competing offer.

a. Outbidding Competitive Price

If a competitive offer is found, SPA will automatically reduce the price of the offer to be 0.01 Euro lower than the competitive price, as long as this reduction still falls within the minimum price set by the user.

b. No Outbidding Competitive Price

If the minimum price set by the user is higher than the found competitive offer but lower than the current user price, SPA will increase the user's price by 0,01 Euro to make it 1 cent lower than the offer that is one position below. This adjustment is made to maintain the current offer position while obtaining a higher price for it.

5.2.2 Best Possible Position

SPA always strives to secure the best available position for the merchant's offer. However, this positioning is subject to certain constraints: the key cost and the minimum profit amount defined by the merchant.

5.2.3 Flexibility

If the merchant's offer cannot attain the first position due to higher key costs or minimum profit requirements, SPA adjusts the offer's price to be 0.01 Euro below the next available position. This flexibility ensures that the offer remains competitive while adhering to the merchant's pricing strategy.

5.2.4 Maximum Price

If the found offer is higher than the user's maximum price after considering the minimum reduction, SPA sets the product/service price to the maximum price.

The Maximum Profit is an optional field (maximum price will be calculated without it).

5.3 Processes

5.3.1 Activating SPA for Offers

To activate the Smart Pricing Assistant for a specific offer, the following API call can be used:

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '[{"offerId":"63e21a36814762653336ba8f","keyCost":300,"minProfitAmount":40,"minPriceIWTR":{"amount":340,"currency":"EUR"}, "maxProfitAmount":90}]' \

https://gateway.kinguin.net/pizzaportal/api/v1/spa/offers

Request allows to activate SPA in more than 1 offer at the time (array of offers in a body request). Once activated, SPA will automatically adjust the offer's price based on the defined criteria.

Detailed description of the body request

Field name

Description

offerId

ID of the offer in which the SPA is to be activated

keyCost

cost per key (euro cents)

minProfitAmount

the minimum profit per key (euro cents)

minPriceIWTR *

{amount, currency}

the minimum amount that can be obtained for a key in euro cents (IWTR - I Want To Receive - the net price that the seller will receive)

*optional field - if not provided it will be calculated from the formula keyCost + minProfitAmount

maxProfitAmount *

the maximum profit per key (euro cents)

*optional field - no maximum price limit, field is required if maxPriceIWTR provided

maxPriceIWTR *

{amount, currency}

the maximum amount that can be obtained for a key in euro cents (IWTR - I Want To Receive - the net price that the seller will receive)

*optional field - if not provided it will be calculated from the formula keyCost + maxProfitAmount

 

5.3.2 Updating Minimum Price

Merchants can update the minimum price, key cost, and minimum profit amount for an offer with the following API call:

curl -X PUT \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"minPriceIWTR":{"amount":344,"currency":"EUR"},"keyCost":300,"minProfitAmount":44}' \

https://gateway.kinguin.net/pizzaportal/api/v1/spa/offers/${OFFER_ID}

This API call allows merchants to modify the price adjustment parameters, thereby influencing SPA's automated pricing decisions.

Detailed description of the body request

Field name

Description

keyCost

cost per key (euro cents)

minProfitAmount

the minimum profit per key (euro cents)

minPriceIWTR *

{amount, currency}

the minimum amount that can be obtained for a key in euro cents (IWTR - I Want To Receive - the net price that the seller will receive)

*optional field - if not provided it will be calculated from the formula keyCost + minProfitAmount

maxProfitAmount *

the maximum profit per key (euro cents)

*optional field - no maximum price limit, field is required if maxPriceIWTR provided

maxPriceIWTR *

{amount, currency}

the maximum amount that can be obtained for a key in euro cents (IWTR - I Want To Receive - the net price that the seller will receive)

*optional field - if not provided it will be calculated from the formula keyCost + maxProfitAmount

5.3.3 Deactivating SPA for an Offer

To deactivate SPA for a specific offer, merchants can use the following API call:

curl -X DELETE \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

https://gateway.kinguin.net/pizzaportal/api/v1/spa/offers/deactivate/${OFFER_ID}"

This API call removes the automated price adjustment feature for the selected offer, allowing merchants to resume manual control over pricing.

6. Introducing Sales Booster

Sales Booster is an innovative tool tailored for merchants who seek enhanced visibility on the Kinguin’s product page buy button despite price-related limitations. This chapter delves into the key features and processes of the Sales Booster, demonstrating how merchants can strategically leverage this tool to increase their presence and boost sales on the platform.

6.1.1 Visibility Enhancement

Sales Booster is designed to give merchants an opportunity to stand out on Kinguin, even when they can't compete purely on price. By utilizing the provided endpoints, merchants can strategically bid for better positioning on the buy button, allowing them to catch the attention of potential customers.

6.1.2 Strategic Bidding

Merchants have the flexibility to place bids for improved positioning based on their marketing strategy and budget. This enables them to allocate resources effectively to enhance their offer’s visibility.

6.2 Processes

6.2.1 Requesting Visibility Boost

To enhance the visibility of an offer using the Sales Booster, merchants can send a POST request to the following endpoint:

POST /sales-manager-api/api/v1/offers/{OFFER_ID}/popularity

This API call allows merchants to strategically place bids to improve their offer's visibility on the buy button. The offer ID should be replaced with the corresponding offer's identifier.

6.2.2 Checking Position and Bid Impact

Merchants can assess the potential impact of their bid on their offer's position using the following GET request:

GET /sales-manager-api/api/v1/offers/{OFFER_ID}/position?bid={bid}&price={price}

This API call provides merchants with insights into how their offer's position would change based on the specified bid and price parameters. It's a valuable tool to make informed decisions regarding bid amounts.

7. FAQ

If someone order 2 keys from product X and 2 keys from product Y (in one order), then 4 BOUGHT events will be sent to the API?

Yes, events are sent for each key separately. This allows tracking changes for each key.

When I have 2 keys "up front" stock on Kinguin's offer and 20 as "declaredStock", someone bought 4 keys in one order. What parameters will be sent to the API (availableStock, buyableStock, declaredStock, reservedStock)?

When we assume there is no other order(s) on pending process:

{

[...]

"availableStock": 2,

"buyableStock": 22,

"declaredStock": 20,

"reserverdStock": 4,

[...]

}

When exactly OUT_OF_STOCK event will be sent? Only after 30 min after order, when my API does not sent enough keys before?

When there is no availableStock ("up front") then event OUT_OF_STOCK is sent right after BOUGHT.
When there is a reservation in status BOUGHT longer than 30 minutes you will get event OUT_OF_STOCK again.
You should be able to handle many OUT_OF_STOCK for the same reservation.

There are cases when OUT_OF_STOCK is not sent?

When you have availableStock (uploaded stock on "up front" approach) in the offer then OUT_OF_STOCK event is not sent

In the events JSON payload there is a price and currency. How to ensure that currency will be always EUR?

At the moment all orders are billed in EUR, and we don't plan to change this in known future

Can I assume that when my API gets OUT_OF_STOCK event, then it should add exactly one key to the offer, and everything will be fine?

Yes. We advise to listen on DELIVEREDevent to keep track of which reservation the key has been assigned to

Does API response codes to the events mean something? If there will be non-2xx then it will be tried once again?

Yes, when you return other status than 2xx, we will try to deliver event again (5 tries, and then after 10 minutes again 5 tries)

If we set declaredStock=0 and there will be no up-front stock (availableStock=0), then should be change the status of the offer, or it will be done automatically?

Offer disappears from Product Page, and customers cannot purchase from it. Status change is not needed. Uploading keys or changing declaredStock value will make the offer buyable again.

When my offer is visible for users and their can buy it

Offer is visible for buyers when buyableStock is greater than 0 (zero) and offer status is ACTIVE and offer is not blocked

How buyableStock is calculated

buyableStock = availableStock + declaredStock - reservedStock

How long reservation can be in BUYING status

It’s max 72h when reservation is canceled or bought

What happens if I don't deliver the declared stock?
If the stock is not delivered within 15 minutes, an alert will be generated that will affect the seller's rating. Then after about 10-15 minutes, the reservation will be canceled and the offer will be temporarily blocked (for about 4h)

Appendix

Events

Our system is able to broadcast notifications about Kinguin’s marketplace ordering process related to given merchant’s offers . These notifications aren’t automatically send to merchant. To enable those notifications you have to subscribe in our notification service (Envoy).

1. Events

Envoy is able to send webhooks for given Kinguin’s marketplace events:

Marketplace event

Webhook endpoint

Description

BUYING

reserve

When user start buying process (go to payment gateway)

BOUGHT

give

When we received payment from user

CANCELED

cancel

When reservation is cancelled, e.g. payment gateway cancellation during payment. This event can appear only before key is delivered.

DELIVERED

delivered

When key is delivered to buyer

RETURNED

returned

When user did now saw key and during complaint process Kinguin agreed to “return key to stock”. Mostly user is refunded then.

OUT_OF_STOCK

outofstock

When reservation was in BOUGHT state and key wasn’t uploaded to stock at time. This is “reminding” event that in some reservations are not delivered keys. Not providing stock at time can block merchant offer.

REFUNDED

refunded

When reservation was refunded

REVERSED

reversed

When payment for order was reversed

PROCESSING_PREORDER

processingpreorder

When reservation is waiting for stock for the preorder, simillar to out_of_stock, but with diffrent restrictions regarding the time limit for stock delivery

OFFER_POSITION_CHANGED

offerpositionchanged

When an offer has changed its position on the product’s offers list (e.g. when another merchant adds a better offer and his offer is above yours)

You can find more information about particular events in Declared Stock approach integration section of such documentation.

2. Manage subscription

To receive whatever webhooks that Kinguin sent you have to setup your own subscription. This part will guide you how to configure (make / update) your subscription.

You are going to use endpoints which are protected and because of that we suggest you to read documentation Requirements and Authorization points. Next endpoints requires you to attach auth token in request’s headers. In case when You receive 401s as a HTTP code in responses this may

To create / update / view your subscription you will be using given endpoint:

Operation

Method

Payload

Headers

URL

Make subscription

POST

See Making / updating subscription point.

Auth token required.

https://gateway.kinguin.net/envoy2/api/v1/subscription

Update subscription

View subscription

GET

none

Common valid HTTP code for each of those requests is 200.

Making / updating subscription

You can create subscription only once. You are able to modify your subscription multiple times depending on your needs.

Keep in mind that every change you made in subscription impacts only to newly created webhooks. Let say that you’ve change endpoint for DELIVERED event. Since that change every newly made webhooks are going to be delivered to updated endpoint. Old queued webhooks are going to be delivered to old endpoint.

Payload for given operations has two fields:

Field

Type

Required

Can be empty?

endpoints

Map<String, URL>

true

yes

headers

List<Map<String, String>>

true

yes

Example of request payload:

{

"endpoints": {

"reserve": "https://your-service-domain.com/reserve_receiver",

"give": "https://your-service-domain.com/give_receiver",

"cancel": "https://your-service-domain.com/cancel_receiver",

"delivered": "https://your-service-domain.com/delivered_receiver",

"returned": "https://your-service-domain.com/returned_receiver",

"outofstock": "https://your-service-domain.com/outofstock_receiver",

"reversed": "https://your-service-domain.com/reversed_receiver",

"refunded": "https://your-service-domain.com/refunded_receiver",

"processingpreorder": "https://your-service-domain.com/processingpreorder_receiver",

"offerpositionchanged": "https://your-service-domain.com/offerpositionchanged_receiver"

},

"headers": [

{

"name": "your-secret-token",

"value": "$@CrEt"

}

]

}

Given payload will make new subscription or update existed one. Crucial part of that payload is endpoints field which contains a map of key-value pairs where key is an endpoint name and URL as a value. As you can see endpoints keys refers to webhook endpoints in Events paragraph. It means that each endpoint is mapped to Kinguin’s marketplace events.

Every request (create / update / view) has the same structure of response. Common success HTTP code for each of those requests is 200.

Envoy sends webhooks over internet and delivers payload to publicly available endpoints. Due to security reasons we sugggest you to define your own security header. Each of Envoy’s request will contain your header and thus gives you ability to verify identity Envoy as a true sender of webhook.

Example of common response

{

"id": "8e78b7aa9c66c4d5bbe983546",

"endpoints": {

"reserve": "https://your-service-domain.com/reserve_receiver",

"give": "https://your-service-domain.com/give_receiver",

"cancel": "https://your-service-domain.com/cancel_receiver",

"delivered": "https://your-service-domain.com/delivered_receiver",

"returned": "https://your-service-domain.com/returned_receiver",

"outofstock": "https://your-service-domain.com/outofstock_receiver",

"reversed": "https://your-service-domain.com/reversed_receiver",

"refunded": "https://your-service-domain.com/refunded_receiver",

"processingpreorder": "https://your-service-domain.com/processingpreorder_receiver",

"offerpositionchanged": "https://your-service-domain.com/offerpositionchanged_receiver"

},

"subscriberId": "12345678",

"headers": [

{

"name": "your-secret-token",

"value": "$@CrEt"

}

]

}

Blocking webhooks - automatic prevention of unsuccessful requests

The mechanism of blocking webhooks is designed to automatically prevent unsuccessful webhook requests.

The purpose of this feature is to identify and take action when, within a 15-minute timeframe, every response returns a status code other than 200 OK or timeout. In such cases, the affected URL is placed on a block list and Kinguin will cease sending any webhooks to this address until it is manually unblocked. Additionally, a notification email is sent to the merchant.

This proactive approach ensures that webhook integrations remain efficient and reliable, preventing scenarios where all responses to a series of requests are unsuccessful.

Unblocking webhooks

After verifying that the URL is functioning correctly, you can reactivate webhook delivery to this address by sending the endpoint name in the POST request (the name should match the Webhook Endpoint name from the table in point 1. Events):

curl -i -X POST \

https://gateway.kinguin.net/envoy/api/v1/subscription/unblock \

-H 'authorization: Bearer ${BEARER}' \

-H 'content-type: application/json' \

-d '{ "endpoint": "reserve" }'

3. Requests (webhooks) history

Envoy gives you opportunity to review notifications which have been sent through Envoy service. To get your own requests (webhooks) history use endpoint:

Method

Headers

Expected response HTTP status

URL

GET

Auth token required.

200

https://gateway.kinguin.net/envoy2/api/v1/requests

Every thing that is 200.

Remember to attach auth token in request headers.

Example of response

{

    "_embedded": {

        "requestHistoryList": [

          // collection of webhooks (look on webhook model below)

        ]

    },

    "_links": {

        "first": {

            "href": "https://gateway.kinguin.net/envoy2/api/v1/requests?page=0&size=1"

        },

        "self": {

            "href": "https://gateway.kinguin.net/envoy2/api/v1/requests?page=0&size=1"

        },

        "next": {

            "href": "https://gateway.kinguin.net/envoy2/api/v1/requests?page=1&size=1"

        },

        "last": {

            "href": "https://gateway.kinguin.net/envoy2/api/v1/requests?page=2537&size=1"

        }

    },

    "page": {

        "size": 1,

        "totalElements": 2538,

        "totalPages": 2538,

        "number": 0

    }

}

Webhook model

Webhooks are located inside collection named _embedded.requestHistoryList. Below’s list contains fields which are part of single webhook document.

Field

Type

Description

id

String

Request history ID.

webhookRequestId

String

ID of webhook request.

deployAttempt

Integer

Webhook request sent count (webhookRequestId)

sentDate

Date

Webhook request sent date. Date format YYYY-MM-DDTHH:mm:ss.ms GMT is the timezone.

destinationUrl

String/URL

URL on which webhook has been sent.

Request

request.id

String

ID of webhook request.

request.endpointKey

String

The name of the endpoint (e.g. “reserve“, “give“…)

request.headers

List

Collection of Header objects which have been attached to request.

request.subscriberId

Integer

Merchant’s ID.

request.state

String

State of request (for internal purposes).

request.statusesLog

List

Log ledger for given webhook (for internal purposes).

request.deployAttempts

Integer

Webhook request sent count

request.createDate

Date

Creation date (for internal purposes).

request.toDeployDate

Date or null

Deploy date (for internal purposes).

request.lastDeployDate

Date

Deployment date (for internal purposes).

request.toSent.body

String

Request’s payload which has been sent out. Serialized to JSON-like string.

request.toSent.bodyId

String

ID of sent entity (e.g. ReservationID).

Response

response.responseStatus

NInteger

HTTP status that has been returned in response.

response.responseBody

String or null

HTTP body response mapped to string that has been returned in response.

Example of single webhook request document

{

"id": "89d752ce-0cd7-4038-976a-eee3e04df39d",

"webhookRequestId": "3fd6c1b4-3db5-4c38-a460-9e4f490c342e",

"deployAttempt": 1,

"request": {

"id": "3fd6c1b4-3db5-4c38-a460-9e4f490c342e",

"endpointKey": "delivered",

"headers": [

{

"name": "x-secret-key",

"value": "s3cr3t"

}

],

"subscriberId": "5005408",

"state": "DEPLOYED",

"statusesLog": [

{

"date": "2021-08-31T13:00:38.914+0000",

"state": "READY"

},

{

"date": "2021-08-31T13:00:39.163+0000",

"state": "DEPLOYED"

}

],

"deployAttempts": 1,

"createDate": "2021-08-31T13:00:38.914+0000",

"toDeployDate": null,

"lastDeployDate": "2021-08-31T13:00:39.163+0000",

"toSent": {

"body": "{\"reservationId\":\"039a219d-7a62-4978-b070-03d7a88bb3ee\",\"productId\":\"5c9b608d2539a4e8f1737129\",\"name\":\"Worms Armageddon Steam CD Key\",\"price\":{\"amount\":1120,\"currency\":\"EUR\"},\"priceIWTR\":{\"amount\":1000,\"currency\":\"EUR\"},\"offerId\":\"5f8842ba34825e0001c95465\",\"status\":\"DELIVERED\",\"updatedAt\":\"2021-08-31T13:00:38.884+0000\",\"orderIncrementId\":\"JBOZP02ECRT\",\"declaredStock\":0,\"reservedStock\":26,\"availableStock\":253,\"buyableStock\":227,\"commissionRule\":{\"percentValue\":10,\"ruleName\":\"Test commision\",\"fixedAmount\":20},\"releasedStockId\":\"5e264018-3f66-4c35-95dc-ac72418720e2\",\"releasedExternalStockId\":null,\"popularityBid\":{\"amount\":4000,\"currency\":\"EUR\"}}",

"bodyId": "039a219d-7a62-4978-b070-03d7a88bb3ee"

}

},

"response": {

"responseStatus": 200,

"responseBody": null

},

"sentDate": "2021-08-31T13:00:39.163+0000",

"destinationUrl": "https://webhook.site/5c46edb4-e3d5-4737-b580-43dd1b1eb32c"

}

4. Webhook request sending and Re-tries

Every webhook request is send until don’t get response with status 200, but not often than 5 times. After every failed attempt envoy delays next send. First send is immediately. Second after 30 seconds, third after 60 seconds, fourth after 5 minutes and fifth after 15 minutes on last failed delivery.

There is possibility to re-try on demand making request:

curl -X POST \

-H "Authorization: Bearer ${TOKEN}" \

-H "Content-Type: application/json" \

-d '{"webhookRequestId": "[webhookRequestId]"}' \

https://gateway.kinguin.net/envoy2/api/v1/requests/retry

Updating Offer

changing price

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"price": {"amount": 2, "currency": "EUR"}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

response:

{

"id":"${OFFER_ID}",

"productId":"${PRODUCT_ID}",

"name":"Testowe CD Key",

"sellerId":5005408,

"status":"ACTIVE",

"block":null,

"priceIWTR":{

"amount":2,

"currency":"EUR"

},

"declaredStock":0,

"reservedStock":0,

"availableStock":0,

"updatedAt":"2020-03-06T10:58:49.088+0000",

"createdAt":"2020-03-06T10:58:48.951+0000",

"buyableStock":0

}

Updating wholesale tiers in Offer

Offer can be set to be sold wholesale. To enable offer as available for wholesale it has to have enabled set to true, and sell tiers need to be defined. There are four (4) tiers that decrease prices depending on bought keys amount.

  • level 1 above 0 to 10 pcs

  • level 2 above 10 to 20 pcs

  • level 3 above 20 to 50 pcs

  • level 4 above 50 pcs

discount attribute in the tier is a percent discount off the offer's “I Want To Receive” Price

Examples of API usage below.

Setting up wholesale without discounts

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"wholesale":{"enabled":true,"name":"custom", "tiers": [{"level": 1, "discount": 0},{"level": 2, "discount": 0},{"level": 3, "discount": 0},{"level": 4, "discount": 0}]}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

response:

{

"id": "5f8842ba34825e0001c95465",

[...]

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

},

"price": {

"amount": 1320,

"currency": "EUR"

},

[...]

"wholesale": {

"name": "custom",

"enabled": true,

"tiers": [

{

"discount": 0,

"level": 1,

"price": {

"amount": 1060,

"currency": "EUR"

},

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

}

},

{

"discount": 0,

"level": 2,

"price": {

"amount": 1060,

"currency": "EUR"

},

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

}

},

{

"discount": 0,

"level": 3,

"price": {

"amount": 1060,

"currency": "EUR"

},

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

}

},

{

"discount": 0,

"level": 4,

"price": {

"amount": 1060,

"currency": "EUR"

},

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

}

}

]

},

[...]

}

Setting up wholesale with discounts, 0% for sales smaller or equal than 10 pcs, 4% for sales between 11-20 pcs, 5% for sales between 21-50 pcs, 6% for sales above 6%

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"price": { "amount": 1000, "currency": "EUR"}, "wholesale":{"enabled":true,"name":"custom", "tiers": [{"level": 1, "discount": 0},{"level": 2, "discount": 4},{"level": 3, "discount": 5},{"level": 4, "discount": 6}]}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

response:

{

"id": "5f8842ba34825e0001c95465",

[...]

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

},

"price": {

"amount": 1320,

"currency": "EUR"

},

[...]

"wholesale": {

"name": "custom",

"enabled": true,

"tiers": [

{

"discount": 0,

"level": 1,

"price": {

"amount": 1060,

"currency": "EUR"

},

"priceIWTR": {

"amount": 1000,

"currency": "EUR"

}

},

{

"discount": 4,

"level": 2,

"price": {

"amount": 1018,

"currency": "EUR"

},

"priceIWTR": {

"amount": 960,

"currency": "EUR"

}

},

{

"discount": 5,

"level": 3,

"price": {

"amount": 1007,

"currency": "EUR"

},

"priceIWTR": {

"amount": 950,

"currency": "EUR"

}

},

{

"discount": 6,

"level": 4,

"price": {

"amount": 996,

"currency": "EUR"

},

"priceIWTR": {

"amount": 940,

"currency": "EUR"

}

}

]

},

[...]

}

Disable offer from wholesale

curl -i -X PATCH \

-H "Authorization: Bearer ${BEARER}" \

-H "Content-Type: application/json" \

-d '{"wholesale":{"enabled":false,"name":"dontSell"}}' \

https://gateway.kinguin.net/sales-manager-api/api/v1/offers/${OFFER_ID}

Matching products

Platforms:

[

{

"id":2,

"name":"Steam"

},

{

"id":1,

"name":"EA Origin"

},

{

"id":10,

"name":"XBOX ONE"

},

{

"id":7,

"name":"XBOX 360"

},

{

"id":5,

"name":"Uplay"

},

{

"id":3,

"name":"Battle.net"

},

{

"id":15,

"name":"GOG COM"

},

{

"id":18,

"name":"Epic Games"

},

{

"id":8,

"name":"PlayStation 3"

},

{

"id":11,

"name":"PlayStation 4"

},

{

"id":14,

"name":"PlayStation Vita"

},

{

"id":6,

"name":"Kinguin"

},

{

"id":4,

"name":"NCSoft"

},

{

"id":17,

"name":"Nintendo"

},

{

"id":12,

"name":"Android"

},

{

"id":13,

"name":"Other"

}

]

Regions

[

{

"id":3,

"name":"Region free"

},

{

"id":1,

"name":"Europe"

},

{

"id":18,

"name":"North America"

},

{

"id":10,

"name":"RoW"

},

{

"id":4,

"name":"Other"

},

{

"id":12,

"name":"Asia"

},

{

"id":14,

"name":"Australia"

},

{

"id":15,

"name":"Brazil"

},

{

"id":9,

"name":"China"

},

{

"id":13,

"name":"Germany"

},

{

"id":16,

"name":"India"

},

{

"id":17,

"name":"Japan"

},

{

"id":11,

"name":"Latin America"

},

{

"id":5,

"name":"Outside Europe"

},

{

"id":6,

"name":"RU VPN"

},

{

"id":7,

"name":"Russia"

},

{

"id":8,

"name":"United Kingdom"

},

{

"id":2,

"name":"United States"

}

]

languages:

[

{

"id":"ar_AE",

"name":"Arabic"

},

{

"id":"bg_BG",

"name":"Bulgarian"

},

{

"id":"zh_CN",

"name":"Chinese"

},

{

"id":"cs_CZ",

"name":"Czech"

},

{

"id":"da_DK",

"name":"Danish"

},

{

"id":"nl_NL",

"name":"Dutch"

},

{

"id":"en_US",

"name":"English"

},

{

"id":"fi_FI",

"name":"Finnish"

},

{

"id":"fr_FR",

"name":"French"

},

{

"id":"de_DE",

"name":"German"

},

{

"id":"el_GR",

"name":"Greek"

},

{

"id":"hu_HU",

"name":"Hungarian"

},

{

"id":"it_IT",

"name":"Italian"

},

{

"id":"ja_JP",

"name":"Japanese"

},

{

"id":"ko_KR",

"name":"Korean"

},

{

"id":"nn_NO",

"name":"Norwegian"

},

{

"id":"pl_PL",

"name":"Polish"

},

{

"id":"pt_PT",

"name":"Portuguese"

},

{

"id":"ro_RO",

"name":"Romanian"

},

{

"id":"ru_RU",

"name":"Russian"

},

{

"id":"es_ES",

"name":"Spanish"

},

{

"id":"sv_SE",

"name":"Swedish"

},

{

"id":"th_TH",

"name":"Thai"

},

{

"id":"tr_TR",

"name":"Turkish"

},

{

"id":"uk_UA",

"name":"Ukrainian"

}

]";"

https://gateway.kinguin.net/library/api/v1/products/search?platforms=2&regions=3&languages=en_US&phrase=phrase

To use more than one use comma(s)

Finding the valid productId by name

TODO

Finding the valid productId by kinguin catalog_id (old id)

To get productId you can use Kinguin Product Catalog endpoint

request

curl 'https://gateway.kinguin.net/kpc/api/v1/products/search/findByTypeAndExternalId?type=kinguin&externalId=56966' | jq "._embedded.products[0].id"

response

"5c9b786b2539a4e8f1842c1c"

[Value in Cents] Getting I Want to Receive Price from Offer Price (with Kinguin commision)

request

curl --request GET 'https://gateway.kinguin.net/sales-manager-api/api/v1/offers/calculations/priceAndCommission?kpcProductId=$[kpcProductId]&price=[$price] \

--header 'Authorization: Bearer ${BEARER}

response:

{

"rule": "Rule name",

"priceIWTR": 100,

"price": 125,

"fixedAmount": 0,

"percentValue": 25

}

[Value in Cents] Getting Offer Price (with Kinguin commision) from I Want to Receive Price

request

curl --request GET 'https://gateway.kinguin.net/sales-manager-api/api/v1/offers/calculations/priceAndCommission?kpcProductId=$[kpcProductId]&priceIWTR=[$priceIWTR] \

--header 'Authorization: Bearer ${BEARER}

response:

{

"rule": "Rule name",

"priceIWTR": 100,

"price": 125,

"fixedAmount": 0,

"percentValue": 25

}


Was this article helpful?