VittasVittas Docs

Core Concepts → Payment Sessions

Payment Sessions

A payment session is a single, time-bounded payment intent. It holds the amount, payer info, an auto-generated virtual bank account, and a status that updates in real time as the payment is processed. Sessions expire after 15 minutes by default.

Create a session (server-side)

Before opening the payment widget your backend creates a session using your secret key. The response includes a clientSecret (cs_…) that you forward to the frontend — the widget uses it to bootstrap the checkout.

POST/api/widget/sessionsAuth

Creates a payment session and returns a clientSecret for the widget.

Request body

amount*integerAmount in kobo (₦1 = 100 kobo). Minimum: 100 (₦1).
currency*stringISO 4217 currency code. e.g. "NGN".
referencestringYour idempotency key — auto-generated if omitted.
payerNamestringPre-fills the customer name in the widget.
payerEmailstringPre-fills the customer email.
payerPhonestringPre-fills the customer phone number.
metadataobjectArbitrary key-value pairs echoed in webhooks.
create-session.js
javascript
const response = await fetch(
  // Use dev-api for test keys, api for live keys
  '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
      currency:   'NGN',
      reference:  'ORDER-001',
      payerName:  'Ada Lovelace',
      payerEmail: 'ada@example.com',
      payerPhone: '+2348012345678',
      metadata:   { orderId: 'ORD-001' },
    }),
  }
);

const { data } = await response.json();
const { sessionId, clientSecret } = data.result;
// Forward clientSecret to your frontend — the widget calls VittasPay.init({ clientSecret })
response
json
{
  "meta": { "statusCode": 201, "message": "Created" },
  "data": {
    "result": {
      "sessionId":    "3f7e2a1b-0000-0000-0000-000000000000",
      "clientSecret": "cs_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
  }
}

Never expose clientSecret beyond the current request

The clientSecret is single-use and short-lived. Do not log it, store it in a database, or cache it. Return it directly to the frontend response and discard it.

Get session status

Poll this endpoint from your backend to check whether a session has been paid. Authenticate with your secret key — no additional headers required.

GET/api/widget/sessions/:idAuth

Returns the current status and key details of a session.

get-session.js
javascript
const { data } = await fetch(
  `https://dev-api.core.vittasinternational.com/api/widget/sessions/${sessionId}`,
  {
    headers: { Authorization: `Bearer ${process.env.VITTAS_SECRET_KEY}` },
  }
).then(r => r.json());

const session = data.result;
console.log(session.status);     // 'pending' | 'successful' | 'expired' | ...
console.log(session.paidAmount); // amount actually received (null if not yet paid)
response
json
{
  "meta": { "statusCode": 200, "message": "OK" },
  "data": {
    "result": {
      "id":         "3f7e2a1b-0000-0000-0000-000000000000",
      "status":     "successful",
      "reference":  "ORDER-001",
      "amount":     500000,
      "paidAmount": 500000,
      "currency":   "NGN"
    }
  }
}

Session lifecycle

pending
successful
mismatch
expired
cancelled
failed

All sessions start as pending. They transition to a terminal state exactly once, triggered either by an incoming bank transfer or by the expiry timer.

StatusDescription
pendingSession created; awaiting payment transfer.
successfulCorrect amount received and confirmed.
mismatchTransfer received but amount differed from expected.
expiredNo transfer received before the session TTL elapsed.
cancelledPayer or merchant explicitly cancelled the session.
failedAn unrecoverable error occurred during processing.

Prefer webhooks over polling

Rather than polling GET /api/widget/sessions/:id, configure a webhook endpoint to receive payment.successful and payment.failed events instantly as they happen. See the Webhooks guide for setup instructions.