Интеграция

Ачкычтарды түзүү

Терминалда бул эки буйрукту иштетиңиз:

terminal
openssl genrsa -out finik_private.pem 2048
openssl rsa -in finik_private.pem -pubout > finik_public.pem
ФайлМаксаты
finik_private.pemАр бир сурамга ушул ачкыч менен кол коюңуз. Аны жашыруун сактаңыз, анткени ачкычты алган адам сиздин атыңыздан сурам жөнөтө алат.
finik_public.pemFinik сурамдарыңызды текшере алышы үчүн ачык ачкычты коопсуз канал аркылуу жөнөтүңүз.

Сурамдарга кол коюу

Ар бир суроо үчүн signature баш аты талап кылынат - RSA-SHA256, Base64-коддолгон, купуя ачкычыңыз менен түзүлгөн. Finik Node.js жана Python үчүн даяр пакеттерди камсыз кылат.

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

create-payment.ts
import { Signer, RequestData } from '@mancho.devs/authorizer';
import fetch from 'node-fetch'; // or axios

// Choose the environment you call:
const baseUrl = 'https://api.acquiring.averspay.kg';      // prod
// const baseUrl = 'https://beta.api.acquiring.averspay.kg'; // beta

// IMPORTANT: Host header must match the URL host exactly.
const host = new URL(baseUrl).host;

// Your credentials
const apiKey = process.env.FINIK_API_KEY!;           // from Finik
const privateKey = process.env.FINIK_PRIVATE_PEM!;   // contents of finik_private.pem
const timestamp = Date.now().toString();             // UNIX ms

// Create Payment body per spec
const body = {
  Amount: 100,
  CardType: 'FINIK_QR',
  PaymentId: '00000000-0000-0000-0000-000000000000',  // use a real UUID
  RedirectUrl: 'https://example.com/success',
  Data: {
    accountId: 'your-account-id',
    name_en: 'your-qr-name',
  },
};

// Build the canonical input for signing
const requestData: RequestData = {
  httpMethod: 'POST',
  path: '/v1/payment',                 // absolute path only (no query)
  headers: {
    Host: host,                        // must match baseUrl host
    'x-api-key': apiKey,               // included in signature
    'x-api-timestamp': timestamp,      // UNIX ms; same value used in signature
    // You may send other headers, but only `host` and `x-api-*` are included in the signature.
  },
  queryStringParameters: undefined,    // or { ... } if you have query; lib sorts & encodes
  body,                                // plain JS object; lib will canonicalize/JSON-stringify
};

// Produce Base64 RSA-SHA256 signature
const signature = await new Signer(requestData).sign(privateKey);

// Send the actual HTTP request
const url = `${baseUrl}${requestData.path}`;
const res = await fetch(url, {
  method: requestData.httpMethod,
  headers: {
    'content-type': 'application/json',
    'x-api-key': apiKey,
    'x-api-timestamp': timestamp,
    signature,                         // <- attach signature header
  },
  body: JSON.stringify(body),
  // If your API currently returns 302 (HTML) on S2S calls, prevent auto-follow:
  redirect: 'manual', // remove once API returns 201 JSON by default
});

if (res.status === 302) {
  // Read Location when you opt into redirects
  console.log('Redirect to:', res.headers.get('location'));
} else {
  console.error(res.status, await res.text());
}

Кол тамгага Host жана x-api- менен башталган баш аттар гана кирет. Кол тамгада жана сурамдын баш атында бир эле убакыт белгисин колдонуңуз.

Төлөм түзүү

POST кол коюлган өтүнүч:

API endpoints
POST https://api.acquiring.averspay.kg/v1/payment — Продакшен
POST https://beta.api.acquiring.averspay.kg/v1/payment — Бета

Баш аттар

Баш атСыпаттама
signatureСиз түзгөн кол тамга.
x-api-keyFinik берген API ачкычыңыз.
x-api-timestampUNIX миллисекунддарындагы учурдагы убакыт. Кол тамгада колдонулган мааниге барабар болушу керек.

Сурамдын денеси

ТалааТүрүМилдеттүүСыпаттама
AmountNumberМилдеттүү эмесТөлөмдүн белгиленген суммасы. Көрсөтүлбөсө, кардар каалаган сумманы төлөй алат.
CardTypeStringМилдеттүүАр дайым FINIK_QR.
PaymentIdStringМилдеттүүКайталанган төлөмдөрдү болтурбоочу уникалдуу төлөм ID.
RedirectUrlStringМилдеттүүИйгиликтүү төлөмдөн кийин кардар багыттала турган дарек.
LangStringМилдеттүү эмесТөлөм барагынын тили. Колдоого алынган маанилер: `ky`, `ru`, `en`.
DataObjectМилдеттүүТөлөмдүн чоо-жайы. Төмөндө караңыз.

