Skip to content

Verify transaction

The sails.pay.verify() method verifies the status of a payment transaction directly with the provider, independent of webhooks. The lookup key depends on the adapter: Paystack verifies by reference, while Bachs verifies by chargeId.

Adapter support

Paystack basic usage

js
const transaction = await sails.pay.verify({
  reference: 'TXN-1708963200000-ABC123'
})

The method returns the full transaction object from the payment provider, including status, amount, currency, and metadata.

Bachs basic usage

js
const charge = await sails.pay.verify({
  chargeId: 'chr_1a2b3c4d5e6f'
})

Bachs verifies a charge by chargeId. If your app only has checkoutId, fetch the checkout first with sails.pay.checkout.get({ checkoutId }), then read checkout.charge.charge_id.

Example in an action

Here's a complete example using Actions2:

js
module.exports = {
  friendlyName: 'Verify payment',

  description: 'Verify a payment transaction by its reference.',

  inputs: {
    reference: {
      type: 'string',
      required: true,
      description: 'The transaction reference to verify.'
    }
  },

  exits: {
    success: {
      description: 'Transaction verified successfully.'
    },
    paymentError: {
      description: 'Could not verify the transaction.',
      responseType: 'serverError'
    }
  },

  fn: async function ({ reference }) {
    try {
      const transaction = await sails.pay.verify({ reference })

      return {
        status: transaction.status,
        amount: transaction.amount,
        currency: transaction.currency,
        paidAt: transaction.paid_at
      }
    } catch (error) {
      sails.log.error('Payment verification error:', error)
      throw 'paymentError'
    }
  }
}

Parameters

Paystack parameters

ParameterTypeRequiredDescription
referenceStringYesThe transaction reference used to initiate the transaction
secretKeyStringNoOverride the configured secret key

Bachs parameters

ParameterTypeRequiredDescription
chargeIdStringYesThe Bachs charge ID to verify
apiKeyStringNoOverride the configured API key

Response

The response contains the full transaction object from Paystack. Here's an example of the data structure:

js
{
  id: 5875134045,
  domain: 'live',
  status: 'success',
  reference: 'TXN-1708963200000-ABC123',
  amount: 450000,
  message: null,
  gateway_response: 'Successful',
  paid_at: '2026-02-26T10:30:00.000Z',
  created_at: '2026-02-26T10:29:53.000Z',
  channel: 'card',
  currency: 'NGN',
  ip_address: '143.105.174.31',
  metadata: {
    context: 'credit-purchase',
    userId: 1,
    credits: 50,
    packs: 1,
    paymentReference: 'TXN-1708963200000-ABC123'
  },
  fees: 16750,
  authorization: {
    authorization_code: 'AUTH_xxx',
    bin: '408408',
    last4: '4081',
    channel: 'card',
    card_type: 'visa',
    bank: 'TEST BANK',
    country_code: 'NG',
    brand: 'visa',
    reusable: true
  },
  customer: {
    id: 342381770,
    email: '[email protected]',
    customer_code: 'CUS_xxx'
  },
  plan: null,
  requested_amount: 450000
}

Transaction statuses

Paystack transactions can have the following statuses:

  • success — Payment was completed successfully
  • abandoned — Customer started checkout but didn't complete payment
  • failed — Payment attempt failed

Common use cases

Payment reconciliation

Use verify() in a background job to catch payments that webhooks may have missed:

js
// In a scheduled script (e.g. scripts/reconcile-purchases.js)
const pending = await CreditTransaction.find({
  type: 'purchase',
  status: 'pending',
  createdAt: { '>=': Date.now() - 48 * 60 * 60 * 1000 }
})

for (const txn of pending) {
  const paystackTxn = await sails.pay
    .provider('paystack')
    .verify({ reference: txn.paymentReference })

  if (paystackTxn.status === 'success') {
    // Fulfill the purchase
  }
}

Callback page verification

Verify a transaction when the user returns from the Paystack checkout page:

js
module.exports = {
  friendlyName: 'Payment callback',

  inputs: {
    reference: {
      type: 'string',
      required: true
    }
  },

  exits: {
    success: {
      responseType: 'redirect'
    }
  },

  fn: async function ({ reference }) {
    const transaction = await sails.pay.verify({ reference })

    if (transaction.status === 'success') {
      return '/payment/success'
    }

    return '/payment/failed'
  }
}

Bachs checkout return verification

When Bachs redirects the customer back to your returnUrl, it appends checkout_id. Use that value to fetch the checkout and inspect the embedded charge.

js
const checkout = await sails.pay.checkout.get({ checkoutId })
const charge = checkout.charge

Using a specific provider

If you have multiple payment providers configured, you can specify which one to use:

js
// Use the default provider
const transaction = await sails.pay.verify({ reference: '...' })

// Use a specific provider
const transaction = await sails.pay
  .provider('paystack')
  .verify({ reference: '...' })

// Use Bachs
const charge = await sails.pay.provider('bachs').verify({ chargeId: '...' })

Additional resources

All open source projects are released under the MIT License.