Developers · Live API

The Paytab REST API

This is the API your account actually runs on. No SDK required — every endpoint is plain HTTPS and JSON, authenticated with a key you create yourself in the dashboard.

Get started in three steps

  1. 1. Create a key

    Go to Dashboard → Developers and click Create key. The key belongs to the workspace you are in and is shown once — store it as an environment variable, never in your frontend or a git repo.

  2. 2. Call the API

    Every request goes to https://paytab.co.uk/api/v1 with your key in the Authorization header as a Bearer token. Send JSON bodies with Content-Type: application/json.

  3. 3. Listen for webhooks

    Add an endpoint URL in the dashboard. We POST a signed JSON event whenever a payment succeeds or is refunded, so you can fulfil orders reliably.

Authentication

Send your secret key as a Bearer token on every request. Keys starting sk_live_ never move real money; keys starting sk_live_ do.

curl https://paytab.co.uk/api/v1/account \
  -H "Authorization: Bearer sk_live_..."

Endpoints

GET/api/v1/account

Your account, its country, currency and which payment capabilities are live.

Request
curl https://paytab.co.uk/api/v1/account \
  -H "Authorization: Bearer sk_live_..."
Response
{
  "object": "account",
  "id": "acct_...",
  "business_name": "Ada's Coffee",
  "country": "GB",
  "default_currency": "gbp",
  "charges_enabled": true,
  "payouts_enabled": true,
  "capabilities": { "card_payments": "active" }
}
POST/api/v1/payments

Create a payment. Returns a client_secret you confirm in the browser, or a completed payment when a saved method is passed.

amount
integer, required — smallest currency unit (4999 = £49.99)
currency
string, required — e.g. gbp, eur, usd
description
string, optional — shows on the statement and dashboard
customer
string, optional — a Paytab customer id
payment_method
string, optional — confirms immediately when supplied
metadata
object, optional — up to 20 key/value pairs
Request
curl https://paytab.co.uk/api/v1/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4999,
    "currency": "gbp",
    "description": "Pro plan",
    "metadata": { "order_id": "4102" }
  }'
Response
{
  "object": "payment",
  "id": "pay_...",
  "amount": 4999,
  "currency": "gbp",
  "status": "requires_payment_method",
  "client_secret": "pi_..._secret_...",
  "metadata": { "order_id": "4102" },
  "created": "2026-01-08T10:22:41.000Z"
}
GET/api/v1/payments

List payments, newest first.

limit
integer, optional — 1 to 100, default 25
status
string, optional — filter by payment status
Request
curl "https://paytab.co.uk/api/v1/payments?limit=10&status=succeeded" \
  -H "Authorization: Bearer sk_live_..."
Response
{
  "object": "list",
  "data": [ { "object": "payment", "id": "pay_...", "amount": 4999 } ],
  "has_more": false
}
GET/api/v1/payments/:id

Retrieve a single payment by its Paytab id.

Request
curl https://paytab.co.uk/api/v1/payments/pay_123 \
  -H "Authorization: Bearer sk_live_..."
Response
{ "object": "payment", "id": "pay_123", "status": "succeeded" }
POST/api/v1/payments/:id/refund

Refund a payment in full, or partially by passing an amount.

amount
integer, optional — defaults to the full amount
reason
string, optional — duplicate, fraudulent or requested_by_customer
Request
curl https://paytab.co.uk/api/v1/payments/pay_123/refund \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "amount": 1500, "reason": "requested_by_customer" }'
Response
{
  "object": "refund",
  "id": "re_...",
  "payment": "pay_123",
  "amount": 1500,
  "status": "succeeded"
}
POST/api/v1/customers

Create a customer you can reuse across payments.

email
string, optional
name
string, optional
phone
string, optional
metadata
object, optional
Request
curl https://paytab.co.uk/api/v1/customers \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "email": "ada@example.com", "name": "Ada Lovelace" }'
Response
{
  "object": "customer",
  "id": "cus_...",
  "email": "ada@example.com",
  "name": "Ada Lovelace"
}
GET/api/v1/customers

List customers, newest first.

Request
curl "https://paytab.co.uk/api/v1/customers?limit=25" \
  -H "Authorization: Bearer sk_live_..."
Response
{ "object": "list", "data": [ { "object": "customer", "id": "cus_..." } ] }
GET/api/v1/customers/:id

Retrieve one customer.

Request
curl https://paytab.co.uk/api/v1/customers/cus_123 \
  -H "Authorization: Bearer sk_live_..."
Response
{ "object": "customer", "id": "cus_123" }

Webhooks

Add an HTTPS endpoint under Dashboard → Developers. Each event is POSTed as JSON with aPaytab-Signatureheader: an HMAC-SHA256 of the raw request body, keyed with your endpoint's signing secret. Always verify it before trusting the payload, and reply 2xx quickly.

Event payload
{
  "id": "evt_...",
  "type": "payment.succeeded",
  "created": "2026-01-08T10:22:41.000Z",
  "data": {
    "object": {
      "object": "payment",
      "id": "pay_...",
      "amount": 4999,
      "currency": "gbp",
      "status": "succeeded"
    }
  }
}
Verifying the signature
import express from "express";
import { createHmac, timingSafeEqual } from "crypto";

app.post("/webhooks/paytab",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.headers["paytab-signature"];
    const expected = createHmac("sha256", process.env.PAYTAB_WEBHOOK_SECRET)
      .update(req.body)
      .digest("hex");

    if (!signature ||
        !timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
      return res.status(400).send("Invalid signature");
    }

    const event = JSON.parse(req.body.toString());
    if (event.type === "payment.succeeded") {
      // fulfil the order
    }
    res.json({ received: true });
  });
payment.createdpayment.succeededpayment.refundedcustomer.created

Errors

Errors return a JSON body shaped { "error": { "type", "message" } }.

200Success.
400Something in your request is missing or invalid — the message says exactly what.
401Missing, malformed, revoked or unknown API key.
403Your account can't take payments yet. Finish verification in the dashboard.
404No object with that id belongs to your account.
500Something went wrong on our side. Safe to retry.

Keeping your key safe

  • • Call the API from your server only — never from a browser or mobile app.
  • • Store keys in environment variables, not in source control.
  • • Use separate keys per environment so you can revoke one without downtime.
  • • Revoke instantly from Dashboard → Developers if a key is ever exposed.
Manage keys and webhooks