Библиотека для взаимодействия с API Т-Кассы.
import { TKassa } from "t-kassa-api";
const ткасса = new TKassa(process.env.TERMINAL_KEY, process.env.PASSWORD, {
server: "https://rest-api-test.tinkoff.ru",
});
const result = await ткасса.init({
Amount: 1000,
OrderId: "12",
});
console.log(result);
- Генерируется исходя из OpenAPI спецификации
- Очень удобная работа с нотификацией (webhook) с умными фильтрами
- Имеет в себе webhook адаптеры для самых популярных фреймворков
- Удобна и для нескольких касс
- Отличная документация кода с помощью JSDoc (сгенерировано из OpenAPI)
- Современная и с умнейшими типами
- 0 зависимостей
- Берёт работу с подписью запроса на себя
- Есть на JSR
Пример использования webhook с фреймворком Hono
import { Hono } from "hono";
import { TKassa, webhookHandler, filters } from "t-kassa-api";
const ткасса = new TKassa(process.env.TERMINAL_KEY, process.env.PASSWORD);
ткасса.on(
filters.and(
filters.equal("Status", "SUCCESS"),
filters.notNullable("RebillId")
),
(context) => {
// при этом типы понимают фильтры
}
);
const app = new Hono();
app.get("/", webhookHandler(ткасса, "hono"));
или любой другой фреймворк
// a non-existing framework for the example
import { App } from "some-http-framework";
import { TKassa } from "t-kassa-api";
const ткасса = new TKassa(process.env.TERMINAL_KEY, process.env.PASSWORD, {
server: "https://rest-api-test.tinkoff.ru",
});
const app = new App().post("/t-kassa", async (req) => {
// req.body must be json equivalent to Webhook notification body
await ткасса.emit(req.body);
});
app.listen(80);
Не всегда бывает удобным передача параметров одной кассы в конструктор класса, поэтому и появился режим мульти-кассы. Он позволяет вам не указывать TerminalKey
и Password
.
import { TKassa } from "t-kassa-api";
const ткасса = new TKassa();
const result = await ткасса.init({
Amount: 1000,
OrderId: "12",
TerminalKey: "12312sf",
Password: "123123231",
});
console.log(result);
И как вы можете заметить, теперь требуется указывать TerminalKey
и Password
в теле запроса. И в типах это тоже выражено! Магия? Не иначе.
Но как тогда получать webhook события? (нотификацию)
Для этого вам понадобится указать функцию первым аргументом конструктора.
import { TKassa } from "t-kassa-api";
const ткасса = new TKassa((body) => {
const [kassa] = await db
.select()
.from(kassaTable)
.where(eq(kassaTable.terminalKey, body.TerminalKey));
if (!kassa) throw new Error("Касса не найдена");
return {
Password: kassa.password,
custom: { kassa },
};
});
ткасса.on(
filters.and(
filters.equal("Status", "SUCCESS"),
filters.notNullable("RebillId")
),
(context, { kassa }) => {
// и тут появляется вторым аргументов переданное вами значение в custom
}
);
И типы опять же совсем не глупы и делают вам благое дело, указывая верный путь.
Вы можете повлиять на поведение запроса
const tKassa = new TKassa({
requestsOptions: {
headers: {
"x-awesome": "this library is great",
},
},
});
await tKassa.getQr(/** some data */, {
signal: AbortSignal.timeout(500)
});
Таким образом вы можете, например, воспользоваться прокси.
В Node.js
import { ProxyAgent } from "undici";
const proxyAgent = new ProxyAgent("my.proxy.server");
const tKassa = new TKassa({
requestsOptions: {
dispatcher: proxyAgent,
},
});
Несмотря на то что undici
работает под капотом Node.js
, вам придётся его скачать. Также убедитесь, что у вас нет "lib": ["DOM"]
в вашем tsconfig.json
, иначе вы не увидите свойства dispatcher
(хотя undici
всё равно его обработает).
В Bun
const tKassa = new TKassa({
requestsOptions: {
proxy: "my.proxy.server",
},
});
Генерирует подпись для запроса.
const signature = generateSignature(
{ body: "OK" },
process.env.TERMINAL_KEY,
process.env.PASSWORD
);
Шифрует данные карты.
const cardData = encryptCardData(тк, {
PAN: "4000000000000101",
ExpDate: "1230",
CVV: "111",
});
const tds = await тк.check3dsVersion({
PaymentId: response.PaymentId,
CardData: cardData,
});
Функция, которая отправляет запрос в сервис аутентификации банка (по ACSUrl
) в зависимости от версии 3D-Secure
. Возвращает Response с HTML формочкой, которую браузер сабмитнет сразу. Вместо этого метода рекомендуется использовать элемент form
в <body onload="document.form.submit()">
.
const response = await fetchACSUrl(finishAuthorize.ACSUrl, threeDS.version, {
MD: finishAuthorize.MD,
PaReq: finishAuthorize.PaReq,
TermURL: "https://example.com",
// other data
});
Функция для получения строкового представления creq
(нужен для 3DS 2.0)
const str = encryptCReq({
threeDSServerTransID: data.threeDSServerTransID,
acsTransID: data.acsTransID,
challengeWindowSize: data.challengeWindowSize,
messageType: "CReq",
messageVersion: threeDS.version,
});
Функция для получения строкового представления ThreeDSMethodData
const tds = await тк.check3dsVersion({
PaymentId: response.PaymentId,
CardData: CardData,
});
if (tds.ThreeDSMethodURL && tds.TdsServerTransID) {
const data = encryptThreeDSMethodData({
threeDSMethodNotificationURL: tds.ThreeDSMethodURL,
threeDSServerTransID: tds.TdsServerTransID,
});
}