wire docs

Quickstart

Эхний төлбөрөө хүлээн ав — PaymentIntent, hosted checkout, баталгаажуулсан webhook, хуулж ажиллуулах жишээ хүсэлттэй.

Энэ гарын авлага таныг тэгээс эхлээд төлсөн захиалга хүртэл явуулна: PaymentIntent үүсгэх, худалдан авагчийг hosted checkout руу илгээх, үр дүнг webhook-оор баталгаажуулах. Алхам бүрд яг ямар HTTP хүсэлт илгээж, ямар хариу авахыг харуулсан.

0. Данс нээх ба баталгаажуулалт (KYC)

Wire бол санхүүгийн үйлчилгээ тул dashboard-д нэвтэрсний дараа эзэмшигч бүр нэг удаа баталгаажна — нийтдээ 2 минут орчим:

  1. Утас — дугаараа оруулаад заасан богино дугаар руу нэг SMS илгээнэ.
  2. Иргэний баталгаажуулалт (ДАН) — төрийн нэгдсэн нэвтрэлт sso.gov.mn руу шилжиж өөрийн зөвшөөрлөөр нэвтэрнэ. Wire таны нууц үгийг хардаггүй; мэдээлэл шифрлэгдэж хадгалагдана, нэг иргэн нэг л аккаунт баталгаажуулна.

Оператороор төлбөр хүлээн авахад хүсэлт, хяналт, цахим гэрээ гэсэн нэг удаагийн идэвхжүүлэлт бий — Оператор идэвхжүүлэх-ээс үз.

Бүтэн дараалал нь:

  1. Баталгаажуулалт — утас + ДАН иргэний баталгаажуулалт (нэг удаа).
  2. Project үүсгэх — интеграц (сайт эсвэл апп) бүрд нэг.
  3. Холболт (connector) идэвхжүүлж, project дээрээ асаах — таны акаунтад идэвхжсэн операторуудаас сонгоно.
  4. Төлбөр хүлээн авах данс холбох — оператор орлогыг энэ данс руу шилжүүлнэ.
  5. API key авах — project-ийнхөө key хэсгээс.
  6. API-аар гүйлгээгээ автоматжуулах — доорх алхмууд.

3 ба 4-р алхам дуусаагүй үед төлбөр үүсгэх хүсэлтэд API 403 connector_required эсвэл 403 settlement_account_required гэж хариулна — Алдаа-г үз.

1. API key авах

Хүсэлт бүр Authorization header дэх project-ийн нууц key-ээр authenticate хийгдэнэ. Key нь sk_live_ угтвартай бөгөөд бодит мөнгө хөдөлгөнө — эхний төлбөрөө бага дүнгээр хий. Key-г browser эсвэл mobile кодод хэзээ ч бүү тавь.

export WIRE_API_KEY="sk_live_..."

Хүсэлт бүрд хоёр дүрэм үйлчилнэ:

  • Body нь JSON: Content-Type: application/json илгээ. Form-encoded body (curl -d key=value) 400 invalid_json-оор татгалзагдана.
  • POST, DELETE бүрд Idempotency-Key header заавал. Үйлдэл бүрд тогтвортой утга (жишээ нь захиалгын дугаар + үйлдэл) ашигла — дахин оролдлого хэзээ ч хоёр дахь төлбөр үүсгэхгүй.

Дүн нь бүхэл төгрөг (integer) — 15000 гэдэг нь 15,000 ₮ (бутархайгүй, 100-аар бүү үржүүл).

2. SDK суулгах (заавал биш)

SDK-ууд доор харуулсан HTTP дуудлагуудыг л ороосон.

go get github.com/buildry-wire/wire-go
pip install wirepayment
npm install @buildry-wire/wire

3. PaymentIntent үүсгэх

PaymentIntent нь нэг захиалгад цуглуулах мөнгийг төлөөлнө. Зөвхөн дүнгээ (хүсвэл тайлбар болон өөрийн metadata) илгээ. allowed_operators-ыг бүү илгээ: тэгвэл худалдан авагч таны project дээр асаасан бүх оператороор төлж чадна. allowed_operators-ыг зөвхөн dashboard-ын Холболтууд хуудсанд байгаа тодорхой операторын id-аар хумих гэж байгаа үед л ашигла.

curl https://api.wire.mn/v1/payment_intents \
  -H "Authorization: Bearer $WIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1001-create" \
  -d '{
    "amount": 15000,
    "currency": "MNT",
    "description": "Захиалга #1001",
    "metadata": { "order_id": "1001" }
  }'
package main

import (
	"context"
	"fmt"
	"log"

	wire "github.com/buildry-wire/wire-go"
)

