API sənədləşməsi
E-Xezine vasitəsilə ödəniş qəbulu üçün developerə lazım olan hər şey: ödənişlərin yaradılması, vebhuklar, geri qaytarmalar, quraşdırılmış forma.
22.09.2026 tarixli redaksiya, API versiyası 2026-09-22
2026-09-22 versiyalı API üçün sənədləşmə. Baza ünvanı —
https://exezine.az/api/v2, maşın üçün təsvir —
openapi.json. Bütün metodlar üzrə interaktiv
arayış: açmaq.
Necə işləyir
- Serveriniz ödəniş yaradır:
POST /payments. - Cavabda
checkout_urlgəlir — bu bizim ödəniş səhifəmizdir. - Müştərini həmin ünvana yönləndirirsiniz (və ya öz saytınızda çərçivədə göstərirsiniz).
- Ödəniş bitəndə sizə vebhuk göndəririk:
payment.succeeded. - Müştərini sizin
return_urlünvanınıza qaytarırıq.
Siz yalnız E-Xezine ilə inteqrasiya edirsiniz. Ödənişi hansı ekvayrinq bankın emal etməsi bizim daxili məsələmizdir və istənilən an dəyişə bilər: ünvanlar, cavabın formatı və vebhuklar dəyişmir, kodunuz bunu hiss etmir.
Açarlar və avtorizasiya
Açarlar şəxsi kabinetdə, «API və vebhuklar» bölməsində verilir.
| Açar | Görünüşü | Nə edir |
|---|---|---|
| Canlı | exz_live_… | Real pul |
| Test | exz_test_… | Qum qutusu, pul yoxdur |
Açar yaradılarkən bir dəfə göstərilir. İtiribsinizsə — yenisini buraxın, köhnəsini ləğv edin. Hər sorğuda göndərilir:
Authorization: Bearer exz_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTest və canlı mühitlər tam ayrıdır: test açarı ilə canlı ödəniş tapılmayacaq
(404 qayıdacaq) və əksinə.
Açar — pula girişdir. O, yalnız sizin serverinizdə yaşayır. Heç vaxt onu sayt kodunda, mobil tətbiqdə və ya repozitoriyada saxlamayın.
Ümumi qaydalar
Məbləğlər — valyutanın minimal vahidlərində tam ədədlərdir.
10 manat = 1000, 25.50 = 2550. API-də ümumiyyətlə
onluq kəsrlər yoxdur — yuvarlaqlaşdırma səbəbindən bir qəpiklik səhv mümkün deyil.
Vaxt — RFC 3339 sətirləri: 2026-09-22T18:30:00+04:00.
Kodlaşdırma — UTF-8, sorğunun gövdəsi JSON,
Content-Type: application/json başlığı ilə. Hər cavabda
request_id var — dəstəyə yazanda onu göstərin.
Xətalar
Həmişə eyni zərf:
{
"error": {
"type": "invalid_request_error",
"code": "amount_invalid",
"message": "Məbləğ sıfırdan böyük tam ədəd olmalıdır",
"param": "amount"
},
"request_id": "req_4f2c9a1b8e0d3a71"
}message deyil, code əsas götürün: o sabitdir, mətn isə
dəyişə bilər və Accept-Language: ru | az | en başlığından asılıdır.
| HTTP | type | Nə vaxt |
|---|---|---|
| 400 | invalid_request_error | Yanlış JSON |
| 401 | authentication_error | Açar yoxdur, yanlışdır və ya ləğv edilib |
| 403 | authentication_error | Mağaza üçün API söndürülüb |
| 404 | invalid_request_error | Obyekt tapılmadı |
| 409 | invalid_request_error | Konflikt: idempotentlik, uyğun olmayan status |
| 422 | invalid_request_error | Sahənin dəyəri uyğun deyil |
| 429 | rate_limit_error | Həddindən çox sorğu |
| 5xx | api_error | Bizim tərəf və ya şlüz |
Sorğu tezliyinin limiti
Susmaya görə hər açar üçün dəqiqədə 120 sorğu. Cavabda həmişə:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118Aşıldıqda — 429 və saniyələrlə Retry-After.
Göstərilən qədər gözləyin və təkrarlayın; dövrə ilə döyəcləməyin.
İdempotentlik
Ödəniş, geri qaytarma və ya link yaradarkən başlıq göndərin:
Idempotency-Key: sizin istənilən unikal sətriniz- Eyni açar və eyni gövdə → birinci nəticəni və
Idempotent-Replayed: truebaşlığını qaytarırıq. İkiqat silinmə olmayacaq. - Eyni açar, başqa gövdə →
409 idempotency_conflict. - Açarlar bir sutka yaşayır.
Beləliklə şəbəkə qırılandan sonra sorğunu təkrarlamaq təhlükəsizdir: heç vaxt bir ödəniş əvəzinə iki ödəniş yaranmayacaq.
Ödəniş yaratmaq
POST /api/v2/payments{
"amount": 4990,
"currency": "AZN",
"order_id": "1024",
"description": "Sifariş №1024",
"method": "card",
"return_url": "https://shop.az/thanks",
"customer": {
"email": "buyer@example.com",
"name": "Aysel Məmmədova",
"phone": "+994501234567",
"ip": "85.132.1.1",
"country": "AZ",
"city": "Baku",
"address": "Nizami 10",
"zip": "AZ1000"
},
"metadata": { "cart": "17", "source": "mobile" },
"locale": "az"
}| Sahə | Vacib | Təsvir |
|---|---|---|
amount | bəli | Tam ədəd, minimal vahidlər |
currency | xeyr | Susmaya görə AZN; siyahını biz qoşuruq |
order_id | xeyr | Sizin sifariş nömrəniz. Sonra ona görə axtarmaq olar |
description | xeyr | 200 simvola qədər, müştəriyə görünür |
method | xeyr | card (susmaya görə) və ya sbp |
return_url | xeyr | Müştərini hara qaytarmalı. İctimai https:// |
customer.* | xeyr | Nə qədər dolğun olsa, 3-D Secure imtinaları bir o qədər az olar |
metadata | xeyr | 20 sahəyə və 4 KB-a qədər. Olduğu kimi qaytarırıq |
locale | xeyr | az / ru / en — ödəniş səhifəsinin dili |
customer haqqında. Emitent banklar 3-D Secure 2-də riski
məhz bu məlumatlara görə qiymətləndirir. Heç olmasa email,
ip və country göndərin — bu, imtinaların payını nəzərəçarpacaq
dərəcədə azaldır.
SBP haqqında. method: "sbp" yalnız
currency: "RUB" ilə işləyir. Başqa valyutada
422 method_not_available qayıdacaq.
Cavab 201
{
"id": "EXZ-20260922-7FD54BA1D8",
"object": "payment",
"livemode": true,
"status": "pending",
"amount": 4990,
"currency": "AZN",
"amount_refunded": 0,
"fee": 125,
"net": 4865,
"charged": null,
"order_id": "1024",
"description": "Sifariş №1024",
"metadata": { "cart": "17" },
"method": "card",
"customer": { "email": "buyer@example.com", "name": "Aysel", "phone": "" },
"card": null,
"failure": null,
"checkout_url": "https://exezine.az/checkout/EXZ-20260922-7FD54BA1D8",
"return_url": "https://shop.az/thanks",
"source": "api",
"created_at": "2026-09-22T18:30:00+04:00",
"paid_at": null,
"request_id": "req_c0ad2cf33ed31637"
}id — bizdəki ödənişin identifikatorudur. Onu sifarişin yanında saxlayın.
| Sahə | Mənası |
|---|---|
livemode | true — canlı ödəniş, false — qum qutusu |
fee | Bu ödəniş üzrə bizim komissiyamız |
net | Komissiyadan sonra sizə nə qədər çatacaq |
charged | Silinmə başqa valyutadadırsa — {"amount":…, "currency":"…"}, əks halda null |
amount_refunded | Artıq nə qədər geri qaytarılıb |
source | Ödəniş haradan: api, link, form, insales |
card | Ödənişdən sonra: {"brand":"visa","last4":"4242","country":"AZ"} |
paid_at | Ödəniş anı; ondan əvvəl — null |
Statuslar
| Status | Mənası |
|---|---|
pending | Yaradılıb, müştəri hələ ödəməyib |
succeeded | Ödənilib |
failed | İmtina, bax failure |
expired | Ödəniş müddəti bitib |
refunded | Tam geri qaytarılıb |
partially_refunded | Qismən geri qaytarılıb |
review | Bizdə yoxlanışdadır |
Yekun statuslar: succeeded, failed, expired,
refunded, partially_refunded.
İmtinanın səbəbi
"failure": { "code": "insufficient_funds", "message": "Kartda kifayət qədər vəsait yoxdur" }| code | Müştəriyə nə demək |
|---|---|
authentication_failed | Bank 3-D Secure təsdiqləmədi — yenidən cəhd edin |
insufficient_funds | Kifayət qədər vəsait yoxdur |
card_expired | Kartın etibarlılıq müddəti bitib |
limit_exceeded | Kart limiti aşılıb |
card_declined | Bank əməliyyatı rədd etdi |
expired | Ödəniş müddəti bitib, yeni ödəniş yaradın |
Statusu öyrənmək
GET /api/v2/payments/{id}curl -H "Authorization: Bearer $KEY" \
https://exezine.az/api/v2/payments/EXZ-20260922-7FD54BA1D8{id} — bizim EXZ-… və ya sizin
order_id (onda həmin nömrəli sonuncu ödəniş qayıdacaq).
Statusu dövrə ilə sorğulamaq nə lazımdır, nə də düzgündür — bunun üçün vebhuklar var. Sorğulamanın məqbul istifadəsi: müştəri saytınıza qayıdanda birdəfəlik yoxlama və «asılı qalmış» sifarişlər üzrə saatda bir tutuşdurma.
Ödənişlərin siyahısı
GET /api/v2/paymentsGET /api/v2/payments?limit=25&status=succeeded&order_id=1024| Parametr | Təsvir |
|---|---|
limit | 1–100, susmaya görə 25 |
status | Yuxarıdakı statuslardan istənilən biri |
order_id | Sizin sifariş nömrəniz |
from, to | Tarixlər YYYY-MM-DD və ya YYYY-MM-DD HH:MM |
starting_after | Növbəti səhifənin kursoru |
{
"object": "list",
"data": [ { "…ödəniş…" } ],
"has_more": true,
"next_cursor": "EXZ-20260922-11E5866313",
"request_id": "req_…"
}has_more true olduqca next_cursor dəyərini
starting_after kimi göndərin.
Geri qaytarma
POST /api/v2/payments/{id}/refunds{ "amount": 3000, "reason": "Müştəri maldan imtina etdi" }amount göstərilmədikdə qalığın tam məbləği qaytarılır.
{
"object": "refund_result",
"refund": {
"id": "ref_12",
"object": "refund",
"payment_id": "EXZ-20260922-7FD54BA1D8",
"amount": 3000,
"currency": "AZN",
"status": "succeeded",
"reason": "Müştəri maldan imtina etdi",
"created_at": "2026-09-22T19:05:00+04:00"
},
"payment": { "…yenilənmiş ödəniş…" },
"request_id": "req_…"
}Ödəniş üzrə geri qaytarmaların siyahısı: GET /api/v2/payments/{id}/refunds.
| Kod | Nə vaxt |
|---|---|
payment_not_payable | Ödəniş ödənilməyib — qaytarmağa bir şey yoxdur |
refund_amount_invalid | Məbləğ qalıqdan çoxdur |
refund_failed | Şlüz geri qaytarmanı qəbul etmədi |
Geri qaytarma da Idempotency-Key dəstəkləyir — mütləq istifadə edin.
Ödəniş linkləri
Sayt olmadıqda və ya hesab əl ilə verildikdə.
POST /api/v2/links{ "amount": 12000, "currency": "AZN", "description": "Hesab №77", "max_uses": 3, "expires_at": "2026-10-01" }| Sahə | Təsvir |
|---|---|
amount | Minimal vahidlərdə tam ədəd. Göstərməsəniz — məbləği ödəyən daxil edəcək |
currency | Susmaya görə mağazanın valyutası |
description | 200 simvola qədər |
max_uses | Link üzrə neçə dəfə ödəmək olar. Göstərməsəniz — məhdudiyyətsiz |
expires_at | Bu andan sonra link işləmir |
type | dynamic (susmaya görə) və ya static |
{
"id": "idP62kFt",
"object": "payment_link",
"url": "https://exezine.az/l/idP62kFt",
"amount": 12000,
"currency": "AZN",
"max_uses": 3,
"uses": 0,
"expires_at": null,
"active": true,
"created_at": "2026-09-22T19:10:00+04:00"
}Oxumaq: GET /api/v2/links/{id}.
Vebhuklar — nəticəni öyrənməyin əsas yolu
Ünvan və hadisələr kabinetdə qurulur: «API və vebhuklar».
| Hadisə | Nə vaxt |
|---|---|
payment.succeeded | Ödəniş keçdi |
payment.failed | İmtina |
payment.expired | Ödəniş müddəti bitdi |
refund.succeeded | Geri qaytarma keçdi |
Sizin ünvana POST{
"id": "evt_5f0f0c55264b546ecb1a3045",
"type": "payment.succeeded",
"api_version": "2026-09-22",
"livemode": true,
"created_at": "2026-09-22T18:45:00+04:00",
"data": { "object": { "…ödəniş…" } }
}refund.succeeded üçün data daxilində əlavə olaraq
refund da olur.
X-Exezine-Event: payment.succeeded
X-Exezine-Event-Id: evt_5f0f0c55264b546ecb1a3045
X-Exezine-Attempt: 1
X-Exezine-Signature: t=1790095200,v1=6c1f…a93İmzanın yoxlanması — mütləqdir
İmza "<t>.<sorğunun xam gövdəsi>" sətrindən HMAC-SHA256
alqoritmi ilə, kabinetdəki vebhuk sirriniz açar kimi istifadə olunmaqla hesablanır.
<?php
$secret = 'kabinetdən_sizin_sirriniz';
$body = file_get_contents('php://input'); // XAM gövdə, json_decode-dan əvvəl
$sig = $_SERVER['HTTP_X_EXEZINE_SIGNATURE'] ?? '';
if (!preg_match('~t=(\d+),v1=([a-f0-9]{64})~', $sig, $m)) {
http_response_code(400); exit;
}
$expected = hash_hmac('sha256', $m[1] . '.' . $body, $secret);
if (!hash_equals($expected, $m[2]) || abs(time() - (int) $m[1]) > 300) {
http_response_code(400); exit; // imza uyğun gəlmədi və ya gecikib
}
$event = json_decode($body, true);
// … sizin emalınız …
http_response_code(200);
echo 'OK';const crypto = require('crypto');
function verify(rawBody, header, secret) {
const m = /t=(\d+),v1=([a-f0-9]{64})/.exec(header || '');
if (!m) return false;
const expected = crypto.createHmac('sha256', secret)
.update(`${m[1]}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
return ok && Math.abs(Date.now() / 1000 - Number(m[1])) < 300;
}İmza xam gövdədən hesablanır. Freymvorkunuz JSON-u artıq
parçalayıbsa, məhz ilkin sətri götürün: yenidən yığılmış
JSON.stringify başqa baytlar verəcək və imza uyğun gəlməyəcək.
«İmza yoxlanmır» şikayətinin ən çox rast gəlinən səbəbi budur.
Emal qaydaları
- Tez
200cavab verin. Ağır işi fon növbəsinə salın. 2xx-dən fərqli istənilən cavab uğursuzluq sayılır. - Hadisə iki dəfə gələ bilər. Hadisənin
iddəyərini (evt_…) yadda saxlayın və təkrarları nəzərə almayın. - Təkrarlar. Uğursuzluqda 8 dəfə təkrarlayırıq: 1 dəq, 5 dəq, 30 dəq, 2 saat, 6 saat, 12 saat, 24 saat sonra. Sonra hadisə çatdırılmamış kimi işarələnir və kabinetdən düymə ilə yenidən göndərilə bilər.
- Ardıcıllığa zəmanət yoxdur. Gəliş sırasına deyil, gövdədəki
statusdəyərinə əsaslanın. - Pulu vebhuka görə hesablayın, müştərinin sayta qayıtmasına görə yox: müştəri vərəqi bağlaya bilər, ödəniş isə keçər.
Kabinetdə «Test hadisəsi göndər» düyməsi var — real imza ilə
test.ping gələcək. Canlı başlanğıcdan əvvəl qəbuledicini yoxlamaq üçün rahatdır.
Müştərinin sayta qaytarılması
Ödənişdən sonra müştərini sizin return_url ünvanınıza yönləndirir
və əlavə edirik:
https://shop.az/thanks?payment_id=EXZ-20260922-7FD54BA1D8&status=succeededBu parametrlər yalnız «Təşəkkür» səhifəsini göstərmək üçündür.
Sifarişi ödənilmiş saymaq yalnız vebhukdan və ya
GET /payments/{id} sorğusundan sonra olar: müştəri ünvan sətrini
redaktə edə bilər.
Quraşdırılmış forma
Müştəri sizin səhifənizdə qalır, kart forması isə bizim verdiyimiz çərçivədə açılır. Kart məlumatları sizin saytdan keçmir.
- Saytınızın domenlərini bizə bildirin — onları ağ siyahıya salacağıq, əks halda brauzer quraşdırmaya icazə verməyəcək.
- Səhifədə:
HTML + JS<div id="pay"></div>
<script src="https://exezine.az/assets/js/exezine-checkout.js"></script>
<script>
// checkout_url POST /api/v2/payments cavabında gəlib
ExezineCheckout.mount('#pay', {
url: payment.checkout_url,
onSuccess: function (p) { location.href = '/thanks?id=' + p.payment_id; },
onFailure: function (p) { alert('Ödəniş keçmədi'); }
});
</script>Çərçivə əvəzinə sadə keçid:
ExezineCheckout.redirect(payment.checkout_url);Bu skriptin verdiyi nəticə interfeys üçündür. Malı göndərmək və sifarişin statusunu dəyişmək — yalnız vebhuka görə.
Qoşulmanın ardıcıllığı
- Test açarı alın,
GET /api/v2/pingçağırın — əlaqəyə əmin olun. - Vebhuk ünvanını qurun, «Test hadisəsi göndər» düyməsini basın, imzanın uyğun gəlməsinə nail olun.
- Yaradılmadan
payment.succeededhadisəsinə qədər test ödənişi keçirin. - Eyni
Idempotency-Keyilə təkrar sorğunu yoxlayın. - Geri qaytarmanı yoxlayın — tam və qismən.
- Canlı açar alın və 3–5-ci bəndləri kiçik məbləğlə təkrarlayın.
- Test açarını canlı serverin tənzimləmələrindən silin.
Nə etmək lazım deyil
GET /payments/{id}sorğusunu dövrə ilə göndərmək — bunun üçün vebhuklar var.- Müştəri qayıdanda ünvan sətrindəki parametrlərə inanmaq.
- Açarı brauzerdə və ya mobil tətbiqdə saxlamaq.
Idempotency-Keyolmadan ödəniş göndərmək — şəbəkə qırılanda dublikat alacaqsınız.- Xətanın
messagemətnini təhlil etmək —codedəyərinə baxın.
| Əlamət | Səbəb |
|---|---|
| İmza heç cür uyğun gəlmir | Gövdə yoxlamadan əvvəl freymvork tərəfindən parçalanıb. Xam gövdə lazımdır |
| Məbləğlər 100 dəfə böyükdür | 4990 əvəzinə 49.90 göndərilib |
422 amount_invalid | Onluq kəsr göndərilib. API-də yalnız tam ədədlər var |
| Bir sifarişə iki ödəniş | Idempotency-Key yoxdur |
Mövcud ödənişə 404 | Canlı mühitdə test açarı və ya əksinə |
Dəstək
support@exezine.az ünvanına yazın.
Cavabdakı request_id dəyərini və vaxtı dəqiqəyə qədər göstərin —
belə olduqda sorğunu jurnalda dərhal tapırıq.
Cavab tapmadınız və ya nəsə yazıldığı kimi işləmir? Bizə yazın — konkret cavab veririk.
support@exezine.az