Идемпотентность
POST /payments дээр X-Idempotency-Key ашиглан давхар төлбөрөөс хэрхэн сэргийлэх, давтан хүсэлтийг хэрхэн зохицуулах.
Идемпотентность гэдэг нь нэг хүсэлтийг хэдэн ч удаа давтан илгээсэн, эцсийн үр дүн нь нэг л удаа гүйцэтгэгдсэнтэй адил байхыг хэлнэ. Сүлжээ тасрах, timeout болох, клиент дахин оролдох зэрэг тохиолдолд нэг нэхэмжлэлийг хоёр удаа төлчихгүй байх нь Төлбөр хийхэд хамгийн чухал баталгаа юм.
gov-pay нь үүнийг POST /payments дээр X-Idempotency-Key header-ээр шийднэ.
X-Idempotency-Key нь сонголттой (optional) боловч бодит орчинд (production) ҮРГЭЛЖ илгээхийг хатуу зөвлөж байна. Энэ түлхүүргүйгээр давтан илгээсэн хүсэлт бүр шинэ төлбөр болж, давхар төлбөр үүсэх эрсдэлтэй.
Яагаад чухал вэ
POST /payments нь нэхэмжлэлийг төрийн систем рүү дамжуулдаг мөнгөн гүйлгээтэй үйлдэл. Дараах нөхцөлд клиент хариуг хүлээж аваагүй ч серверт төлбөр үүссэн байж болзошгүй:
- Хүсэлт серверт хүрсэн боловч хариу буцах замдаа сүлжээ тасарсан.
- Клиент талын timeout ажиллаж, гүйлгээ амжилттай болсон эсэхийг мэдэхгүй болсон.
- Mobile/superapp дээр хэрэглэгч "Төлөх" товчийг хоёр дахин дарсан.
Эдгээр тохиолдолд та аюулгүйгээр яг ижил X-Idempotency-Key-ээр дахин оролдох боломжтой бөгөөд хоёр дахь төлбөр үүсэхгүй.
Семантик
- Анхны хүсэлт — gov-pay түлхүүрийг бүртгэж, төлбөрийг боловсруулаад үр дүнг (хариуг) cache-д хадгална. Хариу:
201(амжилттай) эсвэл422(амжилтгүй). - Ижил түлхүүртэй давтан хүсэлт — gov-pay шинээр төлбөр үүсгэхгүйгээр cache-д хадгалсан анхны хариуг буцаана. Хариунд нэмж
"message": "idempotent"талбар ирнэ.
{
"success": true,
"id": "9c1e7f2a-4b8d-4d3a-9f1e-2a6b8c0d4e5f",
"status": "submitted",
"amount": 250000,
"invoiceId": "f0a1b2c3-d4e5-6789-abcd-ef0123456789",
"invoiceIds": ["f0a1b2c3-d4e5-6789-abcd-ef0123456789"],
"message": "idempotent"
}"message": "idempotent" нь "энэ түлхүүрийг өмнө нь боловсруулсан, чамд анхны үр дүнг буцааж байна" гэсэн дохио. Хэрэв энэ талбар ирвэл шинэ гүйлгээ хийгдээгүй гэдгийг ойлгож, давхар бичилт хийхгүй байх ёстой.
Түлхүүрийн хүрээ (scope)
Идемпотентностийн түлхүүр нь партнёр тус бүрээр тусгаарлагдсан (таны X-API-Key-д хамаарна). Өөрөөр хэлбэл:
- Таны ашигласан түлхүүр зөвхөн таны хүсэлтэд нөлөөлнө. Өөр партнёр санамсаргүй ижил түлхүүр ашигласан ч хоорондоо мөргөлдөхгүй.
- Тиймээс түлхүүр глобал давтагдашгүй байх албагүй — зөвхөн таны хүрээнд давтагдахгүй байхад хангалттай.
Юуг түлхүүр болгох вэ
Өөрийн хүсэлт бүрд шинэ UUID (v4) үүсгэж X-Idempotency-Key болгон ашигла.
- Нэг логик төлбөрийн оролдлогод нэг түлхүүр ноогдоно. Дахин оролдох бүртээ ИЖИЛ түлхүүрийг ашигла — энэ нь "энэ бол өмнөх оролдлогын давталт" гэдгийг gov-pay-д хэлж байгаа хэрэг.
- Шинэ, өөр төлбөр эхлүүлэх бол шинэ түлхүүр үүсгэ.
- Түлхүүрийг хүсэлт илгээхээс өмнө клиент талдаа үүсгэж, дахин оролдоход дахин ашиглахаар хадгалж байх ёстой.
invoiceId-г шууд түлхүүр болгож бүү ашигла. Нэг нэхэмжлэлийг нэг л удаа төлдөг гэж бодвол логиктой мэт боловч, төлбөр амжилтгүй болсны дараа дахин оролдоход (хууль ёсны шинэ оролдлого) хуучин cache хариу буцаад, бодит дахин боловсруулалт хийгдэхгүй болж мэдэх эрсдэлтэй. Оролдлого бүрийг өөрийн UUID-аар тэмдэглэ.
Сүлжээний алдаа дээр дахин оролдох
Зөв retry схем нь дараах байдалтай:
- Хүсэлт илгээхээс өмнө UUID
keyүүсгэ. - Энэ
key-ийгX-Idempotency-Keyheader-т тавьжPOST /paymentsдууд. - Хэрэв сүлжээний алдаа гарвал (timeout, холболт тасрах, эсвэл
5xx), ЯГ ижилkey-ээр дахин оролд. - Эцсийн хариу
201(амжилттай) эсвэл422(амжилтгүй) ирэх хүртэл хэдэн ч удаа давтаж болно — хоёр дахь төлбөр үүсэхгүй.
Хариу руу нь итгэлгүй болсон үед хамгийн найдвартай арга бол ижил түлхүүрээр дахин дуудах. Хэрэв анхны хүсэлт серверт хүрсэн байсан бол cache хариу ("message": "idempotent"-той) ирнэ; хүрээгүй байсан бол шинээр боловсруулагдана. Аль ч тохиолдолд эцсийн төлбөр нэг л удаа хийгдэнэ.
Хариу ирэхгүй байх үед бас сонголт нь GET /payments/{id}-ээр статусыг шалгах юм — гэхдээ retry-ийн хувьд ижил түлхүүрээр дахин дуудах нь хамгийн энгийн бөгөөд найдвартай.
curl жишээ
Анхны хүсэлт
curl -X POST https://sandbox-tts.qpay.mn/api/v1/payments \
-H "X-API-Key: <таны_api_key>" \
-H "X-Idempotency-Key: 9b2f1c44-7e0a-4d61-8c2f-1a3b5d7e9f00" \
-H "Content-Type: application/json" \
-d '{ "invoiceId": "f0a1b2c3-d4e5-6789-abcd-ef0123456789" }'Дахин оролдлого (яг ижил түлхүүр)
curl -X POST https://sandbox-tts.qpay.mn/api/v1/payments \
-H "X-API-Key: <таны_api_key>" \
-H "X-Idempotency-Key: 9b2f1c44-7e0a-4d61-8c2f-1a3b5d7e9f00" \
-H "Content-Type: application/json" \
-d '{ "invoiceId": "f0a1b2c3-d4e5-6789-abcd-ef0123456789" }'Хоёр дахь хүсэлтэд хариу нь шинэ төлбөр биш, анхны үр дүн нь "message": "idempotent" талбартайгаар буцна.
Орчны Base URL-уудын талаар Орчин хуудаснаас үзнэ үү. Хүсэлтийн боломжит хариунууд (201, 422, 429 г.м)-ийг Алдааны кодууд хэсгээс харна уу.
Хураангуй
| Дүрэм | Тайлбар |
|---|---|
| Түлхүүр болгож юу ашиглах | Оролдлого бүрд өөрийн үүсгэсэн UUID (v4) |
| Дахин оролдох үед | ЯГ ижил түлхүүрийг дахин ашиглах |
| Шинэ төлбөр бол | Шинэ түлхүүр үүсгэх |
| Давтан хүсэлтийн дохио | Хариунд "message": "idempotent" ирнэ |
| Хүрээ | Партнёр (X-API-Key) тус бүрээр тусгаарлагдсан |
| invoiceId-г түлхүүр болгох уу | Үгүй — оролдлого бүрийг тусад нь UUID-аар тэмдэглэ |
Дэлгэрэнгүйг Төлбөр хуудаснаас үзнэ үү.