Прескокни до содржината

SDK наплата

Објавено издание: SDK 0.1.3 е јавно достапен на npm. Инсталацијата не активира серверски функции.

Трите npm пакети

Дел „Трите npm пакети“
  • @kordiva/sdk — серверски Node клиент со таен Store API клуч за каталог, checkout.createTest во TEST, checkout.createHosted и payments.confirm во LIVE.
  • @kordiva/checkout — безбедна проверка на exact-origin URL и пренасочување, без клуч и без обработка на картички.
  • @kordiva/react — React/Next.js копче Купи што го повикува вашиот заштитен backend и го отвора URL.
Терминал
pnpm add @kordiva/sdk@0.1.3
pnpm add @kordiva/checkout@0.1.3 @kordiva/react@0.1.3

Вообичаен тек: Копче Купи → ваш автентициран backend → Kordiva серверски SDK → постојна Kordiva/Stripe хостирана наплата → серверска потврда. URL за враќање не докажува успешно плаќање. CMS продавниците, директниот API и Checkout Links остануваат поддржани без SDK.

  1. На сервер автентицирајте го купувачот и одобрете ја кошничката. Изберете одобрени UUID на производи/варијанти и количини; не прифаќајте износ од прелистувач како цена.
  2. За LIVE повикајте client.checkout.createHosted({ lineItems, idempotencyKey, checkoutLanguage: 'en' }). SDK задолжително користи stripe_hosted. Добиениот Kordiva /q/… води кон постојниот хостиран тек; не мора да е директен Stripe URL.
  3. Зачувајте го добиениот sessionId заедно со стабилниот обид и овластениот купувач/кошничка во трајно заштитено складиште. Серијализирајте создавање наплата по кошничка. Не создавајте нов клуч само поради истечено барање.
  4. Предадете само { url: session.checkoutUrl } на прелистувачот и проверете точен доверлив origin.
  5. По враќање, на сервер повикајте client.payments.confirm({ sessionId }). pending или expired не значат платено. Проверете дали купувачот има право да ја види нарачката пред да вратите детали.
  6. Исполнувајте преку соодветниот Kordiva тек. Individual даночни/локациски/задржани платежни и дигитални проверки остануваат; платена проекција сама не дава право на преземање.

Како мојата веб-страница дознава дека е платено? Kordiva ги прима потпишаните Stripe известувања. Вашиот сервер ги чува session UUID и овластениот обид за кошничката. UI потоа повикува заштитен endpoint на вашиот сервер, кој во LIVE повикува client.payments.confirm({ sessionId, idempotencyKey }). Само потврден paid со применливите услови за испорака дозволува исполнување. SDK 0.1.3 додава одделен потпишан Business канал; за претплати видете ги Business водичите подолу. Видете го водичот за статус и webhooks со тестиран Node пример и ограничено проверување.

POST никогаш не се повторува автоматски, ни со idempotency клуч. Серверското пребарување на претходни обиди е ограничено, врзано за клуч и истекува; не гарантира атомско извршување точно еднаш. Усогласете неизвесни резултати пред контролирано повторување со исто тело/клуч. Ротацијата го менува идентитетот за повторување.

Тестираниот обработувач подолу е пример за еден производ. Пред јавна употреба обезбедете вистинска сесиска/кошничка авторизација, ограничување на големина, ограничување по корисник, трајно заклучување и складиште за усогласување. Примерот не е целосен трговски сервер.

server.ts
import type { Kordiva } from "@kordiva/sdk";
export interface CheckoutRouteOptions {
client: Kordiva;
/** Product is selected from your approved server-side catalog. */
productId: string;
storefrontOrigin: string;
/** Authenticate your customer session AND authorize this cart; return a stable opaque actor ref. */
authorize: (request: Request) => Promise<string | null>;
}
/** Shared Web Request/Response handler for a Node backend or Next.js App Router. */
export function createCheckoutRoute({
client,
productId,
storefrontOrigin,
authorize,
}: CheckoutRouteOptions) {
return async function POST(request: Request): Promise<Response> {
const headers = { "cache-control": "no-store" };
if (request.method !== "POST")
return Response.json(
{ error: "Method not allowed" },
{ status: 405, headers },
);
if (request.headers.get("origin") !== storefrontOrigin)
return Response.json(
{ error: "Origin rejected" },
{ status: 403, headers },
);
const actor = await authorize(request);
if (!actor || !/^[A-Za-z0-9_-]{1,48}$/.test(actor))
return Response.json({ error: "Unauthorized" }, { status: 401, headers });
if (!request.headers.get("content-type")?.startsWith("application/json"))
return Response.json(
{ error: "JSON required" },
{ status: 415, headers },
);
const raw = await request.text();
if (raw.length > 1024)
return Response.json(
{ error: "Request too large" },
{ status: 413, headers },
);
let input: unknown;
try {
input = JSON.parse(raw);
} catch {
return Response.json({ error: "Invalid JSON" }, { status: 400, headers });
}
const attempt =
input && typeof input === "object" && "attempt" in input
? input.attempt
: null;
if (typeof attempt !== "string" || !/^[A-Za-z0-9_-]{8,64}$/.test(attempt))
return Response.json(
{ error: "Stable cart attempt required" },
{ status: 400, headers },
);
try {
if (client.environment === "TEST") {
const checkout = await client.checkout.createTest({
productId,
testSaleMarket: "AU",
});
return Response.json({ url: checkout.url }, { headers });
}
const checkout = await client.checkout.createHosted({
lineItems: [{ productId, quantity: 1 }],
idempotencyKey: `${actor}:${attempt}`,
checkoutLanguage: "en",
});
return Response.json({ url: checkout.checkoutUrl }, { headers });
} catch {
// Production host supplies per-actor rate limiting and a durable cart lock.
return Response.json(
{
error:
"Checkout unavailable. Reconcile this attempt before retrying.",
},
{ status: 502, headers },
);
}
};
}

