mcpField
P
paystack-transactions

paystack-transactions

github.com/rexedgeOther137 installsUpdated 33w ago
Repository

About paystack-transactions

Paystack Transactions is a skill for developers integrating Paystack payments. It documents transaction initialization, verification, management, reusable authorization charges, and reporting endpoints.

Key features

  1. 01Initialize and verify transactions
  2. 02List and retrieve transaction records
  3. 03Charge saved authorizations
  4. 04View timelines and aggregate totals
  5. 05Export transaction data as CSV
  6. 06Partially debit an authorization

Use cases

  1. 01Build a payment checkout flow
  2. 02Verify payments before fulfilling orders
  3. 03Charge reusable customer authorizations
  4. 04Review or export transaction records

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/rexedge/paystack --skill paystack-transactions

After installing, type/paystack-transactionsin Claude Code to confirm it loaded.

Details

From the project README

Paystack Transactions

The Transactions API lets you create and manage payments on your integration. This covers the entire transaction lifecycle from initialization through verification.

Depends on: paystack-setup for the paystackRequest helper and environment config.

Transaction Lifecycle

Initialize (server) → Complete (client/redirect) → Verify (server) + Webhook

Endpoints

MethodEndpointDescription
POST/transaction/initializeInitialize a transaction
GET/transaction/verify/:referenceVerify a transaction
GET/transactionList transactions
GET/transaction/:idFetch a transaction
POST/transaction/charge_authorizationCharge a saved authorization
GET/transaction/timeline/:id_or_referenceView transaction timeline
GET/transaction/totalsGet transaction totals
GET/transaction/exportExport transactions as CSV
POST/transaction/partial_debitPartial debit on an authorization

Initialize Transaction

POST /transaction/initialize

Creates a payment and returns an authorization_url (for redirect) and access_code (for Popup/InlineJS).

Parameters (Body)
ParamTypeRequiredDescription
amountstringYesAmount in subunits (kobo). "50000" = NGN 500
emailstringYesCustomer's email address
referencestringNoUnique ref. Alphanumeric + - . = only
currencystringNoNGN, USD, GHS, ZAR, KES. Defaults to integration currency
callback_urlstringNoOverride the dashboard callback URL
channelsarrayNo["card","bank","ussd","qr","mobile_money","bank_transfer","eft","apple_pay"]
planstringNoPlan code for subscription-based payment
invoice_limitintegerNoMax charges for subscription
metadatastringNoStringified JSON with custom_fields array
subaccountstringNoSubaccount code e.g. ACCT_8f4s1eq7ml6rlzj
split_codestringNoSplit code e.g. SPL_98WF13Eb3w
transaction_chargeintegerNoFlat fee override for split (in subunits)
bearerstringNo"account" or "subaccount" — who pays Paystack fees
Response
{
  "status": true,
  "message": "Authorization URL created",
  "data": {
    "authorization_url": "https://checkout.paystack.com/3ni8kdavz62431k",
    "access_code": "3ni8kdavz62431k",
    "reference": "re4lyvq3s3"
  }
}
Server Action Example (Next.js)
"use server";
import { paystackRequest } from "@/lib/paystack";

export async function initializePayment(email: string, amountInNaira: number) {
  const result = await paystackRequest<{
    authorization_url: string;
    access_code: string;
    reference: string;
  }>("/transaction/initialize", {
    method: "POST",
    body: JSON.stringify({
      email,
      amount: Math.round(amountInNaira * 100).toString(),
      callback_url: `${process.env.NEXT_PUBLIC_APP_URL}/payment/callback`,
    }),
  });
  return result.data;
}
Client-Side Popup (InlineJS)
"use client";
import PaystackInline from "@paystack/inline-js";

function PayButton({ email, amount }: { email: string; amount: number }) {
  const handlePay = async () => {
    // 1. Initialize on server
    const { access_code } = await initializePayment(email, amount);

    // 2. Open Popup with access_code
    const popup = new PaystackInline();
    popup.openIframe({
      accessCode: access_code,
      onSuccess: (response) => {
        // 3. Verify on server — NEVER trust this alone
        verifyTransaction(response.reference);
      },
      onClose: () => console.log("Payment window closed"),
    });
  };

  return <button onClick={handlePay}>Pay ₦{amount}</button>;
}
Redirect Method

After initializing, redirect the user to authorization_url. Paystack redirects back to your callback_url with ?trxref=REFERENCE&reference=REFERENCE in the query string. Verify server-side immediately.

// app/payment/callback/page.tsx
import { paystackRequest } from "@/lib/paystack";

