Preskoči na sadržaj
AMIO
Meni

AMIO za programere

Povežite kasu, internet prodavnicu ili sistem banke sa AMIO. API daje iste rezultate kao rad u aplikaciji, sa istim pravilima, ulogama i revizorskim tragom.

OpenAPI specifikacija

Autentifikacija

Administrator vaše organizacije pravi API ključ u aplikaciji, u odeljku Za programere. Ključ šaljete u zaglavlju Authorization: Bearer amio_live_... uz svaki zahtev ka /api/public/v1. Ključ se prikazuje samo jednom i može se povući u svakom trenutku.

API je namenjen serverima, ne pregledačima: CORS nije uključen, a ključ nikada ne stavljajte u kod koji se izvršava kod kupca.

curl https://www.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]}'

Uloge i prava

Svaki ključ ima jednu ulogu vaše organizacije, izabranu pri pravljenju, i sme samo ono što sme ta uloga u aplikaciji. Ključ može biti i samo za čitanje. Trgovci: administrator, menadžer i zaposleni; partneri: administrator, odobravalac i analitičar.

Ključ radi u ime osobe koja ga je napravila i prestaje da radi kada ta osoba više nije član tima. Ograničenje je 120 zahteva u minuti po ključu; preko toga dobijate 429 i zaglavlje Retry-After.

Idempotentnost

Svaki POST i PUT zahtev mora imati zaglavlje Idempotency-Key, na primer UUID. Ponovljen zahtev sa istim ključem i istim telom vraća isti odgovor (sa zaglavljem Idempotent-Replayed), pa se ponuda ili povraćaj nikada ne naprave dvaput. Isti ključ sa drugačijim telom vraća 409 IDEMPOTENCY_CONFLICT. Ključevi se pamte 24 sata.

Greške i iznosi

Greške uvek imaju isti oblik: error.code, error.message i error.correlationId, a isti identifikator je i u zaglavlju X-Correlation-Id. Navedite ga kada se obraćate podršci. Izmene koriste verzije: pošaljite version koju ste poslednji put dobili; ako se u međuvremenu nešto promenilo, dobijate 409 sa razlogom VERSION_CONFLICT.

Iznosi su uvek objekat { amountMinor, currency }, gde je amountMinor ceo broj u najmanjoj jedinici valute, zapisan kao tekst, na primer "12990000" za 129.900,00 RSD.

{
  "error": {
    "code": "CONFLICT",
    "message": "VERSION_CONFLICT",
    "reason": "VERSION_CONFLICT",
    "correlationId": "c0a8..."
  }
}

Webhook obaveštenja

Administrator dodaje adresu i bira događaje. AMIO šalje POST sa JSON telom { id, type, createdAt, livemode, data } kada se status promeni. Odgovorite statusom 2xx u roku od 10 sekundi; neuspele isporuke ponavljamo sa sve dužim razmacima, a poslednji pokušaji su vidljivi u aplikaciji.

Svaka poruka ima zaglavlje AMIO-Signature: t=<unix vreme>,v1=<hex HMAC-SHA256 nad "t.telo">, potpisano tajnom adrese. Proverite potpis nad sirovim telom i odbacite stare poruke. Isti događaj može stići više puta; koristite id da ga obradite jednom.

  • Trgovci: quote.created, quote.status_changed, application.status_changed, refund.status_changed
  • Partneri: 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);
// });

Ugrađeni ekrani

Ekrane za novu ponudu i status ponude možete prikazati u svom portalu u iframe-u: /{locale}/embed/merchant/quotes/new i /{locale}/embed/merchant/quotes/{id}. Administrator prvo dodaje adresu portala; sa svih drugih adresa pregledač blokira prikaz (Content-Security-Policy: frame-ancestors).

Pregledači ne šalju AMIO kolačić prijave u iframe na drugom sajtu, zato vaš server traži jednokratni token: POST /api/public/v1/embed-tokens. Token važi 5 minuta i AMIO ga pri prvom otvaranju menja za kratku sesiju samo za vašu firmu, sa ulogom ključa. Ako je portal na istom sajtu kao AMIO, radi i obična prijava (otvorite je u iskačućem prozoru).

// On your server, with a merchant key:
const response = await fetch("https://www.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>

Test okruženje

Ključevi koji počinju sa amio_test_ postoje samo u test okruženju i tamo rade sa test partnerom. U produkciji se koriste samo amio_live_ ključevi. Ponude trgovca koji još nije aktivan su uvek označene kao test (mode SANDBOX, livemode false u webhook porukama).