Data object

ТалааТүрүМилдеттүүСыпаттама
accountIdStringМилдеттүүКаражат түшө турган Finik эсебиңиздин IDси.
name_enStringМилдеттүүКардарга көрсөтүлө турган QR коддун аталышы.
webhookUrlStringМилдеттүүТөлөмдүн статусу тууралуу билдирүүлөр үчүн сервериңиздин endpoint дареги.
descriptionStringМилдеттүү эмесТөлөм барагындагы сыпаттама.
startDateNumberМилдеттүү эмесQR коддун жарактуулук мөөнөтүнүн башталышы (UNIX мс).
endDateNumberМилдеттүү эмесQR коддун жарактуулук мөөнөтүнүн аягы (UNIX мс).
additionalDataArrayМилдеттүү эмесЭгер value талаасы берилбесе, кардар төлөм ыкмалары көрсөтүлгөнгө чейин форманы толтурат. Талаалардын максималдуу саны — 20.

Көп тилдүү барактар

Төлөм барагынын тилин тандоо үчүн Lang параметрин сурамдын денесинин жогорку деңгээлинде бериңиз. Колдоого алынган маанилер: ky, ru, en.

additionalData items

ТалааТүрүМилдеттүүСыпаттама
fieldIdStringМилдеттүүWebhook payload ичиндеги талаанын ачкычы.
nameStringМилдеттүүТөлөм барагындагы талаанын аталышы.
isHiddenBooleanМилдеттүү эмесТөлөм барагындагы талааны жашыруу.
valueStringМилдеттүү эмесАлдын ала толтурулган маани.

Сурамдын body мисалы

POST /v1/payment — body
{
  "Amount": 100,
  "CardType": "FINIK_QR",
  "PaymentId": "a3f1c2e4-7b9d-4e2a-8c1f-3d0e9b2a5f6c",
  "RedirectUrl": "https://example.com/success",
  "Lang": "ky",
  "Data": {
    "accountId": "your-account-id",
    "name_en": "your-qr-name",
    "webhookUrl": "https://merchant.example.com/webhooks/finik",
    "description": "your-qr-description",
    "startDate": 1737369000000,
    "endDate": 1737455400000
  }
}

Жоопту иштетүү

Төлөм ийгиликтүү түзүлгөндө, төлөм барагынын URL дареги Location баш атында берилген 302 багыттоо кайтарылат:

response
HTTP/1.1 302 Found
Location: https://qr.finik/<payment-path>
  1. Багыттоолорду өчүрүү менен бэкендден POST /v1/payment чалыңыз.
  2. Location окуңуз - бул төлөм барагыңыздын URL дареги.
  3. Бул URL даректи кардарга жөнөтүү - браузерди ага багыттаңыз же веб-көрүнүштө ачуу үчүн SPA/мобилдик тиркемеңизге кайтарыңыз.
  4. Кардар төлөмдү аяктайт жана сиздин RedirectUrl'ге багытталат.
  5. Финик вебхук жөнөтөт акыркы статусу менен - ​​аны чындыктын булагы деп эсептеңиз.

Автоматтык багыттоону өчүрүп, Location баш атын окуңуз

fetch.js
const res = await fetch("https://api.acquiring.averspay.kg/v1/payment", {
  method: "POST",
  headers: { "content-type": "application/json", "x-api-key": apiKey, "x-api-timestamp": ts, signature },
  body: JSON.stringify(body),
  redirect: "manual", // don't auto-follow
});

if (res.status === 302) {
  const paymentUrl = res.headers.get("location"); // send this to the browser
}

Бэкенд браузерди багыттай алат (302 Location: <paymentUrl>) же SPA колдонмоңузга JSON кайтарып, window.location = paymentUrl орното алат.

Ката жооптору

Ар бир ката төмөнкү түрдө JSON катары кайтарылат:

error response
{
  "StatusCode": 400,
  "ErrorMessage": "..."
}

Сурамды валидациялоо каталары

