VittasVittas Docs

Overview → Getting Started

Quick Start

Start accepting payments in minutes

Your backend creates a payment session, receives a short-lived clientSecret, then passes it to the Vittas widget — which handles the entire checkout experience. Amount and currency are locked server-side, so they cannot be tampered with from the browser.

Before you begin

  • A Vittas Core business account sign up at core.vittasinternational.com. Business owners and admins can access the portal immediately. To grant a developer access, go to Team → Invite member and assign the Developer role.
  • Node.js 18+ or any backend runtime (examples use Node.js)
  • A publicly reachable HTTPS URL for webhook delivery (use webhook.site for testing)
1

Get your secret key

Log in to the developer portal and navigate to API Keys. Copy your secret key — you will use it on your server to create payment sessions.

Key typePrefixUsage
Secret keysk_test_… / sk_live_…Server-side only — creates sessions, processes refunds, calls webhooks.
Client secretcs_…Short-lived, single-use credential returned by the session endpoint. Pass this to the widget.

Keep your secret key safe

Never commit secret keys to version control or include them in client-side code. Use environment variables: VITTAS_SECRET_KEY=sk_test_…
2

Create a session on your backend

Before opening the widget, your server calls the Vittas API to create a payment session. This locks the amount and currency server-side and returns a clientSecret (cs_…) that your frontend will pass to the widget.

server.js (Node.js example)
javascript
app.post('/api/checkout', async (req, res) => {
  const response = await fetch(
    'https://dev-api.core.vittasinternational.com/api/widget/sessions',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.VITTAS_SECRET_KEY}`,
        'Content-Type':  'application/json',
      },
      body: JSON.stringify({
        amount:     500000,             // ₦5,000 in kobo (₦1 = 100 kobo)
        currency:   'NGN',
        reference:  'ORDER-001',        // your idempotency key — auto-generated if omitted
        payerName:  'Ada Lovelace',
        payerEmail: 'ada@example.com',
        payerPhone: '+2348012345678',
        metadata:   { orderId: 'ORD-001' },
      }),
    }
  );

  const { data } = await response.json();
  // Return the clientSecret to your frontend — never log or store it
  res.json({ clientSecret: data.result.clientSecret });
});

Use dev-api for TEST, api for LIVE

https://dev-api.core.vittasinternational.com — test environment (sk_test_…)
https://api.core.vittasinternational.com — production (sk_live_…)
3

Open the widget with the client secret

Load the CDN widget script and call VittasPay.init() with the clientSecret your server returned. The widget handles the entire checkout — virtual account display, countdown, real-time confirmation.

checkout.html
html
<!-- Load from the CDN that matches your environment -->
<!-- TEST:  https://dev-cdn.core.vittasinternational.com/latest/widget.js -->
<!-- LIVE:  https://cdn.core.vittasinternational.com/latest/widget.js     -->
<script src="https://dev-cdn.core.vittasinternational.com/latest/widget.js"></script>

<button id="pay-btn">Pay 5,000</button>

<script>
  document.getElementById('pay-btn').addEventListener('click', async () => {
    // Fetch a fresh clientSecret from YOUR backend  never hard-code it
    const { clientSecret } = await fetch('/api/checkout', { method: 'POST' })
      .then(r => r.json());

    window.VittasPay.init({
      clientSecret,

      onSuccess(ref) {
        // ref: { id, reference, status }
        window.location.href = '/order/success?ref=' + ref.reference;
      },
      onCancel() {
        console.log('Payment cancelled.');
      },
      onError(err) {
        console.error('Widget error:', err.message);
      },
    });
  });
</script>

React / Next.js

Use the @vittascore/payment-widget-react npm package for a typed React component and hook. See the SDK reference.
4

Listen for webhooks

Vittas sends a signed POST request to your webhook URL when payment events occur. Set your endpoint URL in the portal under Webhooks.

webhook-handler.js
javascript
const express = require('express');
const crypto  = require('crypto');
const app     = express();

// IMPORTANT: use raw body — do NOT use express.json() before this route
app.post('/webhooks/vittas', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-vittas-signature'];
  const rawBody   = req.body;

  // Verify signature
  if (!verifySignature(signature, rawBody, process.env.VITTAS_WEBHOOK_SECRET)) {
    return res.status(401).send('Signature mismatch');
  }

  const event = JSON.parse(rawBody);

  switch (event.type) {
    case 'payment.successful':
      fulfillOrder(event.data.reference);
      break;
    case 'payment.expired':
      cancelOrder(event.data.reference);
      break;
  }

  res.status(200).json({ received: true });
});

function verifySignature(header, body, secret) {
  const [tPart, v1Part] = header.split(',');
  const t  = tPart.split('=')[1];
  const v1 = v1Part.split('=')[1];

  // Reject if older than 5 minutes
  if (Math.abs(Date.now() / 1000 - parseInt(t)) > 300) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${body}`)
    .digest('hex');

  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
5

Go live checklist

Live keys only work after your business KYC has been approved. Test keys are always available.