paystack-transactions

Paystack Transactions API — initialize payments, verify transactions, list/fetch transaction history, charge saved authorizations, view timelines, get totals, export data, and perform partial debits. Use this skill whenever building a checkout flow, verifying payment status, recharging a returning customer's saved card, pulling transaction reports or analytics, exporting transaction CSVs, or handling any transaction-related Paystack endpoint. Also use when you see references to /transaction/initialize, /transaction/verify, authorization_url, access_code, or charge_authorization in Paystack integrations.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "paystack-transactions" with this command: npx skills add rexedge/paystack/rexedge-paystack-paystack-transactions

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: "customer@email.com",
      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: "customer@email.com",
      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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

paystack-webhooks

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-setup

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-charges

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-miscellaneous

No summary provided by upstream source.

Repository SourceNeeds Review