HTTP статусуКата билдирүүсүСебеби
400 Bad RequestA payload must be provided.Сурам денеси бош.
400 Bad RequestAn unrecognizable payload is provided.Дене валиддүү JSON эмес.
400 Bad RequestInvalid payment ID is required.`PaymentId` жок же саптык маани эмес.
400 Bad RequestPayment ID must be less than or equal to 36 characters long.`PaymentId` 36 белгиден ашык.
400 Bad RequestAn invalid amount is provided. Amount must be greater than 0.`Amount` 0гө барабар же терс.
400 Bad RequestInvalid IP address is provided.`CustomerIp` (же автоматтык аныкталган булак IP) жарактуу IP дарек эмес.
400 Bad RequestCard type is required.`CardType` жок.
400 Bad RequestAn unrecognizable card type is provided.`CardType` учурда колдоого алынбайт (учурда `FINIK_QR` гана колдоого алынат).
400 Bad RequestRedirectUrl is required.`CardType` `FINIK_QR` барабар, ал эми `RedirectUrl` жок.
400 Bad RequestCurrency must be provided.`Currency` жок жана демейки маанини аныктоо мүмкүн болгон жок.
400 Bad RequestAn invalid currency is provided.`Currency` `KGS` же `RUB` эмес.
400 Bad Request"FINIK_QR" payment method currently does not support {Currency} currency.Көрсөтүлгөн `Currency` Finik QR үчүн колдоого алынбайт (`KGS` гана колдоого алынат).

Төлөм маалыматынын каталары

Булар сурам денесиндеги Data талаасына тиешелүү.

HTTP статусуКата билдирүүсүСебеби
400 Bad RequestPayment data must be provided.`Data` жок.
400 Bad RequestAn invalid payment data is provided.`Data` объектиге ажыратылган жок.
400 Bad RequestAccount ID is required in the payment data.`Data.accountId` жок.
400 Bad RequestItem name is required in the payment data.`Data.name_en` жок.
400 Bad RequestStart Date invalid in the payment data.`Data.startDate` көрсөтүлгөн, бирок жарактуу убакыт белгиси эмес.
400 Bad RequestEnd Date invalid in the payment data.`Data.endDate` көрсөтүлгөн, бирок жарактуу убакыт белгиси эмес.
400 Bad RequestImages in payment request is invalid: {images}`Data.images` көрсөтүлгөн, бирок массив эмес.
400 Bad Requestbase64Image in payment request includes invalid base64Data.images ичиндеги бир элемент жарактуу base64 сүрөт data URI эмес (data:image/<type>;base64,<data> үлгүсүнө дал келиши керек).
400 Bad RequestUnable to create media filesЭквайер сүрөт жүктөө кадамын четке какты же ал ийгиликсиз аяктады.
400 Bad RequestadditionalData invalid in the payment data.`Data.additionalData` көрсөтүлгөн, бирок массив эмес.
400 Bad RequestadditionalData exceeds maximum allowed size of 20.`Data.additionalData` ичинде 20дан ашык элемент бар.
400 Bad Request"fieldId" not provided in the payment data.`additionalData` элементтеринин биринде `fieldId` жок.
400 Bad Request"name" not provided in the payment data.`additionalData` элементтеринин биринде `name` жок.

Эквайер жана сервер каталары

HTTP статусуКата билдирүүсүСебеби
502 Bad Gateway(эквайерден жөнөтүлөт, же "Unable to process the payment request.")
400 Bad Request(эквайерден жөнөтүлөт, же "Unable to process the payment request.")Эквайерге HTTP чалуу ийгиликсиз аяктады жана эквайердин өзүнүн HTTP статусу 400 болду. Билдирүү жогоруда сүрөттөлгөндөй эле берилет.

Сурамды иштетүү учурунда төмөнкү валидация каталары да чыгышы мүмкүн:

КатаБилдирүүСебеби
ValidationExceptionA maximum of 10 media files can be uploaded.`mediaFiles` өтө көп.
ValidationExceptionThe {media file id} is required.`mediaFiles` элементинин `id`си жок.
ValidationExceptionA duplicate ID in MediaFiles is provided.Кайталанган `mediaFiles` `id`си.
ValidationExceptionMediaFiles field contains an id that does not exists.Белгисиз медиа `id`.
ValidationExceptionThe account.id is required.`account.id` жок.
ValidationExceptionAccount or parentId fields should be provided.`account` жана `parentId` жок.
ValidationExceptionThe name_en is required.`name_en` жок.
ValidationExceptionThe requestId is required.`requestId` жок.
ValidationExceptionThe fixedAmount must be a decimal number with no more than 2 digits after the decimal point.`fixedAmount` так эместиги.
ValidationExceptionThe fixedAmount must be a greater than or equal to 0.01.`fixedAmount` өтө аз.
ValidationException(merchant category code валидатору тарабынан аныкталган билдирүү)Жараксыз `merchantCategoryCode`.
ValidationExceptionThe requiredField.fieldId is required.`requiredFields` элементинин `fieldId`си жок.
ValidationExceptionMissing values for fields: {missing}Милдеттүү талаалар толтурулган эмес.
ValidationExceptionAccount is not provided.Account жеткиликсиз.
ValidationExceptionAccount status must be "Enabled"Account активдүү эмес.