Буцаалт¶
Төлөгдсөн intent-ийн мөнгийг хүнд бүтнээр эсвэл хэсэгчлэн буцаана — нэг intent-д хэд ч удаа, нийлбэр нь төлсөн дүнгээс
хэтрэхгүй, төлбөрөөс хойш 90 хоногийн дотор. Уншихад ~5 минут. Хэрэгтэй: refunds:write scope-той API түлхүүр
(эсвэл mini app-ын хувьд хүний token), буцаалт бүрт шинэ Idempotency-Key.
Буцаах — POST /payment-intents/{id}/refunds¶
curl -sS https://geregeapp.mn/api/v1/miniapp/payment-intents/pi_4fQ2mX8kLp0aZr7TbN3cVw9E/refunds \
-u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET" \
-H "Idempotency-Key: refund-order-8812-1" \
-H "Content-Type: application/json" \
-d '{"amount": 10000, "reason": "supplier_failed"}'
| Талбар | Дүрэм |
|---|---|
amount |
заавал биш. Орхивол хараахан буцаагүй бүх дүн (amount − refunded_amount). Өгвөл ≥ 1; өмнөх буцаалтуудтай нийлээд төлсөн дүнгээс хэтэрвэл 400 validation_error (path amount) |
reason |
заавал биш, ≤ 255 тэмдэгт. Таны API, webhook, консолд харагдана; хүнд очих мэдэгдэлд хэзээ ч орохгүй |
Idempotency-Keyзаавал (1–128 хэвлэгдэх ASCII). Key нь intent дотроо өвөрмөц: ижил intent-д ижил key + ижил бие → эхний буцаалт (200); ижил key өөр биетэй →409 idempotency_conflict. Шинэ буцаалт = шинэ key.- Зөвхөн
succeededэсвэлpartially_refundedintent-ийг буцаана (бусад →409 not_refundable).requires_captureдээрх барьцааг буцаалт биш, cancel суллана. - Төлбөр амжилттай болсон (
confirmed_at) мөчөөс хойш 90 хоног өнгөрсөн бол →409 refund_window_expired.
Хариу ба төлөв¶
{
"id": "re_2kLm9Pq4Rs6Tu8Vw0Xy1Za3B",
"object": "refund",
"intent_id": "pi_4fQ2mX8kLp0aZr7TbN3cVw9E",
"amount": 10000,
"status": "succeeded",
"reason": "supplier_failed",
"failure_code": null,
"livemode": true,
"created_at": "2026-10-22T09:00:00Z"
}
| HTTP | Утга |
|---|---|
201 |
шинэ буцаалт, дуусгавар төлөвтэй — succeeded эсвэл failed (failure_code-ийг үз) |
202 |
pending — дэвтрийн хариу тодорхойгүй; платформ ижил key-ээр өөрөө дуусгана (минут тутмын reconcile job), үр дүн нь refund.succeeded / refund.failed webhook-оор ирнэ |
200 |
давталт (ижил key + ижил бие) — тэр буцаалт одоогийн төлвөөрөө |
status |
Утга |
|---|---|
pending |
мөнгө буцаагдаж байна. Энэ дүн refunded_amount-д аль хэдийн тоологдсон (хоёр дахь буцаалт түүнийг давхар амлахгүй) |
succeeded |
мөнгө хүний төлсөн дансанд буцсан |
failed |
буцаагдсангүй; дүн нь refunded_amount-аас хасагдана — засаад шинэ key-ээр дахин буцааж болно |
failed буцаалтын failure_code:
failure_code |
Утга, юу хийх |
|---|---|
insufficient_funds |
Мөнгө хүлээн авсан payout данс тэр мөнгийг аль хэдийн зарцуулсан. Дансаа цэнэглээд дахин буцаа |
settlement_shortfall |
Төлбөр тооцоонд орсон бөгөөд апп-ын клирингт буцаах хүрэлцээтэй мөнгө алга. Авлага (дараагийн тооцооноос суутгах) хараахан хийгдээгүй — оператор харна; операторт хандана уу |
refund_rejected |
Дэвтэр өөр шалтгаанаар татгалзав |
Амжилттай буцаалтын дараа intent-ийн status нь partially_refunded, бүх дүн буцсан бол refunded болно;
refunded_amount өснө. Intent-д тусдаа payment_intent.* event ирэхгүй — refund.* event л.
Мөнгө хаанаас буцах¶
Буцаалт нь capture-ийн мөнгө очсон газраас гарна (буцаалт үүсэх үед тогтоно):
- Тооцоо асаагүй апп (одоогийн бүх апп): мөнгө capture-ийн үед шууд апп-ын payout данс (эсвэл дэд худалдагчийн батлагдсан payout данс) руу орсон — буцаалт тэр данснаас гарна. Тиймээс дэд худалдагчийн payout-ыг батлахад эзэмшигч «буцаалтыг энэ данснаас хасна» гэсэн нөхцөлийг зөвшөөрдөг (Payout данс).
- Тооцоо асаалттай апп: төлбөр апп-ын клирингт байна — буцаалт клирингээс гарна. Аль хэдийн тооцоонд орж payout
руу шилжсэн төлбөрийн буцаалт дараагийн төлбөрүүдийн клирингээс гарч, дараагийн тооцоо түүнийг суутгана
(Тооцоо). Клиринг хүрэлцэхгүй бол
settlement_shortfall.
Шимтгэл¶
Тооцоо асаалттай апп-ын төлбөрийн шимтгэл буцаалтаар буцахгүй — операторын дүрэм refund_fee: true гэсэн үед л
буцаасан дүнгийн хувиар буцна. Хэсэгчилсэн буцаалтуудын буцсан шимтгэлийн нийлбэр бүтэн буцаалтад шимтгэлтэй яг
тэнцүү. Дэлгэрэнгүй: Шимтгэл.
Webhook ба мэдэгдэл¶
refund.succeeded/refund.failed—data.objectнь дээрх Refund (Event-ийн лавлах).- Хүн Gerege App-д «буцаалт» мэдэгдэл авна — дүн ба апп-ын батлагдсан нэр л; таны
reasonхэзээ ч биш (апп-ын бичсэн текст платформын нэрийн доор фишингийн суваг болно).
Test горим¶
Test (livemode: false) буцаалт дэвтэр дуудахгүй, тэр дор нь succeeded (201) болж refund.succeeded илгээнэ.
Ингэснээр бүтэн, хэсэгчилсэн, олон удаагийн буцаалт, давталт, idempotency_conflict-ийг мөнгөгүй туршина
(Sandbox).
Самбараас (консолоос) буцаах: POST /api/v1/miniapp/dev/payments/{pi}/refunds {amount?, reason} — ижил
хөдөлгүүр, ижил дүрэм, гэхдээ reason заавал, Idempotency-Key 1–100 тэмдэгт, эрх miniapp.payments; live
≥ 1 000 000₮ бол сүүлийн 10 минутад дахин нэвтэрсэн байх (403 fresh_sign_in_required). Консолын key таны backend-ийн
key-тэй хэзээ ч давхцахгүй (тусдаа угтвартай). Буцаалт бүр хэн хүссэнээ (actor: app эсвэл dashboard:<гишүүн>)
GET /api/v1/miniapp/dev/refunds-д харуулна — Payment intent-ын «Самбараас» хэсэг.
Алдаа¶
| HTTP | code |
Хэзээ |
|---|---|---|
| 400 | idempotency_key_required |
Idempotency-Key алга / буруу |
| 403 | insufficient_scope |
түлхүүрт refunds:write алга (required_scope) |
| 400 | validation_error |
amount < 1, нийлбэр нь төлсөн дүнгээс хэтэрнэ; reason > 255 |
| 400 | invalid_request |
бие уншигдсангүй (JSON биш, мэдэгдэхгүй талбар, 4 KB-аас их) |
| 404 | — | intent алга, эсвэл өөр апп / орчных |
| 409 | idempotency_conflict |
key энэ intent-д өөр биетэй ашиглагдсан |
| 409 | not_refundable |
intent succeeded / partially_refunded биш |
| 409 | refund_window_expired |
төлбөрөөс хойш 90 хоног өнгөрсөн |
| 503 | payments_unavailable |
live: core banking идэвхгүй |
Бүтэн жагсаалт: Алдааны код.