Вебхуктар

Вебхук менен иштөө

Ар бир аяктаган төлөмдөн кийин Finik сиздин webhookUrl дарегиңизге POST сурам жөнөтөт. Аны текшерип, андан кийин буйрутмаңызды жаңыртыңыз.

Payload мисалы

POST /webhooks/finik
{
  "id": "transaction-id-15423_DEBIT", // Finik операциясынын ID'си (_DEBIT суффикси — эсептен алуу)
  "transactionId": "transaction-id-241234", // төлөм транзакциясынын ID'си — идемпотенттүүлүк (дубликацияны болтурбоо) үчүн колдонуңуз
  "status": "success", // төлөмдүн статусу; каалаган регистрде келиши мүмкүн — регистрге сезгич болбой текшериңиз
  "amount": 100, // төлөмдүн суммасы
  "fields": { // төлөм формасынын талаалары жана сиздин additionalData
    "amount": 100, // формада көрсөтүлгөн сумма
    "paymentId": "payment-id-241234", // POST /v1/payment'ке жөнөткөн PaymentId
    "fieldId1": "value1", // fieldId "fieldId1" болгон additionalData талааңыздын мааниси
    "fieldId2": "value2" // fieldId "fieldId2" болгон additionalData талааңыздын мааниси
  },
  "requestDate": 1737369012345, // сурам түзүлгөн убакыт (UNIX, мс)
  "transactionDate": 1737369012345, // транзакция өткөрүлгөн убакыт (UNIX, мс)
  "service": { "id": "VISA" } // болгону Visa карталарын кабыл алуу күйгүзүлгөндө гана келет
}

Эмне кылуу керек

  1. Кол тамганы ырастаңыз - Кирүүчү сурамдан канондук сап түзүңүз (ыкма, жол, хост + бардык аталыштар x-api-*, суроо, негизги), андан кийин signature башын чөйрөңүз үчүн Finik ачык ачкычына каршы текшериңиз.
  2. Убакыт белгисин текшериңиз - x-api-timestamp жарактуу терезеде экенин текшериңиз (мисалы, ±5 мүнөт).
  3. Идемпотенттүүлүгүн камсыз кылуу - Депликация үчүн transactionId (же id) колдонуңуз. Финик бир вебхукту бир нече жолу жеткире алат («жок дегенде бир жолу» жеткирүү).
  4. Тез жооп бериңиз - 200 OK дароо кайтарып, оор жүктү асинхрондук түрдө аткарыңыз.

Кайра жөнөтүү аракеттери

Webhook «жок дегенде бир жолу» жеткирилет. Эгер сервериңиз 200 OK менен жооп бербесе (же ката менен жооп берсе), Finik жөнөтүүнү кайталайт.

  • Алгачкы 5 аракет — ар 30 секунд сайын.
  • Андан кийин — интервал эки эселенип өсөт (экспоненциалдык кечигүү): 60 секунддан башталат жана 24 саат (86 400 секунд) менен чектелет.
АракетКечигүү
060 сек (1 мүн)
1120 сек (2 мүн)
2240 сек (4 мүн)
3480 сек (8 мүн)
4960 сек (16 мүн)
51920 сек (32 мүн)
63840 сек (1 саат 4 мүн)
77680 сек (2 саат 8 мүн)
815360 сек (4 саат 16 мүн)
930720 сек (8 саат 32 мүн)
1061440 сек (17 саат 4 мүн)
11122880 сек → 86400 секундга чектелет (24 саат)

24 саатка жеткенде интервал мындан ары өспөйт — кийинки бардык аракеттер күнүнө бир жолу жасалат.

Кол тамганы кантип туура текшерүү керек

Кол тамганы кантип туура текшерүү керектигинин мисалдары төмөндө.

@mancho.devs/authorizer жана node-fetch орнотуңуз, андан кийин:

check-signature.ts
import { Signer } from "@mancho.devs/authorizer";
import * as dotenv from "dotenv";
dotenv.config({ path: ".env.development" });

const publicKey = process.env.FINIK_BETA_PUBLIC_KEY;

const requestData = {
  body: {
    fields: {
      amount: 1,
      webhook_url: "https://huntpro.kg/finik-callback",
      paymentId: "141fc797-0366-480e-8ba7-2982632b2b2c",
      success_redirect_url:
        "https://api.acquiring.averspay.kg/v1/redirect?paymentId=141fc797-0366-480e-8ba7-2982632b2b2c&clientId=1295102413&status=succeeded",
      name: "HuntPro",
      qrTransactionId: "aaa76e79-f808-4ac5-b88e-76a9b4055832",
    },
    amount: 1,
    transactionDate: 1781697937466,
    clientId: "25c1aabe-fc4a-4968-85d9-90600466e9a5",
    id: "320259584_aaa76e79-f808-4ac5-b88e-76a9b4055832_DEBIT",
    status: "succeeded",
    transactionId: "141fc797-0366-480e-8ba7-2982632b2b2c",
    data: {
      accountId: "8d4e1d11-e50c-4278-a5e2-4e55de196c6a",
      description: "Order 2606",
      webhookUrl: "https://huntpro.kg/finik-callback",
      name_en: "HuntPro",
    },
  },
  httpMethod: "POST",
  headers: {
    "Content-Type": "application/json",
    Host: "huntpro.kg",
    "x-api-timestamp": "1781763261255",
  },
  path: "/finik-callback",
  queryStringParameters: null,
};

const signature = "jS1a8HW4BTIea8iCmoW/EF7FXUA0JSsHe/kSRBfCYdxFwvyrMe0SOfU9pAKzOOO0bIsa9FW+WqAzqxExHjcscmG8k/vwgB+dCMcM04K91vTL6eZAVOE/Hcx2iALNZnG6UVnP/jnUt8MjK+xwBhamwFktxdUovf+cVFZ2io10RAT1pOEIHtZceXbQeg7XlhcPuTAKmOuF1B4gGoksRtGglGwwyvYaa9ml8OPMP3uoCaauYqT0aUKLTNsJdFfO0Q3Dvsy9uyWvuVa5t6adbIm+SHlbz9VGSZ2xrwgETUBVj86dfA3oiAgERLKhQTBSMTxRYlUKhPVHGfR3kjAhD3g4JQ==";

async function checkSignature() {
  const isValid = await new Signer(requestData as any).verify(
    publicKey!,
    signature,
  );

  console.log("Is valid signature:", isValid);
}

checkSignature();