Выберите язык и используйте готовые фрагменты для создания оплаты и приёма уведомлений.
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/create-subscription-checkout', async (req, res) => {
const response = await fetch('https://afinapay.ru/sdk/subscriptions/checkout-sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.AFINAPAY_TOKEN}`
},
body: JSON.stringify({
externalPlan: {
externalPlanKey: 'premium_access',
name: 'Премиум-доступ',
amount: 990,
currency: 'RUB',
billingPeriod: 'month',
billingInterval: 1
},
externalOrderId: req.body.orderId,
externalCustomerId: req.body.customerId,
merchantReturnUrl: 'myapp://payments/subscription-result'
})
});
const checkout = await response.json();
res.status(response.status).json(checkout);
});
import Foundation
struct CheckoutRequest: Encodable {
let externalPlan: ExternalPlan
let externalOrderId: String
let externalCustomerId: String
let merchantReturnUrl: String
}
struct ExternalPlan: Encodable {
let externalPlanKey: String
let name: String
let amount: Int
let currency: String
let billingPeriod: String
let billingInterval: Int
}
var request = URLRequest(url: URL(string: "https://afinapay.ru/sdk/subscriptions/checkout-sessions")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(ProcessInfo.processInfo.environment["AFINAPAY_TOKEN"] ?? "")", forHTTPHeaderField: "Authorization")
request.httpBody = try JSONEncoder().encode(
CheckoutRequest(
externalPlan: ExternalPlan(
externalPlanKey: "premium_access",
name: "Премиум-доступ",
amount: 990,
currency: "RUB",
billingPeriod: "month",
billingInterval: 1
),
externalOrderId: orderId,
externalCustomerId: customerId,
merchantReturnUrl: "myapp://payments/subscription-result"
)
)
let (data, response) = try await URLSession.shared.data(for: request)
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
val body = """
{
"externalPlan": {
"externalPlanKey": "premium_access",
"name": "Премиум-доступ",
"amount": 990,
"currency": "RUB",
"billingPeriod": "month",
"billingInterval": 1
},
"externalOrderId": "$orderId",
"externalCustomerId": "$customerId",
"merchantReturnUrl": "myapp://payments/subscription-result"
}
""".trimIndent()
val request = Request.Builder()
.url("https://afinapay.ru/sdk/subscriptions/checkout-sessions")
.addHeader("Authorization", "Bearer ${System.getenv("AFINAPAY_TOKEN")}")
.post(body.toRequestBody("application/json".toMediaType()))
.build()
val response = OkHttpClient().newCall(request).execute()
import os
import requests
payload = {
"externalPlan": {
"externalPlanKey": "premium_access",
"name": "Премиум-доступ",
"amount": 990,
"currency": "RUB",
"billingPeriod": "month",
"billingInterval": 1,
},
"externalOrderId": order_id,
"externalCustomerId": customer_id,
"merchantReturnUrl": "myapp://payments/subscription-result",
}
response = requests.post(
"https://afinapay.ru/sdk/subscriptions/checkout-sessions",
headers={
"Authorization": f"Bearer {os.environ['AFINAPAY_TOKEN']}",
"Content-Type": "application/json",
},
json=payload,
timeout=15,
)
checkout = response.json()
<?php
$payload = [
'externalPlan' => [
'externalPlanKey' => 'premium_access',
'name' => 'Премиум-доступ',
'amount' => 990,
'currency' => 'RUB',
'billingPeriod' => 'month',
'billingInterval' => 1,
],
'externalOrderId' => $orderId,
'externalCustomerId' => $customerId,
'merchantReturnUrl' => 'myapp://payments/subscription-result',
];
$ch = curl_init('https://afinapay.ru/sdk/subscriptions/checkout-sessions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('AFINAPAY_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$checkout = json_decode($body, true);
import crypto from 'node:crypto';
app.post('/api/webhooks/afinapay', express.text({ type: '*/*' }), (req, res) => {
const signatureHeader = req.header('x-afinapay-signature') ?? '';
const timestamp = req.header('x-afinapay-signature-timestamp') ?? '';
const signature = signatureHeader.startsWith('v1=') ? signatureHeader.slice(3) : '';
const expected = crypto
.createHmac('sha256', process.env.AFINAPAY_WEBHOOK_SECRET ?? '')
.update(`${timestamp}.${req.body}`, 'utf8')
.digest('hex');
if (!signature || signature !== expected) {
res.status(401).json({ error: 'invalid signature' });
return;
}
const event = JSON.parse(req.body);
if (event.type === 'subscription.activated') {
// Откройте доступ пользователю на своей серверной стороне.
}
res.json({ ok: true });
});
import CryptoKit
import Foundation
func verifyAfinapayWebhook(rawBody: String, timestamp: String, signatureHeader: String, secret: String) -> Bool {
guard signatureHeader.hasPrefix("v1=") else { return false }
let signature = String(signatureHeader.dropFirst(3))
let payload = Data("\(timestamp).\(rawBody)".utf8)
let key = SymmetricKey(data: Data(secret.utf8))
let digest = HMAC<SHA256>.authenticationCode(for: payload, using: key)
let expected = digest.map { String(format: "%02x", $0) }.joined()
return signature == expected
}
if event.type == "subscription.activated" {
// Откройте доступ пользователю на своей серверной стороне.
}
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
fun verifyAfinapayWebhook(rawBody: String, timestamp: String, signatureHeader: String, secret: String): Boolean {
if (!signatureHeader.startsWith("v1=")) return false
val signature = signatureHeader.removePrefix("v1=")
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(secret.toByteArray(), "HmacSHA256"))
val expected = mac.doFinal("$timestamp.$rawBody".toByteArray()).joinToString("") { "%02x".format(it) }
return signature == expected
}
if (event.type == "subscription.activated") {
// Откройте доступ пользователю на своей серверной стороне.
}
import hashlib
import hmac
import json
import os
def verify_afinapay_webhook(raw_body: str, timestamp: str, signature_header: str) -> bool:
if not signature_header.startswith("v1="):
return False
signature = signature_header[3:]
payload = f"{timestamp}.{raw_body}".encode("utf-8")
expected = hmac.new(
os.environ["AFINAPAY_WEBHOOK_SECRET"].encode("utf-8"),
payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
event = json.loads(raw_body)
if event["type"] == "subscription.activated":
# Откройте доступ пользователю на своей серверной стороне.
pass
<?php
function verifyAfinapayWebhook(string $rawBody, string $timestamp, string $signatureHeader, string $secret): bool
{
if (!str_starts_with($signatureHeader, 'v1=')) {
return false;
}
$signature = substr($signatureHeader, 3);
$expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
return hash_equals($expected, $signature);
}
$event = json_decode($rawBody, true);
if (($event['type'] ?? null) === 'subscription.activated') {
// Откройте доступ пользователю на своей серверной стороне.
}