export default async function PaymentCallback({
  searchParams,
}: {
  searchParams: Promise<{ reference?: string }>;
}) {
  const { reference } = await searchParams;
  if (!reference) return <p>No reference provided</p>;

  const result = await paystackRequest<{ status: string; amount: number }>(
    `/transaction/verify/${encodeURIComponent(reference)}`
  );

  if (result.data.status === "success") {
    return <p>Payment successful!</p>;
  }
  return <p>Payment failed: {result.data.status}</p>;
}

Verify Transaction

GET /transaction/verify/:reference

Always verify server-side after payment. The reference is in the callback URL query params or returned from Popup's onSuccess.

const result = await paystackRequest<{
  id: number;
  status: "success" | "failed" | "abandoned";
  reference: string;
  amount: number;
  currency: string;
  channel: string;
  paid_at: string;
  authorization: {
    authorization_code: string;
    reusable: boolean;
    card_type: string;
    last4: string;
    bank: string;
  };
  customer: { email: string; id: number };
}>(`/transaction/verify/${encodeURIComponent(reference)}`);

Check result.data.status === "success" and validate result.data.amount matches expected amount before fulfilling the order.

List Transactions

GET /transaction

Query Parameters
ParamTypeDescription
perPageintegerRecords per page (default 50)
pageintegerPage number (default 1)
customerintegerFilter by customer ID
terminalidstringFilter by Terminal ID
statusstring"success", "failed", or "abandoned"
fromdatetimeStart date e.g. 2024-01-01T00:00:00.000Z
todatetimeEnd date
amountintegerFilter by amount (in subunits)
const params = new URLSearchParams({ status: "success", perPage: "20" });
const result = await paystackRequest<Transaction[]>(`/transaction?${params}`);

Fetch Transaction

GET /transaction/:id

Fetch a single transaction by its numeric ID.

const result = await paystackRequest<Transaction>(`/transaction/${transactionId}`);

Charge Authorization

POST /transaction/charge_authorization

Charge a customer's previously saved card (where authorization.reusable === true).

ParamTypeRequiredDescription
amountstringYesAmount in subunits
emailstringYesCustomer's email
authorization_codestringYese.g. AUTH_72btv547
referencestringNoUnique transaction reference
currencystringNoCurrency code
queuebooleanNoSet true for scheduled/bulk charges
const result = await paystackRequest<Transaction>(
  "/transaction/charge_authorization",
  {
    method: "POST",
    body: JSON.stringify({
      authorization_code: "AUTH_72btv547",
      email: "[email protected]",
      amount: "20000",
    }),
  }
);

Transaction Timeline

GET /transaction/timeline/:id_or_reference

Returns a step-by-step history of the transaction (attempted payment method, success/failure, time spent).

const result = await paystackRequest<{
  start_time: number;
  time_spent: number;
  attempts: number;
  errors: number;
  success: boolean;
  history: Array<{ type: string; message: string; time: number }>;
}>(`/transaction/timeline/${reference}`);

Transaction Totals

GET /transaction/totals

Returns aggregate volume and count. Supports from, to, perPage, page query params.

const result = await paystackRequest<{
  total_transactions: number;
  total_volume: number;
  total_volume_by_currency: Array<{ currency: string; amount: number }>;
  pending_transfers: number;
}>("/transaction/totals");

Export Transactions

GET /transaction/export

Returns a CSV download link. Supports all list filters plus settled, settlement, payment_page.

const params = new URLSearchParams({ from: "2024-01-01", status: "success" });
const result = await paystackRequest<{ path: string }>(
  `/transaction/export?${params}`
);
// result.data.path is a time-limited S3 URL to the CSV

Partial Debit

POST /transaction/partial_debit

Debit a portion of a customer's available balance on an authorization. Useful for metered billing.

ParamTypeRequiredDescription
authorization_codestringYesAuth code from previous transaction
currencystringYesNGN or GHS
amountstringYesAmount in subunits
emailstringYesCustomer email tied to the auth code
referencestringNoUnique reference
at_leaststringNoMinimum amount to charge if full amount fails
const result = await paystackRequest<Transaction>(
  "/transaction/partial_debit",
  {
    method: "POST",
    body: JSON.stringify({
      authorization_code: "AUTH_72btv547",
      currency: "NGN",
      amount: "20000",
      email: "[email protected]",
      at_least: "10000",
    }),
  }
);

Important Notes

  • Transaction IDs are unsigned 64-bit integers — store as string in TypeScript to avoid precision loss
  • Always verify server-side after payment — never trust client-side callbacks alone
  • Amount validation: always confirm result.data.amount matches your expected amount after verification
  • The authorization_code from a successful transaction can be saved and reused for future charges if authorization.reusable === true
  • Metadata supports custom_fields for dashboard display — stringify the JSON before sending

Comments

Markdown supported