vellTRDocs
GuidesGetting Started

Getting Started

Beginner10 min

Create your account, grab API keys, and make your first signed request in minutes.


This guide takes you from a blank account to a working, signed API call against Kvell β€” creating your merchant account, grabbing sandbox keys, and launching your first hosted checkout session. Every example below is copy-pasteable.

What you'll need

  • A Kvell merchant account (sign up takes a couple of minutes)
  • A terminal for curl, or any HTTP client
  • Node.js 18+ if you want to run the signature example locally

1. Create your merchant account and a store

Kvell is store-scoped: a merchant account owns one or more stores, and every API key, webhook endpoint, and payment belongs to exactly one store. Most integrations only ever need one store, but the model lets you separate, say, a web storefront from a mobile app under the same merchant without mixing their traffic.

  1. Sign up for a Kvell account.
  2. Create your first store from the dashboard (you're prompted for this automatically on first login).
  3. Open Integration in the left nav β€” this is where your API keys and webhook endpoints live.

2. Grab your API keys

Every store has two key pairs: one for the sandbox and one for live traffic. Each pair has a public key and a secret key.

KeyPrefixWhere it's used
Public key (sandbox)pk_demo_…X-Api-Key header, and card tokenization calls from the browser
Secret key (sandbox)sk_demo_…Signs requests locally β€” never sent over the wire
Public key (live)pk_live_…Same as above, production traffic
Secret key (live)sk_live_…Same as above, production traffic

Your secret key never leaves your server. It's used only to compute the X-Signature header (see Authentication & Request Signing) β€” Kvell never asks for it directly, and no legitimate API call ever includes it in a request body or header.

Start with the sandbox pair. Sandbox traffic hits https://api.pay.sandbox.kvell.group and never touches a real bank β€” see Testing in the Sandbox for how to force specific outcomes.

3. Compute your first signature and make a request

Every signed request needs three headers: X-Api-Key, X-Timestamp, and X-Signature. The signature is an HMAC-SHA256 over a canonical string built from the timestamp, method, path, and a hash of the body β€” the full mechanics are in Authentication & Request Signing; here's the minimum to get a request out the door.

A read-only GET request has no body, so the body hash is just the SHA-256 of an empty string:

TypeScript
import crypto from 'node:crypto';

const secretKey = process.env.KVELL_SECRET_KEY!; // sk_demo_...
const timestamp = new Date().toISOString(); // e.g. 2026-04-13T10:00:00.000Z
const method = 'GET';
const path = '/v1/installments'; // route path only β€” no query string

const bodyHash = crypto.createHash('sha256').update('').digest('hex');
const canonical = `${timestamp}\n${method}\n${path}\n${bodyHash}`;
const signature = crypto.createHmac('sha256', secretKey).update(canonical).digest('hex');

console.log({ timestamp, signature });

Now send it β€” the query string (?bin=…&amount=…) is part of the URL you request, but it is not part of what you sign:

Shell
curl "https://api.pay.sandbox.kvell.group/v1/installments?bin=415565&amount=15000" \
  -H "X-Api-Key: pk_demo_a1b2c3d4e5f6g7h8" \
  -H "X-Timestamp: 2026-04-13T10:00:00.000Z" \
  -H "X-Signature: <signature from above>"

A working call returns the eligible installment plans for that card BIN and amount:

JSON
{
  "bin": "415565",
  "bank": "Garanti BBVA",
  "brand": "visa",
  "cardType": "credit",
  "country": "TR",
  "eligiblePlans": [
    { "count": 1, "commissionRate": 0.019 },
    { "count": 3, "commissionRate": 0.035 },
    { "count": 6, "commissionRate": 0.065 }
  ]
}

If you get back a KVELL-GW-1002 instead, your signature doesn't match what the server computed β€” jump to the troubleshooting checklist in the authentication guide.

4. Create your first hosted checkout session

A signed GET proves your keys work β€” but the call you'll actually build on is creating a payment session. Kvell's hosted checkout collects the card, runs 3DS when required, and shows the installment picker, so you don't have to build any of that yourself.

Shell
curl -X POST https://api.pay.sandbox.kvell.group/v1/payments/sessions \
  -H "X-Api-Key: pk_demo_a1b2c3d4e5f6g7h8" \
  -H "X-Timestamp: 2026-04-13T10:00:00Z" \
  -H "X-Signature: <computed signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionId": "ORDER-2026-001",
    "amount": 15000,
    "currency": "TRY",
    "description": "Order #1234",
    "returnUrl": "https://merchant.example.com/return"
  }'

amount is always an integer in kuruş β€” 1/100 of a Turkish lira. 15000 is 150.00 TRY. Kvell never accepts or returns floating-point money.

The response gives you a hosted page to send your buyer to:

JSON
{
  "sessionId": "3f1c9a2e-6b4d-4e8a-9c1f-2a7b8c9d0e1f",
  "checkoutUrl": "https://pay.kvell.group/s/3f1c9a2e-6b4d-4e8a-9c1f-2a7b8c9d0e1f",
  "expiresAt": "2026-04-13T10:30:00Z",
  "merchantId": "mrc_8a1b2c3d4e5f",
  "amount": 15000,
  "currency": "TRY",
  "status": "active"
}

Redirect the buyer's browser to checkoutUrl. The session is valid for 30 minutes (expiresAt); after that, create a fresh one.

5. Confirm the payment

When the buyer finishes on the hosted page, Kvell redirects them back to your returnUrl. Treat that redirect as a hint, never as proof of payment β€” the buyer's browser is not a trustworthy source of truth. The reliable signal is the payment.captured event delivered to your webhook endpoint; see Webhooks to set one up.

Next steps

GuideWhat it covers
Authentication & Request SigningThe full signing algorithm, idempotency keys, and troubleshooting
Accepting Card PaymentsHosted checkout vs. direct API, 3DS, refunds, preauth/capture
WebhooksRegistering endpoints, verifying signatures, retries
Installment Payments (Taksit)BIN lookup, the installment picker, commission math
Testing in the SandboxForcing specific outcomes with X-Sim-Scenario
API ReferenceEvery endpoint, request, and response shape