Поврзани водичи

Дел „Поврзани водичи“

SDK · Checkout · Безбедност · API

Recurring checkout and subscription reads → Signed Business events → Raw-body verification → Business refunds → API reference. Individual MoR follows its separate refund process.

Individual Merchant of Record: информации пред купување

Дел „Individual Merchant of Record: информации пред купување“

Вашата страница може да го задржи својот бренд. За Individual продажби, Kordiva, LLC е правниот продавач / Merchant of Record; креаторот ја обезбедува дигиталната содржина. Преземете ги канонските информации преку backend пред да го прикажете копчето Купи, и прикажете ги вратениот текст и линковите до копчето. Business/TP добива неприменлив резултат и го задржува својот модел.

GET /public/catalog/stores/:storeId/buyer-disclosure?locale=en
Authorization: Bearer <SERVER_ONLY_STORE_API_KEY>
Individual disclosure: backend only
// Backend / Next.js server component only. Never import this module into a client bundle.
import type { Kordiva } from "../../../../../../packages/kordiva-sdk/src/index.js";
export async function loadBuyerDisclosure(
client: Kordiva,
locale: "mk" | "en",
) {
return client.buyerDisclosure.get({ locale });
}
Individual disclosure: React and escaped HTML
import React from "react";
import type { BuyerDisclosure } from "../../../../../../packages/kordiva-sdk/src/types.js";
/** Presentation only: consume server-returned wording and links, never reconstruct legal policy. */
export function BuyerDisclosureBlock({
disclosure,
}: {
disclosure: BuyerDisclosure;
}) {
if (!disclosure.applicable) return null;
return (
<aside aria-label="Purchase information">
<p>{disclosure.shortDisclosure}</p>
<nav aria-label="Purchase policies">
<a href={disclosure.links.purchaseTerms}>Purchase Terms</a>{" "}
<a href={disclosure.links.refunds}>Refund Policy</a>{" "}
<a href={disclosure.links.privacy}>Privacy</a>{" "}
<a href={disclosure.links.support}>Purchase Support</a>
</nav>
</aside>
);
}
const escape = (v: string) =>
v.replace(
/[&<>"']/g,
(c) =>
({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[
c
]!,
);
export function renderBuyerDisclosureHtml(disclosure: BuyerDisclosure): string {
if (!disclosure.applicable) return "";
return `<aside aria-label="Purchase information"><p>${escape(disclosure.shortDisclosure)}</p><nav aria-label="Purchase policies">${[
["purchaseTerms", "Purchase Terms"],
["refunds", "Refund Policy"],
["privacy", "Privacy"],
["support", "Purchase Support"],
]
.map(
([key, label]) =>
`<a href="${escape(disclosure.links[key as keyof typeof disclosure.links])}">${label}</a>`,
)
.join(" ")}</nav></aside>`;
}
<!-- Plain HTML: your backend escapes and inserts the returned text and URLs. -->
<aside aria-label="Purchase information">
<p><!-- buyerDisclosure.shortDisclosure, escaped --></p>
<a href="{{purchaseTerms}}">Purchase Terms</a>
<a href="{{refunds}}">Refund Policy</a>
<a href="{{privacy}}">Privacy</a>
<a href="{{support}}">Purchase Support</a>
</aside>

Користете locale: "mk" за македонска наплата. Користете ги вратените вредности; не копирајте правен текст и не составувајте policy URL-адреси. Читањето е преку постојната LIVE API автентикација и може да ја ажурира само постојната телеметрија на клучот. Никогаш не изложувајте API клуч во browser. Тестираните backend, HTML и React примери се во apps/store/src/lib/examples/individual-buyer-disclosure.

Kordiva наплатата независно ги прикажува задолжителните информации и бара потврда плус server-issued preflight proof. Надворешниот блок не ја заменува оваа проверка. Приватноста е известување; не се откажуваат законските права за рефундации или откажување. Browser redirect не е доказ за плаќање: користете payments.confirm() преку backend.

Новиот SDK метод бара идна SDK верзија; тековните објавени верзии можеби не го содржат. Дотогаш користете го REST endpoint по одобрено серверско пуштање. Испраќањето е-пошта останува посебна следна фаза.

Individual е-пошта за потврда: планирана следна фаза

Дел „Individual е-пошта за потврда: планирана следна фаза“

Оваа промена не овозможува испраќање е-пошта од Kordiva. Канонската Individual патека го финализира Order и враќа пред заедничкиот email/PDF pipeline; Stripe потврдите зависат од одделна provider конфигурација. Идната потврда за купувачот ќе користи финализиран Order.billingEmail и непроменлив checkout locale, а не земја на продавач, Store email language или Stripe locale: auto. Известувањето за креаторот независно ќе го користи Store email language. Испораката бара трајни уникатни outbox настани при финализација, не директно испраќање од webhook. Известувањата за достапни средства и банкарска исплата остануваат одделни.