func main() {
	client := wire.NewClient("sk_live_...")
	ctx := context.Background()

	pi, err := client.PaymentIntents.Create(ctx, &wire.PaymentIntentCreateParams{
		Amount:         15000, // 15,000 ₮ — бүхэл төгрөг
		Currency:       "MNT",
		Description:    "Захиалга #1001", // төлөгчид харагдах утга (заавал биш)
		IdempotencyKey: "order-1001-create",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(pi.ID, pi.Status)
}
import wire

client = wire.Client("sk_live_...")

pi = client.payment_intents.create(
    amount=15000,                  # 15,000 ₮ — бүхэл төгрөг
    currency="MNT",
    description="Захиалга #1001",  # төлөгчид харагдах утга (заавал биш)
    idempotency_key="order-1001-create",
)
print(pi.id, pi.status)
import { Wire } from "@buildry-wire/wire";

const wire = new Wire("sk_live_...");

const pi = await wire.paymentIntents.create({
  amount: 15000, // 15,000 ₮ — бүхэл төгрөг
  currency: "MNT",
  description: "Захиалга #1001", // төлөгчид харагдах утга (заавал биш)
  idempotencyKey: "order-1001-create",
});
console.log(pi.id, pi.status);

Хариу:

{
  "id": "pi_k3vq7m2xw5nbt4rj6yhc2dpa7e",
  "object": "payment_intent",
  "amount": 15000,
  "currency": "MNT",
  "description": "Захиалга #1001",
  "status": "requires_payment_method",
  "client_secret": "cs_n2xk5q7mw3tz4vbr6jcy2gfa7m",
  "automatic_operator": true,
  "allowed_operators": [],
  "selected_operator": null,
  "next_action": null,
  "metadata": { "order_id": "1001" },
  "livemode": true,
  "created": 1791774000,
  "expires_at": 1791774600
}

requires_payment_method нь алдаа биш — худалдан авагчийг хүлээж байна гэсэн хэвийн анхны төлөв. id-г захиалгатайгаа хамт хадгал. Intent default 10 минутын дараа дуусна (expires_at) тул дараагийн алхмаа шууд хий.

4. Худалдан авагчийг hosted checkout руу илгээх

PaymentIntent-д checkout session үүсгэж, худалдан авагчийг буцаж ирсэн url руу чиглүүл. Hosted хуудас операторууд, QR код, банкны апп-ын холбоосыг харуулж, төлбөрийг өөрөө confirm хийнэ.

curl https://api.wire.mn/v1/checkout/sessions \
  -H "Authorization: Bearer $WIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1001-checkout" \
  -d '{
    "payment_intent": "pi_k3vq7m2xw5nbt4rj6yhc2dpa7e",
    "success_url": "https://yourshop.mn/orders/1001",
    "cancel_url": "https://yourshop.mn/cart"
  }'

Хариу:

{
  "id": "cs_w6qz3k2mx5tn4vbr7cyj2hpa5k",
  "object": "checkout_session",
  "payment_intent": "pi_k3vq7m2xw5nbt4rj6yhc2dpa7e",
  "status": "open",
  "url": "https://pay.wire.mn/c/cs_w6qz3k2mx5tn4vbr7cyj2hpa5k",
  "success_url": "https://yourshop.mn/orders/1001",
  "cancel_url": "https://yourshop.mn/cart",
  "allowed_operators": [],
  "created": 1791774005
}

Худалдан авагчийг url руу чиглүүл. Бүрэн урсгалыг Hosted checkout гарын авлага-аас үз.

Hosted checkout ашиглаж байгаа бол /v1/payment_intents/{id}/confirm-ыг бүү дууд — hosted хуудас өөрөө хийнэ. Session нь зөвхөн requires_payment_method төлөвтэй intent дээр үүснэ; эс бөгөөс 400 payment_intent_unexpected_state буцна.

Өөр хувилбар: төлбөрийн дэлгэцээ өөрөө хийх

Hosted хуудасны оронд төлбөрөө өөрөө харуулах бол intent-ийг confirm хийж, next_action-ыг нь худалдан авагчид үзүүл:

curl -X POST https://api.wire.mn/v1/payment_intents/pi_k3vq7m2xw5nbt4rj6yhc2dpa7e/confirm \
  -H "Authorization: Bearer $WIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1001-confirm" \
  -d '{}'

Intent requires_action төлөвтэй буцна, жишээ нь:

"next_action": {
  "type": "qr",
  "qr": {
    "text": "0002010102121531...",
    "deeplinks": [
      { "name": "Example bank", "link": "examplebank://pay?qr=..." }
    ]
  }
}

qr.text-ийг QR код болгож зур, утсан дээр deeplinks-ийг санал болго. next_action.type-ийн бусад утга: redirect_to_url, loan_app, loan_credit_decision, poll — PaymentIntent schema-г үз.

5. Webhook хүлээн авах

Зөвхөн browser redirect-д бүү итгэ — server тань баталгаажсан payment_intent.succeeded event хүлээн авсны дараа захиалгаа биелүүл.

Endpoint-оо project бүрд нэг удаа бүртгэ:

curl https://api.wire.mn/v1/webhook_endpoints \
  -H "Authorization: Bearer $WIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: webhook-endpoint-1" \
  -d '{
    "url": "https://yourshop.mn/webhooks/wire",
    "enabled_events": ["payment_intent.succeeded"]
  }'

