Opening gFinOS

Securing your workspace…

Embedded Finance SDK — Sandbox

Issue wallets and cards from your app. All endpoints are same-shape between test and live — just swap the key prefix.

Register apps & mint keys: /merchant/sdk ·  OpenAPI: /api/public/openapi.json

1. Authentication

# All SDK requests are Bearer-authenticated. Test keys start with sk_test_, live keys with sk_live_.
# Mint keys under /merchant/sdk and store them server-side only.
curl -s "https://project--5d71d9ce-9982-40e9-98e6-17efab07f151.lovable.app/api/public/sdk/v1/wallets/user_123" \
  -H "Authorization: Bearer sk_test_..."

2. Idempotency

# Every write accepts an Idempotency-Key header. Repeat requests with the same key
# within 24h return the original response and the idempotent_replay: true flag.
curl -s -X POST "https://project--5d71d9ce-9982-40e9-98e6-17efab07f151.lovable.app/api/public/sdk/v1/wallets" \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId":"user_123","currency":"USD","email":"jane@example.com"}'

3. Rate limits

# 60 requests / minute / key. Every response includes:
#   x-ratelimit-limit: 60
#   x-ratelimit-remaining: 47
#   x-efinos-schema-version: 1.1
# Exceeding the limit returns 429 with Retry-After: 60.

4. Issue a card

# Issue an embedded virtual card for a provisioned wallet.
curl -s -X POST "https://project--5d71d9ce-9982-40e9-98e6-17efab07f151.lovable.app/api/public/sdk/v1/cards" \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: card_user_123_v1" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId":"user_123","kind":"virtual","currency":"USD","spendLimit":500}'

5. Webhook signature verification

// Verify every gFinOS webhook you receive. Signature is HMAC-SHA256 over the raw body.
// Your app-specific secret is derived from WEBHOOK_DISPATCH_SECRET + your app id, and
// is available in your app profile under /merchant/sdk (never commit it).
import { createHmac, timingSafeEqual } from "crypto";

export function verifyEfinosWebhook(rawBody: string, header: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(header, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

// In your webhook handler:
// const sig = req.headers.get("x-efinos-signature");
// if (!verifyEfinosWebhook(await req.text(), sig, MY_APP_SECRET)) return new Response("bad sig", { status: 401 });

6. Webhook events

wallet.provisioned  — fired after issueWallet
card.issued         — fired after issueCard
card.authorized     — fired on tap or SDK spend
card.captured       — fired on merchant capture
card.refunded       — fired on refund

Every payload:
{
  "event": "wallet.provisioned",
  "schema_version": "1.1",
  "sent_at": "2026-07-20T12:00:00Z",
  "data": { ... }
}

Errors