Exemplos completos para os principais stacks. Cole no seu projeto, troque a chave e está pronto.
// server.js — npm i express
import express from "express";
import crypto from "crypto";
const app = express();
const SKINPAY_KEY = process.env.SKINPAY_KEY;
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
// 1. Criar cobrança Pix
app.post("/checkout", express.json(), async (req, res) => {
const { amount, orderId } = req.body;
const r = await fetch("https://skinpay.pro/api/public/v1/charges", {
method: "POST",
headers: {
"x-api-key": SKINPAY_KEY,
"Content-Type": "application/json",
"Idempotency-Key": orderId,
},
body: JSON.stringify({
amount,
external_id: orderId,
description: `Pedido #${orderId}`,
expires_in: 3600,
}),
});
const { data } = await r.json();
res.json({
chargeId: data.id,
qrCode: data.pix_qr_code,
copyPaste: data.pix_copy_paste,
});
});
// 2. Receber webhook (Pix confirmado)
app.post("/webhook/skinpay", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-skinpay-signature"];
const [tsPart, v1Part] = sig.split(",");
const ts = tsPart.split("=")[1];
const v1 = v1Part.split("=")[1];
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(`${ts}.${req.body}`)
.digest("hex");
if (expected !== v1) return res.status(401).end();
const event = JSON.parse(req.body);
if (event.event === "charge.paid") {
console.log("Pix recebido:", event.data.external_id);
// libera o pedido no banco
}
res.status(200).end();
});
app.listen(3000);<?php
// checkout.php
$SKINPAY_KEY = getenv("SKINPAY_KEY");
$orderId = "pedido_" . time();
$amount = 9990; // R$ 99,90 em centavos
$payload = json_encode([
"amount" => $amount,
"external_id" => $orderId,
"description" => "Pedido #$orderId",
"expires_in" => 3600,
]);
$ch = curl_init("https://skinpay.pro/api/public/v1/charges");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
"x-api-key: $SKINPAY_KEY",
"Content-Type: application/json",
"Idempotency-Key: $orderId",
],
CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);
$data = $res["data"];
?>
<h2>Pague com Pix</h2>
<img src="<?= htmlspecialchars($data['pix_qr_code']) ?>" alt="QR Pix" />
<input type="text" readonly value="<?= htmlspecialchars($data['pix_copy_paste']) ?>" />
<?php
// webhook.php — receber confirmação
$WEBHOOK_SECRET = getenv("WEBHOOK_SECRET");
$body = file_get_contents("php://input");
$sig = $_SERVER["HTTP_X_SKINPAY_SIGNATURE"] ?? "";
[$tsPart, $v1Part] = explode(",", $sig);
$ts = explode("=", $tsPart)[1];
$v1 = explode("=", $v1Part)[1];
$expected = hash_hmac("sha256", "$ts.$body", $WEBHOOK_SECRET);
if (!hash_equals($expected, $v1)) { http_response_code(401); exit; }
$event = json_decode($body, true);
if ($event["event"] === "charge.paid") {
// libera pedido por external_id
}
http_response_code(200);# app.py — pip install flask requests
import os, hmac, hashlib, requests
from flask import Flask, request, jsonify
app = Flask(__name__)
SKINPAY_KEY = os.environ["SKINPAY_KEY"]
WEBHOOK_SECRET = os.environ["WEBHOOK_SECRET"]
@app.post("/checkout")
def checkout():
body = request.json
order_id = body["order_id"]
r = requests.post(
"https://skinpay.pro/api/public/v1/charges",
json={
"amount": body["amount"],
"external_id": order_id,
"description": f"Pedido #{order_id}",
"expires_in": 3600,
},
headers={
"x-api-key": SKINPAY_KEY,
"Idempotency-Key": order_id,
},
)
data = r.json()["data"]
return jsonify({
"qr": data["pix_qr_code"],
"copy_paste": data["pix_copy_paste"],
})
@app.post("/webhook/skinpay")
def webhook():
sig = request.headers.get("X-SkinPay-Signature", "")
ts_part, v1_part = sig.split(",")
ts = ts_part.split("=")[1]
v1 = v1_part.split("=")[1]
body = request.get_data(as_text=True)
expected = hmac.new(
WEBHOOK_SECRET.encode(),
f"{ts}.{body}".encode(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, v1):
return "", 401
event = request.json
if event["event"] == "charge.paid":
print("Pix confirmado:", event["data"]["external_id"])
return "", 200<!DOCTYPE html>
<html>
<head>
<title>Checkout Pix</title>
<style>
body { font-family: system-ui; max-width: 480px; margin: 40px auto; padding: 20px; }
img { width: 256px; }
input { width: 100%; padding: 8px; font-family: monospace; }
button { background: #00d68f; border: 0; padding: 12px 20px; border-radius: 8px; cursor: pointer; }
</style>
</head>
<body>
<h1>Pedido #<span id="order"></span></h1>
<p>Valor: <strong>R$ 99,90</strong></p>
<button onclick="gerarPix()">Pagar com Pix</button>
<div id="pix" style="display:none">
<img id="qr" />
<p>Ou copie:</p>
<input id="copy" readonly />
</div>
<script>
async function gerarPix() {
const orderId = "ped_" + Date.now();
document.getElementById("order").textContent = orderId;
const r = await fetch("/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ amount: 9990, orderId }),
});
const { qrCode, copyPaste } = await r.json();
document.getElementById("qr").src = qrCode;
document.getElementById("copy").value = copyPaste;
document.getElementById("pix").style.display = "block";
}
</script>
</body>
</html>