Хариунд "secret": "whsec_..." ирнэ — зөвхөн нэг удаа харагдана, хадгалаарай. Endpoint pending төлөвтэй үүснэ; event хүлээн авахаас өмнө dashboard-оос баталгаажуул (Wire гарын үсэгтэй туршилтын ping илгээж, таны URL 2xx буцаах ёстой).

Wire юу илгээдэг вэ (таны URL руу POST):

POST /webhooks/wire HTTP/1.1
Content-Type: application/json
WirePayment-Signature: t=1791774042,v1=5257a869e7ec...

{
  "id": "evt_b7nx3k2qw5mv4tzc6jry2pha4g",
  "object": "event",
  "type": "payment_intent.succeeded",
  "created": 1791774042,
  "data": {
    "id": "pi_k3vq7m2xw5nbt4rj6yhc2dpa7e",
    "object": "payment_intent",
    "status": "succeeded",
    "amount": 15000,
    "currency": "MNT",
    "charge": "ch_m4tz2q7wn5kc3vbx6ryj2hfa5d"
  }
}

Гарын үсгийг шалгаад, дараа нь үйлдэл хий. v1 нь hex(HMAC_SHA256(whsec_secret, t + "." + raw_body)). Үргэлж parse хийгээгүй, түүхий body дээр шалга.

import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.WIRE_WEBHOOK_SECRET!; // whsec_...

app.post(
  "/webhooks/wire",
  express.raw({ type: "application/json" }), // түүхий байтыг хадгална
  (req, res) => {
    const header = req.header("WirePayment-Signature") ?? "";
    const parts = Object.fromEntries(
      header.split(",").map((p) => p.split("=") as [string, string]),
    );
    const t = Number(parts.t);
    const expected = crypto
      .createHmac("sha256", SECRET)
      .update(`${parts.t}.${req.body.toString("utf8")}`)
      .digest("hex");
    const ok =
      parts.v1 &&
      expected.length === parts.v1.length &&
      crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1)) &&
      Math.abs(Date.now() / 1000 - t) < 300;
    if (!ok) return res.status(400).send("bad signature");

    const event = JSON.parse(req.body.toString("utf8"));
    if (event.type === "payment_intent.succeeded") {
      // event.data.id-аар захиалгаа олж биелүүл (нэг л удаа — event.id-аар давхардлыг шүү)
    }
    res.sendStatus(200);
  },
);
body, _ := io.ReadAll(r.Body)
event, err := client.Webhooks.Verify(
	body,
	r.Header.Get(wire.SignatureHeader),
	"whsec_...", // endpoint-ийн signing secret
)
if err != nil {
	http.Error(w, "bad signature", http.StatusBadRequest)
	return
}
if event.Type == "payment_intent.succeeded" {
	// захиалгаа биелүүл
}
w.WriteHeader(http.StatusOK)
event = client.webhooks.verify(
    request.body,                       # түүхий bytes
    request.headers[wire.SIGNATURE_HEADER],
    "whsec_...",                        # endpoint-ийн signing secret
)
if event.type == "payment_intent.succeeded":
    ...  # захиалгаа биелүүл
import { SIGNATURE_HEADER } from "@buildry-wire/wire";

const event = wire.webhooks.verify(
  rawBody, // parse хийгээгүй body (string эсвэл Buffer)
  req.headers[SIGNATURE_HEADER.toLowerCase()],
  "whsec_...", // endpoint-ийн signing secret
);
if (event.type === "payment_intent.succeeded") {
  // захиалгаа биелүүл
}

6. Server талд дахин шалгах

Үнэтэй захиалга илгээхээс өмнө intent-ээ дахин уншаарай:

curl https://api.wire.mn/v1/payment_intents/pi_k3vq7m2xw5nbt4rj6yhc2dpa7e \
  -H "Authorization: Bearer $WIRE_API_KEY"

Зөвхөн "status": "succeeded" үед биелүүл. Webhook заавал биш — бүртгээгүй бол энэ endpoint-ыг давтан асууж (poll) болно.

Дараагийн алхмууд

  • Hosted checkout — QR, deeplink, авто-цуцлалт.
  • Webhooks — event-ийг найдвартай шалгаж боловсруулах.
  • Алдаа — алдааны код бүр ба засах арга.
  • API reference — бүх /v1 endpoint, хүсэлт/хариуны жишээтэй.

Энэ хуудсанд