paystack-transfers

Paystack Transfers API — send money to bank accounts and mobile wallets. Initiate single and bulk transfers, finalize OTP-verified transfers, list, fetch, and verify transfer status. Use this skill whenever implementing payouts, disbursements, vendor payments, withdrawal flows, or any feature that sends money from your Paystack balance to recipients. Also use when you see references to transfer_code, TRF_ prefixed codes, the /transfer endpoint, or need to handle transfer OTP verification.

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-transfers" with this command: npx skills add rexedge/paystack/rexedge-paystack-paystack-transfers

Paystack Transfers

The Transfers API lets you send money from your Paystack balance to bank accounts and mobile wallets. Transfers require a pre-created transfer recipient.

Depends on: paystack-setup for the paystackRequest helper.
Related: paystack-transfer-recipients for creating recipients before transfers.

Endpoints

MethodEndpointDescription
POST/transferInitiate a transfer
POST/transfer/finalize_transferFinalize transfer (OTP)
POST/transfer/bulkInitiate bulk transfer
GET/transferList transfers
GET/transfer/:id_or_codeFetch a transfer
GET/transfer/verify/:referenceVerify a transfer

Initiate Transfer

POST /transfer

Returns status pending if OTP is disabled on your account, or otp if OTP is required.

ParamTypeRequiredDescription
sourcestringYesbalance (only option)
amountintegerYesAmount in subunits (kobo/pesewas)
recipientstringYesRecipient code (e.g. RCP_gd9vgag7n5lr5ix)
referencestringYesUnique identifier (16-50 chars, lowercase a-z, 0-9, -, _)
reasonstringNoReason for transfer (shows in customer's credit notification)
currencystringNoCurrency code (defaults to NGN)
account_referencestringNoRequired in Kenya for MPESA Paybill and Till transfers
const transfer = await paystackRequest<{
  transfer_code: string;
  status: string;
  reference: string;
  amount: number;
}>("/transfer", {
  method: "POST",
  body: JSON.stringify({
    source: "balance",
    amount: 100000,          // ₦1,000
    recipient: "RCP_gd9vgag7n5lr5ix",
    reference: `txf_${crypto.randomUUID()}`,
    reason: "Vendor payment for January",
  }),
});
// transfer.data.status → "pending" or "otp"
// transfer.data.transfer_code → "TRF_v5tip3zx8nna9o78"

Finalize Transfer

POST /transfer/finalize_transfer

Required when transfer status is otp. Submit the OTP sent to your business phone.

ParamTypeRequiredDescription
transfer_codestringYesTransfer code from initiate response
otpstringYesOTP sent to business phone
await paystackRequest("/transfer/finalize_transfer", {
  method: "POST",
  body: JSON.stringify({
    transfer_code: "TRF_v5tip3zx8nna9o78",
    otp: "928783",
  }),
});

Initiate Bulk Transfer

POST /transfer/bulk

Batch multiple transfers in a single request. OTP must be disabled on your account to use this endpoint.

ParamTypeRequiredDescription
sourcestringYesbalance
transfersarrayYesArray of transfer objects

Each transfer object:

ParamTypeRequiredDescription
amountintegerYesAmount in subunits
recipientstringYesRecipient code
referencestringYesUnique reference (16-50 chars)
reasonstringNoTransfer reason
const result = await paystackRequest("/transfer/bulk", {
  method: "POST",
  body: JSON.stringify({
    source: "balance",
    currency: "NGN",
    transfers: [
      {
        amount: 20000,
        recipient: "RCP_gd9vgag7n5lr5ix",
        reference: `txf_${crypto.randomUUID()}`,
        reason: "Bonus for the week",
      },
      {
        amount: 35000,
        recipient: "RCP_m7ljkv8leesep7p",
        reference: `txf_${crypto.randomUUID()}`,
        reason: "January salary",
      },
    ],
  }),
});
// result.message → "2 transfers queued."

List Transfers

GET /transfer

ParamTypeRequiredDescription
perPageintegerNoRecords per page (default: 50)
pageintegerNoPage number (default: 1)
recipientintegerNoFilter by recipient ID
fromdatetimeNoStart date
todatetimeNoEnd date
const transfers = await paystackRequest("/transfer?perPage=20&page=1");

Fetch Transfer

GET /transfer/:id_or_code

const transfer = await paystackRequest(
  `/transfer/${encodeURIComponent("TRF_v5tip3zx8nna9o78")}`
);

Verify Transfer

GET /transfer/verify/:reference

Verify the status of a transfer using its reference.

const result = await paystackRequest(
  `/transfer/verify/${encodeURIComponent(reference)}`
);
// result.data.status → "success" | "failed" | "pending" | "reversed"

Transfer Flow

// 1. Create recipient (see paystack-transfer-recipients skill)
// 2. Initiate transfer
const transfer = await paystackRequest("/transfer", {
  method: "POST",
  body: JSON.stringify({
    source: "balance",
    amount: 500000,
    recipient: "RCP_gd9vgag7n5lr5ix",
    reference: `txf_${crypto.randomUUID()}`,
  }),
});

// 3. If OTP required, finalize
if (transfer.data.status === "otp") {
  const otp = await getOTPFromUser();
  await paystackRequest("/transfer/finalize_transfer", {
    method: "POST",
    body: JSON.stringify({
      transfer_code: transfer.data.transfer_code,
      otp,
    }),
  });
}

// 4. Listen for webhooks: transfer.success, transfer.failed, transfer.reversed

Important Notes

  • You can only transfer from balance — ensure your Paystack balance has sufficient funds
  • Bulk transfers require OTP to be disabled (Dashboard → Settings → Preferences)
  • Transfer references must be unique, 16-50 characters, lowercase with - and _ only
  • For Kenya MPESA Paybill/Till, include account_reference in the transfer
  • Always verify transfer status via webhook (transfer.success, transfer.failed) rather than polling

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-charges

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-setup

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-webhooks

No summary provided by upstream source.

Repository SourceNeeds Review
General

paystack-transactions

No summary provided by upstream source.

Repository SourceNeeds Review