Developers

Integration guide.

Drop a container div and a single script tag on your booking page. The widget reads your booking total and travel date, runs the customer through KYC and 3D Secure, and posts back a confirmed booking reference. No payment-page rebuild required.

Quick start

Drop these two snippets on your booking page where you want the payment widget to render. The widget reads data-* attributes from the container and calls our API on mount.

booking-page.html
<!-- 1. Container — the widget renders into this div -->
<div
  id="kalva-widget"
  data-amount="3500"
  data-currency="USD"
  data-travel-date="2026-08-15"
  data-merchant-key="YOUR_MERCHANT_KEY"
  data-description="Overwater Suite — 5 nights"
></div>

<!-- 2. Script — async, loads from Kalva's CDN -->
<script src="https://widget.kalva.app/v1.js" async></script>

That's it. The widget handles installment-plan display, KYC capture, Stripe Elements with 3D Secure, and the booking confirmation lifecycle.

Data attributes

Configure widget behaviour by setting these attributes on the container element.

AttributeRequiredDescription
data-amountYesBooking total in the currency below. Integer or decimal — e.g. 3500 or 3500.00.
data-currencyYesISO 4217 code. USD only at launch.
data-travel-dateYesISO 8601 date — the check-in or experience date. Determines available installment plans.
data-merchant-keyYesYour operator merchant key from the dashboard.
data-descriptionNoHuman-readable description shown in the widget header (e.g. "Overwater Suite — 5 nights").
data-success-urlNoURL the widget redirects to after a successful booking. Defaults to your dashboard.

Test mode

Use a test merchant key (prefix test_) for sandbox bookings. No real charges; Stripe's test card matrix applies.

CardBehaviour
4242 4242 4242 4242Default success — auto-authorises
4000 0027 6000 3184Forced 3D Secure challenge
4000 0000 0000 9995Insufficient funds — failed installment
4000 0000 0000 0002Generic decline

Any CVV. Any future expiry. Any postal code.

Plan API

Server-side: fetch the available installment plans for a given amount and travel date. Useful if you want to preview plans on your own pricing page before the widget mounts.

POST /api/widget/plans
{
  "merchantKey": "YOUR_MERCHANT_KEY",
  "amount": 3500,
  "travelDate": "2026-08-15T00:00:00.000Z"
}

// Response
{
  "success": true,
  "data": [
    { "plan": "PAY_FULL",  "count": 1, "installmentAmount": 3500 },
    { "plan": "PAY_IN_2",  "count": 2, "installmentAmount": 1750 },
    { "plan": "PAY_IN_3",  "count": 3, "installmentAmount": 1167 },
    { "plan": "PAY_IN_4",  "count": 4, "installmentAmount":  875 },
    { "plan": "PAY_IN_6",  "count": 6, "installmentAmount":  584 }
  ]
}

Webhooks

Configure a webhook endpoint in the operator dashboard. Kalva posts JSON to that URL on every lifecycle event. Each request is HMAC-signed with your webhook secret in the Kalva-Signature header.

POST → your webhook URL
{
  "event": "booking.confirmed",
  "createdAt": "2026-08-29T14:22:01.000Z",
  "data": {
    "reference": "KLV-7F3A2B1C",
    "merchantKey": "merch_abc123",
    "amount": 3500,
    "currency": "USD",
    "commission": 245,
    "netPayout": 3255,
    "plan": "PAY_IN_4",
    "customer": {
      "email": "customer@example.com",
      "country": "US",
      "kycTier": 1
    },
    "travelDate": "2026-08-15T00:00:00.000Z"
  }
}

Event types you should handle:

  • booking.reserved — first installment cleared, booking in Reserved status.
  • booking.confirmed — final installment cleared. Honour the booking.
  • booking.cancelled — customer or auto-cancellation. Free up inventory.
  • payout.sent — Stripe Connect payout initiated to your account.

Authentication

The widget script and the plan API use a public merchant key — safe to embed in page source. Server-side endpoints (cancellations, refund adjustments) require a secret API key, available from your operator dashboard under Settings → API. Never embed secret keys in client code.

Going live

  1. Complete operator onboarding KYB in your dashboard.
  2. Connect a Stripe Connect Standard account for payouts.
  3. Swap your test merchant key for the live key in the widget.
  4. Verify your webhook endpoint receives a test event from the dashboard.
  5. Place a real booking with your own credit card to validate end-to-end.

Most operators are live the same working day they finish KYB.

Support

Integration questions: hello@kalva.app. Security disclosure: security@kalva.app. General operator help: /help.