AMIO за програмере
Повежите касу, интернет продавницу или систем банке са AMIO. API даје исте резултате као рад у апликацији, са истим правилима, улогама и ревизорским трагом.
Аутентификација
Администратор ваше организације прави API кључ у апликацији, у одељку За програмере. Кључ шаљете у заглављу Authorization: Bearer amio_live_... уз сваки захтев ка /api/public/v1. Кључ се приказује само једном и може се повући у сваком тренутку.
API је намењен серверима, не прегледачима: CORS није укључен, а кључ никада не стављајте у код који се извршава код купца.
curl https://hub.getamio.com/api/public/v1/quotes \
-H "Authorization: Bearer amio_live_..." \
-H "Idempotency-Key: 6f1c2f9e-6d0b-4f7e-9a51-2c8f2f4b7a10" \
-H "Content-Type: application/json" \
-d '{"amount":{"amountMinor":"12990000","currency":"RSD"},
"description":"Laptop","instalments":[6,12]}'Улоге и права
Сваки кључ има једну улогу ваше организације, изабрану при прављењу, и сме само оно што сме та улога у апликацији. Кључ може бити и само за читање. Трговци: администратор, менаџер и запослени; партнери: администратор, одобравалац и аналитичар.
Кључ ради у име особе која га је направила и престаје да ради када та особа више није члан тима. Ограничење је 120 захтева у минути по кључу; преко тога добијате 429 и заглавље Retry-After.
Идемпотентност
Сваки POST и PUT захтев мора имати заглавље Idempotency-Key, на пример UUID. Поновљен захтев са истим кључем и истим телом враћа исти одговор (са заглављем Idempotent-Replayed), па се понуда или повраћај никада не направе двапут. Исти кључ са другачијим телом враћа 409 IDEMPOTENCY_CONFLICT. Кључеви се памте 24 сата.
Грешке и износи
Грешке увек имају исти облик: еррор.цоде, еррор.мессаге и еррор.correlationId, а исти идентификатор је и у заглављу X-Correlation-Id. Наведите га када се обраћате подршци. Измене користе верзије: пошаљите версион коју сте последњи пут добили; ако се у међувремену нешто променило, добијате 409 са разлогом VERSION_CONFLICT.
Износи су увек објекат { amountMinor, currency }, где је amountMinor цео број у најмањој јединици валуте, записан као текст, на пример "12990000" за 129.900,00 RSD.
{
"error": {
"code": "CONFLICT",
"message": "VERSION_CONFLICT",
"reason": "VERSION_CONFLICT",
"correlationId": "c0a8..."
}
}Webhook обавештења
Администратор додаје адресу и бира догађаје. AMIO шаље POST са JSON телом { ид, type, createdAt, ливемоде, дата } када се статус промени. Одговорите статусом 2xx у року од 10 секунди; неуспеле испоруке понављамо са све дужим размацима, а последњи покушаји су видљиви у апликацији.
Свака порука има заглавље AMIO-Signature: т=<unix време>,в1=<hex HMAC-SHA256 над "т.тело">, потписано тајном адресе. Проверите потпис над сировим телом и одбаците старе поруке. Исти догађај може стићи више пута; користите ид да га обрадите једном.
- Трговци: quote.created, quote.status_changed, application.status_changed, refund.status_changed
- Партнери: application.status_changed, deferral.requested, deferral.decided
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received (a string), before JSON.parse.
export function verifyAmioWebhook(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
String(header ?? "").split(",").map((part) => part.trim().split("=", 2)),
);
const timestamp = Number(parts.t);
if (!parts.v1 || !Number.isInteger(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;
const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest();
const given = Buffer.from(parts.v1, "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}
// Express: app.post("/amio/webhooks", express.text({ type: "*/*" }), (req, res) => {
// if (!verifyAmioWebhook(req.body, req.get("AMIO-Signature"), process.env.AMIO_WEBHOOK_SECRET))
// return res.sendStatus(400);
// const event = JSON.parse(req.body); // { id, type, createdAt, livemode, data }
// res.sendStatus(200);
// });Уграђени екрани
Екране за нову понуду и статус понуде можете приказати у свом порталу у iframe-у: /{locale}/embed/merchant/quotes/new и /{locale}/embed/merchant/quotes/{id}. Администратор прво додаје адресу портала; са свих других адреса прегледач блокира приказ (Content-Security-Policy: фраме-анцесторс).
Прегледачи не шаљу AMIO колачић пријаве у iframe на другом сајту, зато ваш сервер тражи једнократни токен: POST /api/public/v1/embed-tokens. Токен важи 5 минута и AMIO га при првом отварању мења за кратку сесију само за вашу фирму, са улогом кључа. Ако је портал на истом сајту као AMIO, ради и обична пријава (отворите је у искачућем прозору).
// On your server, with a merchant key:
const response = await fetch("https://hub.getamio.com/api/public/v1/embed-tokens", {
method: "POST",
headers: {
Authorization: "Bearer amio_live_...",
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ locale: "sr-Latn-RS" }), // or { quoteId } for one quote's status
});
const { url } = await response.json();
// In your portal page (an origin registered under Developers):
// <iframe src="{url}" width="480" height="820" title="AMIO"></iframe>Тест окружење
Кључеви који почињу са amio_test_ постоје само у тест окружењу и тамо раде са тест партнером. У продукцији се користе само amio_live_ кључеви. Понуде трговца који још није активан су увек означене као тест (моде SANDBOX, ливемоде фалсе у webhook порукама).
Повезивање банке
Банка повезује своје кредитне системе преко Генериц Банк Интегратион API-ја: једног верзионисаног HTTP уговора који банка имплементира, па свака банка користи исти адаптер. Покрива захтев, одлуку, понуде, прихватање, исплату, повраћаје, план отплате и одлагања.
Сваки захтев је потписан HMAC-SHA256 потписом са временском ознаком, захтеви који мењају стање носе Idempotency-Key, а нејасан одговор се пре свега другог проверава позивом за статус. Прихвата се само HTTPS.
Опционе могућности, као што су провера идентитета, повраћаји и одлагања, банка наводи у одговору на проверу доступности. Када банка не може да имплементира уговор, могућ је посебан адаптер уз иста правила.