SkinPlata API
Take CS2, Dota 2 and Rust skins as payment and send skins to your customers — with one REST API and signed webhooks.
Import the OpenAPI file into Postman, Insomnia, Bruno or your code generator to get a ready client.
Quickstart
Get your keys
Open an account and submit a project. Your project key and test secret are shown at once; the live secret works once we approve the project.
Create a payment
Call POST /payments with your order id, then send the customer to pay_url.
Listen for the webhook
Fulfil the order on deposit.success. In test mode, drive outcomes from the checkout's test buttons or POST /test/payments/{id}/simulate.
curl -X POST 'https://skinplata.com/api/v1/payments' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"order_id":"inv-1042","game":"cs2","currency":"usd","min_amount":5,"metadata":{"user_id":"8812"}}'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'order_id' => 'inv-1042',
'game' => 'cs2',
'currency' => 'usd',
'min_amount' => 5,
'metadata' => [
'user_id' => '8812',
],
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"order_id": "inv-1042",
"game": "cs2",
"currency": "usd",
"min_amount": 5,
"metadata": {
"user_id": "8812"
}
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/payments",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"order_id": "inv-1042",
"game": "cs2",
"currency": "usd",
"min_amount": 5,
"metadata": {
"user_id": "8812"
}
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Authentication
Every request carries two headers. Keep the secret on your server — never in a browser or an app.
| Header | Value |
|---|---|
X-Project-Key | Your public project key, pk_… |
X-Project-Secret | sk_live_… for real money, sk_test_… for test mode |
An optional IP allow-list is in the project settings. Rotating a secret stops the old one at once.
Errors & limits
Errors use a matching HTTP status and one shape:
{
"error": {
"code": "invalid_request",
"message": "order_id is required (1–128 printable characters, no spaces).",
"param": "order_id"
}
}
| Status | Codes |
|---|---|
| 401 | unauthenticated, invalid_credentials |
| 402 | insufficient_funds |
| 403 | project_inactive, project_disabled, ip_not_allowed, test_mode_only |
| 404 | not_found |
| 409 | duplicate_order_id, not_in_trade_protection, invalid_transition, no_webhook_url |
| 422 | invalid_request (see param) and refusals from the market |
| 429 | rate_limited — 600 requests a minute per project, 1,200 per IP; see Retry-After |
| 503 | temporarily_unavailable — retry later; nothing was charged |
Lists take page and limit (1–100) and answer {"object":"list","data":[…],"page","limit","total","has_more"}. Creating calls are idempotent by your reference: a repeated order_id answers 409, a repeated custom_id returns the first purchase.
Test mode
Use your sk_test_ secret and everything is simulated: real skin names and prices, no real trades, a separate test balance that starts at $1,000.00 (reset it on the project page). Objects carry "livemode": false, responses the header SkinPlata-Test: 1, webhooks go to the same URL with the same signature. Test objects are invisible to the live secret and the other way round.
Webhooks
Set the URL on the project page. We send a POST with a JSON body for every event below, signed with your whsec_ secret. Answer any 2xx; anything else is retried at 1 min, 5 min, 15 min, 1 h, 3 h, 6 h, 12 h and 24 h. Failed deliveries can be resent from the dashboard.
POST /your/webhook
Content-Type: application/json
SkinPlata-Event: deposit.success
SkinPlata-Delivery: wh_9a8b7c6d5e4f3a2b1c0d9e8f
SkinPlata-Signature: t=1793920000,v1=5f2c…
{
"id": "wh_9a8b7c6d5e4f3a2b1c0d9e8f",
"type": "deposit.success",
"created": 1793920000,
"livemode": true,
"data": {
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"order_id": "inv-1042",
"status": "success",
"net_usd": 14.2,
"…": "…"
}
}
Check the signature
SkinPlata-Signature is t=<unix time>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">. Use the raw body exactly as received, refuse timestamps older than 5 minutes, compare in constant time. Then re-read the object before you hand anything out.
<?php
$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_SKINPLATA_SIGNATURE'] ?? '';
$secret = 'whsec_your_secret';
$parts = [];
foreach (explode(',', $header) as $kv) {
[$k, $v] = array_pad(explode('=', trim($kv), 2), 2, '');
$parts[$k][] = $v;
}
$t = (int) ($parts['t'][0] ?? 0);
$sig = hash_hmac('sha256', $t . '.' . $raw, $secret);
$ok = abs(time() - $t) <= 300 && array_filter($parts['v1'] ?? [], fn ($v) => hash_equals($sig, $v));
if (!$ok) { http_response_code(400); exit; }
$event = json_decode($raw, true);
// Credit your customer only after re-reading the object: GET /payments/{id}
http_response_code(200);import crypto from 'node:crypto';
// Express: app.post('/webhook', express.raw({ type: 'application/json' }), handler)
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map(p => p.trim().split('=')));
const t = Number(parts.t);
const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex');
const ok = parts.v1 && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
return ok && Math.abs(Date.now() / 1000 - t) <= 300;
}
if (!verify(req.body.toString(), req.get('SkinPlata-Signature') || '', 'whsec_your_secret')) {
return res.sendStatus(400);
}
const event = JSON.parse(req.body);
res.sendStatus(200);import hashlib, hmac, json, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.strip().split('=', 1) for p in header.split(',') if '=' in p)
t = int(parts.get('t', '0'))
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return abs(time.time() - t) <= 300 and hmac.compare_digest(expected, parts.get('v1', ''))
# Flask: raw = request.get_data(); header = request.headers.get('SkinPlata-Signature', '')
if not verify(raw, header, 'whsec_your_secret'):
abort(400)
event = json.loads(raw)Events
| Event | When |
|---|---|
deposit.pending | Trade offer sent to the customer. |
deposit.in_hold | Customer accepted; Steam trade protection running. |
deposit.hold_approved | You released it early (your side only). |
deposit.success | Final. Your balance is credited — fulfil the order now. |
deposit.fail | Declined, cancelled or timed out. Nothing credited. |
deposit.hold_returned | Reversed during trade protection; a credit is taken back. |
deposit.expired | The link was never used. |
purchase.creating_trade | Skin bought, trade being created. |
purchase.waiting_accept | Trade offer sent to the recipient. |
purchase.accepted | Delivered. |
purchase.failed | Not delivered; money released or refunded. |
purchase.rolled_back | Trade reversed after delivery; refunded. |
payout.pending | Payout requested. |
payout.paid | Payout sent (reference included). |
payout.rejected | Payout rejected (reason included); money back on your balance. |
test.ping | Sent by "Send test.ping" or POST /webhooks/test. |
Embedding the checkout
Link to pay_url, open it in a pop-up, or put embed_url in an iframe. The page posts every status change to your window — use it for your UI, and credit from the webhook.
<iframe src="https://skinplata.com/pay/…?embed=1" width="100%" height="720" style="border:0"></iframe>
<script>
window.addEventListener('message', (e) => {
if (e.origin !== 'https://skinplata.com' || e.data?.source !== 'skinplata') return;
// { type: 'payment.status', status: 'pending' | 'in_hold' | 'success' | 'fail' …, payment_id, order_id }
if (e.data.status === 'success') showThankYou();
});
</script>
Payments
Take skins as payment: hosted payment links or your own item picker.
/payments
Create a payment link
Creates a hosted payment. Send the customer to pay_url (or embed embed_url). The payment moves through created → pending → in_hold → success; you get a webhook for every step.
Body application/json
order_id requiredstring |
Your reference. Unique per project and mode. 1–128 printable characters, no spaces. |
gamestring |
Game whose inventory the customer sees first. Default: project setting.cs2dota2rust |
currencystring |
Currency prices are shown in. Default: project setting.usdeurgbpcadaudnzdbrlcnymxnrubuahkztarsclppencop |
min_amountnumber |
Least value the customer must send, in currency. |
max_amountnumber |
Most value accepted, in currency. |
trade_urlstring |
The customer's Steam trade link, if you already have it (skips that step). |
success_urlstring |
https URL for "Back to shop" after a good payment. Default: project setting. |
fail_urlstring |
https URL for "Back to shop" after a failed one. |
metadataobject |
Up to 20 keys (1–40 of A-Z a-z 0-9 _ . -), text or number values up to 500 characters. Returned on every object and webhook. |
expires_ininteger |
Seconds until an unused link expires. Default 86400. |
Request
curl -X POST 'https://skinplata.com/api/v1/payments' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"order_id":"inv-1042","game":"cs2","currency":"usd","min_amount":5,"metadata":{"user_id":"8812"}}'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'order_id' => 'inv-1042',
'game' => 'cs2',
'currency' => 'usd',
'min_amount' => 5,
'metadata' => [
'user_id' => '8812',
],
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"order_id": "inv-1042",
"game": "cs2",
"currency": "usd",
"min_amount": 5,
"metadata": {
"user_id": "8812"
}
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/payments",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"order_id": "inv-1042",
"game": "cs2",
"currency": "usd",
"min_amount": 5,
"metadata": {
"user_id": "8812"
}
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 201 403 project_inactive409 duplicate_order_id422 invalid_request
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
/payments/direct
Create a direct payment
For your own item picker: read the inventory with GET /inventory, then send the chosen asset_ids. The Steam trade offer is created at once; the answer has status: pending and trade_offer_url.
Body application/json
order_id requiredstring |
Your reference, unique per project and mode. |
game requiredstring |
cs2dota2rust |
trade_url requiredstring |
The customer's Steam trade link. |
asset_ids requiredstring[] |
1–200 asset ids from GET /inventory. |
currencystring |
usdeurgbpcadaudnzdbrlcnymxnrubuahkztarsclppencop |
metadataobject |
As on POST /payments. |
Request
curl -X POST 'https://skinplata.com/api/v1/payments/direct' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"order_id":"inv-1043","game":"cs2","trade_url":"https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh","asset_ids":["31502281937","31502281944"],"currency":"usd"}'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments/direct');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'order_id' => 'inv-1043',
'game' => 'cs2',
'trade_url' => 'https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh',
'asset_ids' => [
'31502281937',
'31502281944',
],
'currency' => 'usd',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments/direct', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"order_id": "inv-1043",
"game": "cs2",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh",
"asset_ids": [
"31502281937",
"31502281944"
],
"currency": "usd"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/payments/direct",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"order_id": "inv-1043",
"game": "cs2",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh",
"asset_ids": [
"31502281937",
"31502281944"
],
"currency": "usd"
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 201 403 project_inactive409 duplicate_order_id422 invalid_request503 temporarily_unavailable
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
/payments
List payments
Newest first. Only objects of the mode of your secret (live or test).
Parameters
statusquery · string |
Filter by status.createdpendingin_holdhold_approvedsuccessfailhold_returnedexpired |
order_idquery · string |
Find by your order id. |
steam_idquery · string |
Find by the customer's SteamID64. |
fromquery · integer |
Created at or after (unix time). |
toquery · integer |
Created at or before (unix time). |
pagequery · integer |
Page, from 1. |
limitquery · integer |
Items per page, 1–100 (default 25). |
Request
curl 'https://skinplata.com/api/v1/payments' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/payments",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
/payments/{id}
Get a payment
Parameters
id requiredpath · string |
Payment id (dep_…). |
Request
curl 'https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 404 not_found
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
/payments/{id}/release
Release a payment early
For a payment in Steam trade protection (in_hold): tells your system now (deposit.hold_approved). Your balance is still credited only when the trade is final.
Parameters
id requiredpath · string |
Payment id (dep_…). |
Request
curl -X POST 'https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/release' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{}'<?php
$ch = curl_init('https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/release');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/release', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/release",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json=[],
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 404 not_found409 not_in_trade_protection
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
/inventory
Read a customer's inventory
Tradable items with live prices, for POST /payments/direct. Items with available: false cannot be accepted.
Parameters
trade_url requiredquery · string |
The customer's Steam trade link. |
gamequery · string |
Game. Default: project setting.cs2dota2rust |
currencyquery · string |
Currency of price. Default: project setting. |
Request
curl 'https://skinplata.com/api/v1/inventory?trade_url=https%3A%2F%2Fsteamcommunity.com%2Ftradeoffer%2Fnew%2F%3Fpartner%3D12345678%26token%3DAbCdEfGh&game=cs2' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/inventory?trade_url=https%3A%2F%2Fsteamcommunity.com%2Ftradeoffer%2Fnew%2F%3Fpartner%3D12345678%26token%3DAbCdEfGh&game=cs2');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/inventory?trade_url=https%3A%2F%2Fsteamcommunity.com%2Ftradeoffer%2Fnew%2F%3Fpartner%3D12345678%26token%3DAbCdEfGh&game=cs2', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/inventory?trade_url=https%3A%2F%2Fsteamcommunity.com%2Ftradeoffer%2Fnew%2F%3Fpartner%3D12345678%26token%3DAbCdEfGh&game=cs2",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 422 invalid_request503 temporarily_unavailable
{
"object": "inventory",
"livemode": true,
"game": "",
"currency": "",
"steam_id": "",
"items": [],
"total_available": 0.0
}
Market
What is in stock on the skin market.
/market/items
Skins in stock
Every skin you can buy right now with its lowest price.
Parameters
gamequery · string |
Game (default cs2).cs2dota2rust |
qquery · string |
Words that must all appear in the name. |
pagequery · integer |
Page, from 1. |
limitquery · integer |
Items per page, 1–100 (default 25). |
Request
curl 'https://skinplata.com/api/v1/market/items?game=cs2' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/market/items?game=cs2');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/market/items?game=cs2', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/market/items?game=cs2",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"object": "market_item",
"name": "AK-47 | Redline (Field-Tested)",
"price_usd": 25.63,
"count": 60
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
/market/offers
Live offers for one skin
Every offer of an exact market name, cheapest first. Use item_id with POST /purchases to buy that exact item.
Parameters
game requiredquery · string |
Game.cs2dota2rust |
name requiredquery · string |
Exact market name. |
Request
curl 'https://skinplata.com/api/v1/market/offers?game=cs2&name=AK-47%20%7C%20Redline%20%28Field-Tested%29' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/market/offers?game=cs2&name=AK-47%20%7C%20Redline%20%28Field-Tested%29');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/market/offers?game=cs2&name=AK-47%20%7C%20Redline%20%28Field-Tested%29', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/market/offers?game=cs2&name=AK-47%20%7C%20Redline%20%28Field-Tested%29",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"object": "market_offer",
"item_id": 0,
"name": "",
"price_usd": 0.0,
"float": null,
"delivery_type": null,
"stickers": [],
"image": ""
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
Purchases
Buy a skin with your balance and send it to a trade link.
/purchases
Buy a skin and send it
Holds max_price (plus the market fee, if any) on your balance, buys, then charges the real price and releases the rest. Repeating a custom_id returns the existing purchase (200) — safe to retry. If the skin does not reach the customer, the charge comes back.
Body application/json
custom_id requiredstring |
Your reference; makes the call idempotent. |
trade_url requiredstring |
The customer's Steam trade link. |
max_price requirednumber |
Highest item price in USD you accept. |
item_idinteger |
A specific offer from GET /market/offers. Or give name + game. |
namestring |
Exact market name: the cheapest offer under max_price is bought. |
gamestring |
Needed with name.cs2dota2rust |
delivery_typesinteger[] |
1 = instant, 2 = regular. |
test_outcomestring |
Test mode only: how the simulated purchase ends.acceptedwaiting_acceptfailed |
Request
curl -X POST 'https://skinplata.com/api/v1/purchases' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"custom_id":"wd-77","trade_url":"https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh","max_price":30,"name":"AK-47 | Redline (Field-Tested)","game":"cs2"}'<?php
$ch = curl_init('https://skinplata.com/api/v1/purchases');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'custom_id' => 'wd-77',
'trade_url' => 'https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh',
'max_price' => 30,
'name' => 'AK-47 | Redline (Field-Tested)',
'game' => 'cs2',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/purchases', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"custom_id": "wd-77",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh",
"max_price": 30,
"name": "AK-47 | Redline (Field-Tested)",
"game": "cs2"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/purchases",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"custom_id": "wd-77",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=12345678&token=AbCdEfGh",
"max_price": 30,
"name": "AK-47 | Redline (Field-Tested)",
"game": "cs2"
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 201 402 insufficient_funds403 project_inactive422 invalid_request503 temporarily_unavailable
{
"id": "pur_1c2d3e4f5a6b7c8d9e0f1a2b",
"object": "purchase",
"livemode": true,
"custom_id": "wd-77",
"status": "waiting_accept",
"game": "",
"item_name": "AK-47 | Redline (Field-Tested)",
"item_id": null,
"steam_id": null,
"max_price_usd": 30,
"price_usd": 25.63,
"fee_usd": 0,
"charged_usd": 25.63,
"refunded_usd": 0,
"trade_offer_id": null,
"error_reason": null,
"created_at": 1793920000,
"updated_at": 1793920000
}
/purchases
List purchases
Parameters
statusquery · string |
Filter by status.pendingunknowncreating_tradewaiting_acceptacceptedcanceledtimeoutinvalid_trade_tokenuser_not_tradabletrade_create_errorrollback_userrollback_supplierfailed |
custom_idquery · string |
Find by your reference. |
pagequery · integer |
Page, from 1. |
limitquery · integer |
Items per page, 1–100 (default 25). |
Request
curl 'https://skinplata.com/api/v1/purchases' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/purchases');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/purchases', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/purchases",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"id": "pur_1c2d3e4f5a6b7c8d9e0f1a2b",
"object": "purchase",
"livemode": true,
"custom_id": "wd-77",
"status": "waiting_accept",
"game": "",
"item_name": "AK-47 | Redline (Field-Tested)",
"item_id": null,
"steam_id": null,
"max_price_usd": 30,
"price_usd": 25.63,
"fee_usd": 0,
"charged_usd": 25.63,
"refunded_usd": 0,
"trade_offer_id": null,
"error_reason": null,
"created_at": 1793920000,
"updated_at": 1793920000
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
/purchases/{id}
Get a purchase
Parameters
id requiredpath · string |
Purchase id (pur_…). |
Request
curl 'https://skinplata.com/api/v1/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 404 not_found
{
"id": "pur_1c2d3e4f5a6b7c8d9e0f1a2b",
"object": "purchase",
"livemode": true,
"custom_id": "wd-77",
"status": "waiting_accept",
"game": "",
"item_name": "AK-47 | Redline (Field-Tested)",
"item_id": null,
"steam_id": null,
"max_price_usd": 30,
"price_usd": 25.63,
"fee_usd": 0,
"charged_usd": 25.63,
"refunded_usd": 0,
"trade_offer_id": null,
"error_reason": null,
"created_at": 1793920000,
"updated_at": 1793920000
}
Balance
Your project, its balance and every booking.
/status
Service status
Whether payments can be taken right now.
Request
curl 'https://skinplata.com/api/v1/status' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/status');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/status', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/status",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "status",
"livemode": true,
"operational": true,
"time": 1793920000
}
/project
Your project
Request
curl 'https://skinplata.com/api/v1/project' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/project');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/project', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/project",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"id": "",
"object": "project",
"livemode": true,
"name": "",
"website": "",
"status": "pending",
"live_enabled": true,
"deposit_fee_percent": 0.0,
"market_fee_percent": 0.0,
"default_game": "",
"default_currency": "",
"webhook_url": null,
"balance": {
"available_usd": 0.0,
"reserved_usd": 0.0
}
}
/balance
Balance
available can be spent or paid out; reserved is held for open purchases and payouts.
Request
curl 'https://skinplata.com/api/v1/balance' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/balance', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/balance",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "balance",
"livemode": true,
"currency": "usd",
"available": 1290.55,
"reserved": 95
}
/balance/history
Balance history
Every booking, newest first.
Parameters
typequery · string |
Filter by type.depositdeposit_reversalreservereleasepurchasepurchase_refundadjustmentpayouttest_credit |
pagequery · integer |
Page, from 1. |
limitquery · integer |
Items per page, 1–100 (default 25). |
Request
curl 'https://skinplata.com/api/v1/balance/history' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/balance/history');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/balance/history', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/balance/history",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"id": "le_118",
"object": "balance_entry",
"type": "deposit",
"amount": 0.0,
"balance_after": 0.0,
"reserved_after": 0.0,
"description": "",
"reference": null,
"created_at": 1793920000
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
Payouts
Payouts are requested in the dashboard; read them here.
/payouts
List payouts
Parameters
statusquery · string |
Filter by status.pendingpaidrejected |
pagequery · integer |
Page, from 1. |
limitquery · integer |
Items per page, 1–100 (default 25). |
Request
curl 'https://skinplata.com/api/v1/payouts' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/payouts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payouts', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/payouts",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200
{
"object": "list",
"livemode": true,
"data": [
{
"id": "po_4a5b6c7d8e9f0a1b2c3d4e5f",
"object": "payout",
"status": "pending",
"project": null,
"method": "crypto",
"destination": {
"id": null,
"label": null,
"summary": null
},
"amount_usd": 0.0,
"fee_usd": 0.0,
"net_usd": 0.0,
"reference": null,
"reason": null,
"created_at": 1793920000,
"completed_at": null
}
],
"page": 1,
"limit": 25,
"total": 1,
"has_more": false
}
/payouts/{id}
Get a payout
Parameters
id requiredpath · string |
Payout id (po_…). |
Request
curl 'https://skinplata.com/api/v1/payouts/po_4a5b6c7d8e9f0a1b2c3d4e5f' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret'<?php
$ch = curl_init('https://skinplata.com/api/v1/payouts/po_4a5b6c7d8e9f0a1b2c3d4e5f');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/payouts/po_4a5b6c7d8e9f0a1b2c3d4e5f', {
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.get(
"https://skinplata.com/api/v1/payouts/po_4a5b6c7d8e9f0a1b2c3d4e5f",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 404 not_found
{
"id": "po_4a5b6c7d8e9f0a1b2c3d4e5f",
"object": "payout",
"status": "pending",
"project": null,
"method": "crypto",
"destination": {
"id": null,
"label": null,
"summary": null
},
"amount_usd": 0.0,
"fee_usd": 0.0,
"net_usd": 0.0,
"reference": null,
"reason": null,
"created_at": 1793920000,
"completed_at": null
}
Webhooks
Check your endpoint.
/webhooks/test
Send a test.ping
Sends test.ping to the webhook URL of the project and returns the delivery with the answer your endpoint gave.
Request
curl -X POST 'https://skinplata.com/api/v1/webhooks/test' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{}'<?php
$ch = curl_init('https://skinplata.com/api/v1/webhooks/test');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/webhooks/test', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/webhooks/test",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json=[],
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 409 no_webhook_url
{
"id": "wh_9a8b7c6d5e4f3a2b1c0d9e8f",
"object": "webhook_delivery",
"livemode": true,
"type": "deposit.pending",
"url": "",
"status": "pending",
"attempts": 0,
"last_http_code": null,
"last_error": null,
"next_attempt_at": null,
"delivered_at": null,
"created_at": 1793920000
}
Test mode
Drive simulated payments and purchases (sk_test_ secret only).
/test/payments/{id}/simulate
Simulate a payment outcome
A payment nobody started yet first gets sample items sent. Same webhooks as live.
Parameters
id requiredpath · string |
Test payment id. |
Body application/json
outcome requiredstring |
in_holdhold_approvedsuccessfailhold_returnedexpired |
Request
curl -X POST 'https://skinplata.com/api/v1/test/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/simulate' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"outcome":"success"}'<?php
$ch = curl_init('https://skinplata.com/api/v1/test/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/simulate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'outcome' => 'success',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/test/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/simulate', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"outcome": "success"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/test/payments/dep_8f2c1a9b4e7d6c3f2a1b0c9d/simulate",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"outcome": "success"
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 403 test_mode_only409 invalid_transition
{
"id": "dep_8f2c1a9b4e7d6c3f2a1b0c9d",
"object": "payment",
"livemode": true,
"order_id": "inv-1042",
"status": "success",
"flow": "hosted",
"pay_url": "https://skinplata.com/pay/Xr2…",
"embed_url": "https://skinplata.com/pay/Xr2…?embed=1",
"game": "cs2",
"steam_id": "76561198000000042",
"currency": "usd",
"amount": 14.2,
"amount_usd": 14.2,
"fee_usd": 0,
"net_usd": 14.2,
"credited": true,
"min_amount": 5,
"max_amount": null,
"trade_offer_id": "7712345678",
"trade_offer_url": null,
"fail_reason": null,
"hold_until": 1794524800,
"items": [
{
"asset_id": "38271946512",
"name": "AK-47 | Redline (Field-Tested)",
"image": "https://community.akamai.steamstatic.com/economy/image/…",
"price": 14.2,
"price_usd": 14.2
}
],
"metadata": {},
"expires_at": null,
"created_at": 1793920000,
"updated_at": 1793920000,
"completed_at": null
}
/test/purchases/{id}/simulate
Simulate a purchase outcome
Parameters
id requiredpath · string |
Test purchase id. |
Body application/json
outcome requiredstring |
acceptedwaiting_acceptcanceledtimeoutrollback_usertrade_create_error |
Request
curl -X POST 'https://skinplata.com/api/v1/test/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b/simulate' \
-H 'X-Project-Key: pk_your_key' \
-H 'X-Project-Secret: sk_test_your_secret' \
-H 'Content-Type: application/json' \
-d '{"outcome":"canceled"}'<?php
$ch = curl_init('https://skinplata.com/api/v1/test/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b/simulate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'X-Project-Key: pk_your_key',
'X-Project-Secret: sk_test_your_secret',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'outcome' => 'canceled',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);const res = await fetch('https://skinplata.com/api/v1/test/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b/simulate', {
method: 'POST',
headers: {
'X-Project-Key': 'pk_your_key',
'X-Project-Secret': 'sk_test_your_secret',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"outcome": "canceled"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);import requests
r = requests.post(
"https://skinplata.com/api/v1/test/purchases/pur_1c2d3e4f5a6b7c8d9e0f1a2b/simulate",
headers={"X-Project-Key": "pk_your_key", "X-Project-Secret": "sk_test_your_secret"},
json={
"outcome": "canceled"
},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])Response 200 403 test_mode_only409 invalid_transition
{
"id": "pur_1c2d3e4f5a6b7c8d9e0f1a2b",
"object": "purchase",
"livemode": true,
"custom_id": "wd-77",
"status": "waiting_accept",
"game": "",
"item_name": "AK-47 | Redline (Field-Tested)",
"item_id": null,
"steam_id": null,
"max_price_usd": 30,
"price_usd": 25.63,
"fee_usd": 0,
"charged_usd": 25.63,
"refunded_usd": 0,
"trade_offer_id": null,
"error_reason": null,
"created_at": 1793920000,
"updated_at": 1793920000
}
Statuses
Payment
created | Awaiting customer |
pending | Offer sent |
in_hold | Trade protection |
hold_approved | Released early |
success | Paid |
fail | Failed |
hold_returned | Reversed |
expired | Expired |
Purchase
pending | Processing |
unknown | Checking |
creating_trade | Creating trade |
waiting_accept | Offer sent |
accepted | Delivered |
canceled | Declined |
timeout | Not accepted |
invalid_trade_token | Bad trade link |
user_not_tradable | Customer cannot trade |
trade_create_error | Trade failed |
rollback_user | Returned by customer |
rollback_supplier | Returned by seller |
failed | Failed |