orvacon

Get started

Install orvacon, wire a gateway, and take your first payment.

orvacon installs into your own app — there is no hosted service. You bring a database and a gateway account; orvacon orchestrates the rest.

Install

bun add @orvacon/paykit @orvacon/connector-iyzico @orvacon/adapter-supabase @orvacon/adapter-nextjs postgres

Generate keys and schema

npx orvacon keys      # Ed25519 webhook signing keypair → ORVACON_WEBHOOK_SIGNING_KEY
npx orvacon generate  # Postgres schema with default-deny row-level security

Configure

lib/orva.ts
import { orvacon } from "@orvacon/paykit";
import { iyzico } from "@orvacon/connector-iyzico";
import { supabaseAdapter } from "@orvacon/adapter-supabase";
import postgres from "postgres";

const sql = postgres(process.env.SUPABASE_DB_URL!, { prepare: false });

export const orva = orvacon({
  database: supabaseAdapter({ sql }),
  connectors: [
    iyzico({
      apiKey: process.env.IYZICO_API_KEY!,
      secretKey: process.env.IYZICO_SECRET_KEY!,
    }),
  ],
  webhookSigningKey: process.env.ORVACON_WEBHOOK_SIGNING_KEY!,
  webhookUrl: "https://your-app.com/api/webhooks/orvacon",
});

Config is validated fail-fast — a missing or malformed key throws at setup, not at the first payment.

Take a payment

import { idempotencyKey, money } from "@orvacon/paykit";

const outcome = await orva.authorize({
  amount: money(1499, "TRY"), // 14.99 TRY, in minor units
  source: { type: "card", card },
  threeDSecure: true,
  callbackUrl: "https://your-app.com/api/orva/callback/iyzico",
  idempotencyKey: idempotencyKey(crypto.randomUUID()),
});

if (outcome.ok && outcome.status === "requires_action") {
  renderChallenge(outcome.action); // { type: "html", content } — hand it to the browser
}

A 3-D Secure payment returns requires_action; orvacon persists that state and resumes from the signed finalize when the browser returns — it never trusts the raw callback POST. Check outcome.ok first, then outcome.status.

Wire the callback (Next.js)

app/api/orva/callback/[connector]/route.ts
import { toNextJsHandler } from "@orvacon/adapter-nextjs";
import { orva } from "@/lib/orva";

export const { POST } = toNextJsHandler(orva, {
  returnUrl: { success: "/checkout/done", failure: "/checkout/failed" },
});

Make the callback route public

The gateway redirects the browser to your callback with no session — exclude /api/orva/callback from your middleware, or an auth check will silently strand payments.

On this page