CardHook API
Versiya: v1 Oxirgi yangilanish: 2026-09-22
CardHook — Humo va Uzcard kartalariga kelgan o'tkazmalarni avtomatik aniqlab, ularni buyurtmalaringizga bog'laydigan servis. Bu hujjat integratsiya uchun kerak bo'ladigan hamma narsani o'z ichiga oladi.
1. Muammo va yechim
Karta o'tkazmasi hech qanday buyurtma raqamini olib kelmaydi. Bankdan faqat shunday xabar keladi:
HUMO *0268 Popolnenie 24 017.00 UZS Balans: 1 250 000.00 UZS
Bu yerda buyurtma raqami yo'q. Kim to'laganini, qaysi buyurtma uchun to'laganini aniqlashning yagona ishonchli yo'li — noyob summa.
1. Platforma 24 000 so'mlik hisob so'raydi 2. CardHook 24 017 so'm qaytaradi <- oxirgi 2 raqam noyob 3. Mijoz aynan 24 017 o'tkazadi 4. Bank xabari keladi 5. Shu summani kutayotgan yagona hisob topiladi 6. Platformaga imzolangan callback ketadi
Qo'shimcha summa 0 dan 99 so'mgacha — mijoz uchun sezilmaydi, lekin ayni paytda kutilayotgan hisoblar orasida takrorlanmaydi.
Noyoblik qanday kafolatlanadi
Ikki qatlam:
- Kod qatlami — hisob yaratilganda band summalar o'qiladi va bo'shi
tanlanadi.
- Baza qatlami —
UNIQUE(pay_amount) WHERE status='pending'qisman
indeksi. Ikkita so'rov bir vaqtda kelsa ham baza ikkinchisini rad etadi va kod keyingi bo'sh summaga o'tadi.
Shu summa uchun barcha 100 variant band bo'lsa, no_free_amount xatosi qaytadi. Bu vaqtinchalik holat: eski hisoblar muddati tugagach summalar bo'shaydi.
Noaniqlikda taxmin yo'q
Agar bitta summaga ikkita hisob to'g'ri kelsa, CardHook hech birini avtomatik tasdiqlamaydi — tushum adminga qo'lda hal qilish uchun boradi. Bu tizimning eng muhim qoidasi: noto'g'ri buyurtmani yopgandan ko'ra, qo'lda tekshirgan afzal.
2. Boshlash
2.1. Nima kerak
API_KEY | so'rovlarni imzolash uchun (pbx_ bilan boshlanadi) |
CALLBACK_SECRET | callback imzosini tekshirish uchun |
callback_url | to'lov tasdiqlanganda CardHook murojaat qiladigan manzil |
Ikkalasini ham biznes panelidan olasiz: panel.cardhook.uz → API kalitlari.
| Qayta ko'rish mumkinmi | Nega | |
|---|---|---|
API_KEY | yo'q | serverda faqat sha256 hash saqlanadi. Yo'qotsangiz «yangi kalit» tugmasi bilan yangisini olasiz — eskisi shu zahoti ishlamay qoladi. |
CALLBACK_SECRET | ha | imzo hisoblashda kerak, shuning uchun ochiq saqlanadi. «Ko'rsatish» tugmasi bilan istalgan vaqtda olasiz. |
Maxfiy so'z oshkor bo'lsa — «yangi maxfiy so'z» tugmasi. Diqqat: yangilagan zahoti eski maxfiy so'z bilan imzolangan, hali yetkazilmagan callbacklar ham tekshiruvdan o'tmay qoladi.
2.2. Base URL
| Manzil | Qachon ishlatiladi |
|---|---|
http://127.0.0.1:8080 | platforma CardHook bilan bir serverda bo'lsa |
https://api.cardhook.uz | platforma boshqa serverda bo'lsa |
api.cardhook.uz istalgan manzildan ochiladi — IP ro'yxati yo'q. Autentifikatsiya butunlay API_KEY bo'yicha: kalitsiz yoki noto'g'ri kalit bilan 401 qaytadi. Shuning uchun kalitni sir saqlash MUHIM: u oshkor bo'lsa, istalgan joydan ishlatilishi mumkin. Oshkor bo'lsa panelda darhol yangilang.
Bir serverdagi platformalar uchun 127.0.0.1 afzal: tezroq, TLS va DNS ortiqcha yuki yo'q.
2.3. Autentifikatsiya
Har bir /v1/* so'rovda:
Authorization: Bearer pbx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Kalit sarlavhada uzatiladi, so'rov manzilida emas — aks holda u nginx loglariga, proxy loglariga va brauzer tarixiga tushadi.
Kalit noto'g'ri, yo'q yoki platforma bloklangan bo'lsa — 401 unauthorized.
2.4. Pul birligi
API'da summalar so'mda, butun son:
{ "amount": 24000, "pay_amount": 24017 }Ichkarida hammasi tiyinda (int) saqlanadi, float umuman ishlatilmaydi — yaxlitlash xatosi to'lovda qabul qilinmaydi.
Kasr summalar qo'llab-quvvatlanmaydi. 24000.50 yuborsangiz invalid_amount qaytadi.
2.5. Vaqt formati
Barcha vaqtlar UTC, ISO 8601:
2026-09-21T10:30:00Z
Server vaqt zonasi (O'zbekistonda UTC+5) API javoblariga ta'sir qilmaydi. Foydalanuvchiga ko'rsatishda 5 soat qo'shing.
3. Hisob yaratish
POST /v1/invoices Authorization: Bearer pbx_xxxxxxxx Content-Type: application/json
So'rov
{
"external_id": "order-123",
"amount": 24000,
"callback_url": "https://star.uz/cardhook/callback",
"expires_in": 1800,
"description": "100 Stars"
}| Maydon | Tur | Majburiy | Izoh |
|---|---|---|---|
external_id | string | ha | sizning buyurtma raqamingiz, 1–120 belgi |
amount | integer | ha | so'mda, 1 000 – 100 000 000 |
callback_url | string | yo'q | http:// yoki https://. Berilmasa callback yuborilmaydi |
expires_in | integer | yo'q | soniya, 60 – 86400. Default: 1800 (30 daqiqa) |
description | string | yo'q | 255 belgigacha, faqat sizning panelingizda ko'rinadi |
Javob — 201 Created
{
"invoice_id": "inv_9f2a4c1b8e7d3a56",
"external_id": "order-123",
"amount": 24000,
"pay_amount": 24017,
"card": {
"number": "9860 1701 1203 0268",
"holder": "ISM FAMILIYA",
"bank": "HUMO"
},
"status": "pending",
"description": "100 Stars",
"expires_at": "2026-09-21T10:30:00Z",
"paid_at": null,
"created_at": "2026-09-21T10:00:00Z"
}| Maydon | Izoh |
|---|---|
invoice_id | CardHook bergan identifikator, inv_ + 16 hex belgi |
amount | siz so'ragan summa |
pay_amount | mijozga ko'rsatiladigan summa — aynan shu to'lanishi kerak |
card | mijoz pul o'tkazadigan karta |
status | pending · paid · expired · cancelled |
expires_at | shundan keyin hisob expired bo'ladi va summa bo'shaydi |
paid_at | to'langan vaqt, pending holatda null |
Idempotentlik
Bir xil external_id bilan qayta so'ralsa yangi hisob yaratilmaydi — mavjudi 200 OK bilan qaytadi (201 emas).
Bu tarmoq uzilishidan himoya qiladi: javob yo'lda yo'qolsa, so'rovni xavfsiz takrorlaysiz va o'sha hisobni olasiz.
1-so'rov external_id=order-123 -> 201 pay_amount 24017 2-so'rov external_id=order-123 -> 200 pay_amount 24017 (o'sha hisob)
Diqqat: takroriy so'rovda amount boshqacha bo'lsa ham e'tiborga olinmaydi — mavjud hisob o'z summasi bilan qaytadi. Boshqa summa kerak bo'lsa boshqa external_id ishlating.
external_id faqat sizning platformangiz ichida noyob bo'lishi kerak. Turli platformalar bir xil external_id ishlatishi mumkin.
Xatolar
| HTTP | Kod | Sabab |
|---|---|---|
| 400 | invalid_amount | butun son emas, chegaradan tashqarida yoki bool |
| 400 | invalid_request | external_id bo'sh, JSON buzuq, expires_in noto'g'ri, callback_url http(s) emas |
| 401 | unauthorized | kalit yo'q / noto'g'ri / platforma bloklangan |
| 409 | no_free_amount | shu summa uchun 100 ta variant ham band |
| 429 | rate_limited | daqiqalik limitdan oshdi |
| 503 | no_active_card | faol karta yo'q yoki kunlik limit to'lgan |
4. Hisobni olish
4.1. ID bo'yicha
GET /v1/invoices/inv_9f2a4c1b8e7d3a56 Authorization: Bearer pbx_xxxxxxxx
Javob — 3-bo'limdagi bilan bir xil obyekt.
4.2. O'z raqamingiz bo'yicha
GET /v1/invoices?external_id=order-123 Authorization: Bearer pbx_xxxxxxxx
invoice_id ni saqlamagan bo'lsangiz qulay.
Xatolar
| HTTP | Kod | Sabab |
|---|---|---|
| 400 | invalid_request | external_id parametri berilmagan |
| 401 | unauthorized | kalit muammosi |
| 404 | not_found | hisob yo'q yoki boshqa platformaniki |
Boshqa platformaning hisobi ham 404 qaytaradi — 403 emas. Ya'ni mavjudligi ham oshkor qilinmaydi.
5. Hisobni bekor qilish
POST /v1/invoices/inv_9f2a4c1b8e7d3a56/cancel Authorization: Bearer pbx_xxxxxxxx
Faqat pending holatdagi hisob bekor qilinadi. Bekor qilingach uning pay_amount summasi darhol bo'shaydi va boshqa hisobga berilishi mumkin.
Javob — hisob obyekti, status: "cancelled".
Xatolar
| HTTP | Kod | Sabab |
|---|---|---|
| 404 | not_found | hisob yo'q yoki boshqa platformaniki |
| 409 | already_paid | hisob allaqachon to'langan |
expired yoki cancelled hisobni bekor qilish xato emas — hisob o'z holatida qaytadi.
6. Callback
To'lov aniqlangach CardHook sizning callback_url manzilingizga POST yuboradi.
Callback qaysi manzildan keladi:
| Manba IP | 138.249.7.47 |
User-Agent | PayBox/1.0 |
| Metod | POST, Content-Type: application/json |
Xohlasangiz o'z tarafingizda shu IP dan boshqasini rad etishingiz mumkin — lekin bu imzo tekshirish o'rnini bosmaydi. IP ni soxtalashtirish mumkin, imzoni esa yo'q. Imzo har doim tekshirilsin, IP filtri faqat qo'shimcha qatlam.
Agar proxy (Cloudflare, nginx) orqali qabul qilsangiz, haqiqiy IP X-Forwarded-For sarlavhasida bo'ladi.
POST /cardhook/callback
X-Signature: sha256=9b1f2c...
X-Timestamp: 1790000000
Content-Type: application/json
User-Agent: PayBox/1.0
{"invoice_id":"inv_9f2a4c1b8e7d3a56","external_id":"order-123","amount":24000,"paid_amount":24017,"paid_at":"2026-09-21T10:12:03Z","status":"paid"}| Maydon | Izoh |
|---|---|
invoice_id | CardHook identifikatori |
external_id | sizning buyurtma raqamingiz |
amount | siz so'ragan summa |
paid_amount | mijoz haqiqatan o'tkazgan summa (noyob qo'shimcha bilan) |
paid_at | to'lov tasdiqlangan vaqt, UTC |
status | hozircha faqat paid |
6.1. Imzoni tekshirish — MAJBURIY
HMAC_SHA256(callback_secret, timestamp + "." + raw_body)
Imzo aynan yuborilgan baytlar ustidan hisoblanadi. JSON'ni qayta serializatsiya qilmang — bo'sh joy yoki maydon tartibi o'zgarsa imzo mos kelmaydi.
Imzo tekshirilmasa, istalgan odam sizning manzilingizga "to'landi" deb POST yuborishi mumkin.
Python (aiohttp):
import hashlib
import hmac
import json
import time
SECRET = "sizning_callback_secret"
def verify(raw_body: bytes, timestamp: str, signature: str) -> bool:
# Eski so'rovlarni rad etamiz (replay himoyasi)
try:
if abs(time.time() - int(timestamp)) > 300:
return False
except (TypeError, ValueError):
return False
expected = "sha256=" + hmac.new(
SECRET.encode(),
timestamp.encode() + b"." + raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
async def handle_callback(request):
raw = await request.read()
if not verify(
raw,
request.headers.get("X-Timestamp", ""),
request.headers.get("X-Signature", ""),
):
return web.Response(status=403)
data = json.loads(raw)
# Idempotentlik - eng muhim qism
if await already_processed(data["invoice_id"]):
return web.Response(text="ok")
await deliver_order(data["external_id"])
await mark_processed(data["invoice_id"])
return web.Response(text="ok") # 2xx bo'lishi SHARTNode.js (Express):
const crypto = require("crypto");
const SECRET = process.env.CARDHOOK_SECRET;
// raw body kerak - express.json() dan OLDIN
app.post(
"/cardhook/callback",
express.raw({ type: "application/json" }),
async (req, res) => {
const ts = req.get("X-Timestamp") || "";
const sig = req.get("X-Signature") || "";
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
return res.sendStatus(403);
}
const expected =
"sha256=" +
crypto
.createHmac("sha256", SECRET)
.update(Buffer.concat([Buffer.from(ts + "."), req.body]))
.digest("hex");
const ok =
sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
if (!ok) return res.sendStatus(403);
const data = JSON.parse(req.body.toString());
if (await alreadyProcessed(data.invoice_id)) return res.send("ok");
await deliverOrder(data.external_id);
await markProcessed(data.invoice_id);
res.send("ok");
}
);PHP:
<?php
$secret = getenv('CARDHOOK_SECRET');
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
if (abs(time() - (int)$ts) > 300) {
http_response_code(403);
exit;
}
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (!hash_equals($expected, $sig)) {
http_response_code(403);
exit;
}
$data = json_decode($raw, true);
if (alreadyProcessed($data['invoice_id'])) {
echo 'ok';
exit;
}
deliverOrder($data['external_id']);
markProcessed($data['invoice_id']);
echo 'ok';6.2. Qayta urinishlar
Javobingiz 2xx bo'lmasa (yoki umuman kelmasa), CardHook qayta uradi:
| Urinish | Qachon |
|---|---|
| 1 | darhol |
| 2 | 5 soniyadan keyin |
| 3 | 30 soniyadan keyin |
| 4 | 2 daqiqadan keyin |
| 5 | 10 daqiqadan keyin |
| 6 | 1 soatdan keyin |
Jami 6 urinish, taxminan 1 soat 13 daqiqa. Shundan keyin ham yetkazilmasa — CardHook admini Telegram orqali ogohlantiriladi va callback gave_up holatiga o'tadi.
So'rov kutish muddati — 15 soniya. Javobingiz shundan sekin bo'lsa urinish muvaffaqiyatsiz hisoblanadi.
Tavsiya: callback'ni tez qaytaring. Og'ir ishni (buyurtma yetkazish, xabar yuborish) fon vazifasiga qo'ying, 2xx ni darhol bering.
6.3. Idempotentlik — MAJBURIY
Callback takrorlanishi mumkin. Masalan javobingiz yo'lda yo'qolsa, CardHook uni yetkazilmagan deb hisoblab qayta yuboradi.
Shuning uchun qabul qiluvchi tomon invoice_id bo'yicha idempotent bo'lishi shart: bitta invoice_id uchun buyurtma faqat bir marta bajarilsin.
Eng oddiy yo'l — bazada processed_callbacks(invoice_id) jadvali va unda UNIQUE indeks.
6.4. Yetkazilmagan callbackni qayta yuborish
6 urinish tugagach callback to'xtaydi va avtomatik qayta yuborilmaydi. Agar platformangiz uzoq vaqt o'chiq turgan bo'lsa, biznes panelidagi Callbacklar bo'limiga kiring: har bir yetkazilmagan xabar yonida «qayta yuborish» tugmasi bor.
Bu muhim: hisob CardHook'da paid bo'lib turadi, lekin sizning platformangiz bu haqda bilmaydi — mijoz pul to'lagan, buyurtma esa bajarilmagan. Qayta yuborish shu holatdan chiqishning yagona yo'li.
Panelda holatlar:
| Holat | Ma'nosi |
|---|---|
yetkazildi | sizning serveringiz 2xx qaytardi |
urinilmoqda | urinishlar davom etmoqda |
yetkazilmadi | 6 urinish tugadi — qo'lda qayta yuborish kerak |
6.5. Callback kelmasa nima qilish kerak
Callback — qulaylik, yagona haqiqat manbai emas. Tarmoq muammosi bo'lishi mumkin. Shuning uchun:
- muhim buyurtmalar uchun
GET /v1/invoices/{id}bilan davriy tekshiring
(masalan har 30 soniyada, hisob muddati tugagunicha);
- yoki mijoz "To'ladim" tugmasini bosganda holatni so'rang.
Ikkalasi ham idempotent bo'lgani uchun callback bilan to'qnashmaydi.
7. Hisob holatlari
to'lov aniqlandi
pending ─────────────────────────> paid
│
├── expires_at o'tdi ─────────> expired
│
└── /cancel ──────────────────> cancelled| Holat | Ma'nosi |
|---|---|
pending | to'lov kutilmoqda, pay_amount band |
paid | to'lov aniqlandi va tasdiqlandi |
expired | muddati o'tdi, summa bo'shadi |
cancelled | siz bekor qildingiz, summa bo'shadi |
paid — yakuniy holat. Hisob pending dan paid ga faqat bir marta o'tadi: bu baza darajasidagi shartli UPDATE bilan kafolatlangan, ya'ni ikkita xabar bir vaqtda kelsa ham bitta to'lov ikki marta hisoblanmaydi.
8. Cheklovlar
| Cheklov | Qiymat | Oshsa |
|---|---|---|
| So'rovlar | 60 / daqiqa (har platforma uchun) | 429 rate_limited |
| Summa | 1 000 – 100 000 000 so'm | 400 invalid_amount |
| Hisob muddati | 60 – 86 400 soniya | 400 invalid_request |
| Bitta summa uchun faol hisoblar | 100 ta | 409 no_free_amount |
| So'rov tanasi | 64 KB | 413 |
external_id | 120 belgi | 400 invalid_request |
description | 255 belgi | kesiladi |
Qabul qilinmaydigan holatlar
- Qisman to'lov. Hisob to'liq to'lanadi yoki umuman to'lanmaydi.
Bir nechta o'tkazmani bitta hisobga yig'ish qo'llab-quvvatlanmaydi.
- "Taxminan to'g'ri" summa. 1 so'm farq ham rad etiladi — aks holda
noyob summa mexanizmining ma'nosi yo'qoladi.
- Mijozning karta ma'lumotlari. CardHook hech qachon PAN yoki CVV
so'ramaydi va saqlamaydi. U faqat o'z kartasiga kelgan o'tkazmani kutadi.
9. Xatolar
Barcha xatolar bir xil shaklda:
{
"error": {
"code": "no_free_amount",
"message": "Bu summa uchun bo'sh noyob qiymat qolmadi, birozdan keyin urinib ko'ring"
}
}Kodga qarab ish tuting, message ga emas — u o'zgarishi mumkin.
| HTTP | Kod | Nima qilish kerak |
|---|---|---|
| 400 | invalid_amount | summani tekshiring: butun son, chegarada |
| 400 | invalid_request | so'rov maydonlarini tekshiring |
| 401 | unauthorized | kalitni tekshiring; bloklangan bo'lsa adminga murojaat |
| 403 | forbidden | panel API sida: bu amalga ruxsatingiz yo'q |
| 404 | not_found | invoice_id yoki external_id noto'g'ri |
| 409 | already_paid | to'langan hisobni bekor qilib bo'lmaydi |
| 409 | no_free_amount | 2–3 soniyadan keyin qayta urinib ko'ring |
| 429 | rate_limited | so'rovlar tezligini kamaytiring |
| 500 | internal_error | qayta urinib ko'ring; takrorlansa adminga xabar bering |
| 503 | no_active_card | adminga xabar bering — karta o'chirilgan yoki limiti to'lgan |
Qayta urinish tavsiyalari
| Kod | Qayta urinsa bo'ladimi |
|---|---|
no_free_amount | ha — 2–3 soniyadan keyin |
rate_limited | ha — kutib turib |
internal_error | ha — orani ochib (exponential backoff) |
no_active_card | ha — lekin admin aralashuvi kerak |
invalid_*, unauthorized, not_found | yo'q — so'rovning o'zi noto'g'ri |
Qayta urinishda o'sha external_id ni ishlating — idempotentlik ikki marta hisob yaratilishiga yo'l qo'ymaydi.
10. To'liq integratsiya misoli
import os
import aiohttp
BASE = os.environ.get("CARDHOOK_URL", "http://127.0.0.1:8080")
KEY = os.environ["CARDHOOK_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
class CardHookError(Exception):
def __init__(self, code, message):
super().__init__(f"{code}: {message}")
self.code = code
async def create_invoice(session, order_id, amount_som, description=""):
"""Hisob yaratadi. Xato bo'lsa CardHookError."""
payload = {
"external_id": order_id,
"amount": amount_som,
"callback_url": "https://star.uz/cardhook/callback",
"expires_in": 1800,
"description": description,
}
async with session.post(
f"{BASE}/v1/invoices", json=payload, headers=HEADERS
) as resp:
data = await resp.json()
if resp.status not in (200, 201):
err = data.get("error", {})
raise CardHookError(err.get("code"), err.get("message"))
return data
async def get_invoice(session, invoice_id):
async with session.get(
f"{BASE}/v1/invoices/{invoice_id}", headers=HEADERS
) as resp:
if resp.status == 404:
return None
return await resp.json()
async def cancel_invoice(session, invoice_id):
async with session.post(
f"{BASE}/v1/invoices/{invoice_id}/cancel", headers=HEADERS
) as resp:
return await resp.json()
# --- Ishlatish ---
async def start_payment(order_id, amount):
async with aiohttp.ClientSession() as session:
invoice = await create_invoice(session, order_id, amount, "100 Stars")
# Mijozga AYNAN pay_amount ni ko'rsating
return (
f"To'lov summasi: {invoice['pay_amount']:,} so'm\n".replace(",", " ")
+ f"Karta: {invoice['card']['number']}\n"
+ f"{invoice['card']['holder']}\n\n"
+ "Aynan shu summani o'tkazing - 1 so'm farq ham qabul qilinmaydi."
)11. Mijozga nima ko'rsatish kerak
Bu joy integratsiyaning eng muhim qismi. Noyob summa mexanizmi faqat mijoz aynan o'sha summani o'tkazsagina ishlaydi.
Ko'rsatish shart:
pay_amount— katta va aniq,amountemas- karta raqami va egasining ismi
- "aynan shu summani o'tkazing" degan ogohlantirish
- qolgan vaqt (
expires_atgacha)
Namuna:
To'lov summasi 24 017 so'm <- pay_amount, amount emas aynan shu summani o'tkazing 1 so'm farq ham qabul qilinmaydi HUMO 9860 1701 1203 0268 ISM FAMILIYA Qoldi: 29:45
Mijoz 24 000 o'tkazsa, to'lov topilmaydi va qo'lda hal qilishga to'g'ri keladi. Shuning uchun summani yaxlitlash yoki "taxminan" deb ko'rsatish mumkin emas.
12. Sinov
Hozircha alohida test muhiti yo'q. Integratsiyani shunday sinang:
- Kichik summali hisob yarating (masalan 1 000 so'm)
- O'z kartangizdan aynan
pay_amountni o'tkazing - Callback kelganini va buyurtma bajarilganini tekshiring
- Bir xil
external_idbilan qayta so'rov yuboring —200va o'sha
hisob qaytishi kerak
- Callback'ni qasddan
500qaytaradigan qiling va qayta urinishlar
ishlaganiga ishonch hosil qiling
Imzo tekshirishni alohida sinash uchun:
import hashlib, hmac
secret = "sizning_secret"
ts = "1790000000"
body = b'{"invoice_id":"inv_test","status":"paid"}'
signature = "sha256=" + hmac.new(
secret.encode(), ts.encode() + b"." + body, hashlib.sha256
).hexdigest()
print(signature)13. Xavfsizlik
Sizning tomoningizda:
API_KEYvaCALLBACK_SECRETni muhit o'zgaruvchisida saqlang,
kodga yozmang, git'ga tushirmang
- callback imzosini har doim tekshiring
X-Timestampni tekshiring (5 daqiqadan eski so'rovlarni rad eting)- callback'ni faqat HTTPS orqali qabul qiling
- kalit oshkor bo'lsa panelda darhol yangilang
Platformangiz nimani ko'radi
| Ko'radi | Ko'rmaydi |
|---|---|
Qabul kartasining to'liq raqami va egasining ismi — hisob yaratish javobidagi card maydonida. Busiz mijozga qayerga pul o'tkazishni ayta olmaysiz. | Boshqa platformalarning hisoblari, to'lovlari, statistikasi |
| O'z hisoblaringiz va ularning holati | Kartaning kunlik limiti, bugungi aylanmasi |
| O'z callbacklaringiz | Bog'lanmagan (orphan) tushumlar |
Karta raqami sir emas: u mijozga baribir ko'rsatiladi. Sir bo'lgani — API_KEY va CALLBACK_SECRET.
Kartalarni boshqarish (qo'shish, o'chirish, loyihaga biriktirish) va noaniq tushumlarni qo'lda bog'lash API orqali umuman mumkin emas — bular faqat operator panelida bajariladi. Shu sababli bitta platformaning kaliti oshkor bo'lsa ham, u boshqa platformaning puliga yeta olmaydi va kartani o'chirib to'lovlarni to'xtata olmaydi.
CardHook tomonida:
- API kalitlari bazada
sha256hash ko'rinishida — ochiq matnda emas - kalitlar
secrets.token_urlsafe(32)bilan yaratiladi - loglarda karta raqami to'liq yozilmaydi, faqat oxirgi 4 raqam
- so'rovlar oqimi cheklangan (nginx va servis ichida, ikki qatlam)
- barcha pul o'tishlari atomik va idempotent
14. Tez-tez so'raladigan savollar
Mijoz noto'g'ri summa o'tkazsa nima bo'ladi?
To'lov hech qanday hisobga bog'lanmaydi va admin panelidagi "Noaniq to'lovlar" bo'limiga tushadi. Admin uni qo'lda kerakli hisobga bog'lashi mumkin — shundan keyin sizga odatdagi callback keladi.
Mijoz ikki marta to'lasa?
Birinchi to'lov hisobni yopadi, ikkinchisi noaniq to'lovlarga tushadi va admin ogohlantiriladi. CardHook avtomatik qaytarish qilmaydi.
Hisob muddati tugagandan keyin mijoz to'lasa?
To'lov noaniq to'lovlarga tushadi. Admin uni qo'lda bog'lashi mumkin.
Bitta buyurtma uchun ikkita hisob yaratsam bo'ladimi?
Ha, lekin har biriga boshqa external_id kerak. Eskisini /cancel bilan yopish tavsiya etiladi — shunda uning summasi bo'shaydi.
pay_amount ni o'zim tanlasam bo'ladimi?
Yo'q. Noyoblikni CardHook boshqaradi — aks holda ikkita hisob bir xil summa olishi va to'lovni bog'lab bo'lmay qolishi mumkin.
Bir nechta karta ishlatsam bo'ladimi?
Ha. Admin bir nechta karta qo'shishi mumkin, CardHook har hisob uchun kunlik limiti to'lmagan kartani tanlaydi. Qaysi karta tanlanganini javobdagi card maydonida ko'rasiz.
Callback nechta marta keladi?
Muvaffaqiyatli bo'lsa — bir marta. Javobingiz 2xx bo'lmasa 6 martagacha. Shuning uchun idempotentlik majburiy.
Valyuta faqat so'mmi?
Ha. Boshqa valyutalar qo'llab-quvvatlanmaydi.
15. Tez ma'lumotnoma
POST /v1/invoices hisob yaratish
GET /v1/invoices/{invoice_id} hisobni olish
GET /v1/invoices?external_id=... o'z raqami bo'yicha
POST /v1/invoices/{invoice_id}/cancel bekor qilish
Authorization: Bearer pbx_xxxxxxxx
Summalar: so'mda, butun son
Vaqtlar: UTC, ISO 8601 (...Z)
Holatlar: pending | paid | expired | cancelled
Callback imzosi:
HMAC_SHA256(callback_secret, timestamp + "." + raw_body)
X-Signature: sha256=<hex>
Qayta urinish: darhol, 5s, 30s, 2m, 10m, 1h (6 marta)
Rate limit: 60 so'rov / daqiqa16. Integratsiya ro'yxati
Ishga tushirishdan oldin tekshiring:
API_KEYvaCALLBACK_SECRETmuhit o'zgaruvchisida, kodda emas- Mijozga
pay_amountko'rsatiladi (amountemas) - "Aynan shu summani o'tkazing" ogohlantirishi bor
- Karta raqami va egasining ismi ko'rsatiladi
- Qolgan vaqt ko'rsatiladi
external_idhar buyurtma uchun noyob- Callback imzosi tekshiriladi
X-Timestamptekshiriladi (replay himoyasi)- Callback
invoice_idbo'yicha idempotent - Callback tez javob qaytaradi (og'ir ish fonga)
- Callback
2xxqaytaradi - Xatolar
codebo'yicha ishlanadi no_free_amountda qayta urinish bor- Zaxira sifatida
GET /v1/invoices/{id}tekshiruvi bor
CardHook v1 · Savollar bo'lsa admin bilan bog'laning.