Bonaventure OgetoBy Bonaventure Ogeto|

Paystack Access Codes: What They Are and How Long They Live

A Paystack access code is a short alphanumeric string returned alongside the authorization_url when you initialize a transaction. You pass it to PaystackPop.checkout() for inline (popup) checkout. Access codes expire after a period of inactivity, typically around 24 hours, though Paystack does not publish a guaranteed TTL. If an access code expires, initialize a new transaction.

What Is an Access Code?

When you call POST /transaction/initialize, Paystack returns a response with three fields that matter for checkout:

// Response from POST /transaction/initialize
{
  "status": true,
  "message": "Authorization URL created",
  "data": {
    "authorization_url": "https://checkout.paystack.com/0peioxfhpn",
    "access_code": "0peioxfhpn",
    "reference": "order_142_1721472000000"
  }
}

Notice that the access code is the tail end of the authorization URL. They are two ways to reach the same checkout session. The authorization_url is a full URL you can redirect the browser to. The access_code is the short identifier you pass to Paystack's inline JavaScript library when you want a popup checkout instead of a full-page redirect.

Think of the access code as a session ticket. It tells Paystack which transaction the customer is paying for, what amount to charge, which payment channels to show, and what metadata to attach. All of that was locked in when you called initialize.

Access Code vs Authorization URL

Both values come from the same initialize call and represent the same checkout session. The difference is how you use them.

Authorization URL (redirect checkout)

You send the customer's browser to the full URL. The customer leaves your site, completes payment on Paystack's hosted page, and gets redirected back to your callback URL. This is the simplest integration path.

// Redirect the customer to Paystack's hosted checkout
window.location.href = data.authorization_url;

Access code (inline/popup checkout)

You pass the code to PaystackPop, which opens the checkout in an iframe overlay on your page. The customer stays on your site visually. When they finish, you get a JavaScript callback instead of a page redirect.

// Open Paystack checkout as a popup on your page
var popup = new PaystackPop();
popup.checkout({
  accessCode: data.access_code,
  onSuccess: function(transaction) {
    // Verify server-side before granting value
    verifyPayment(transaction.reference);
  },
  onCancel: function() {
    console.log('Customer closed checkout');
  },
});

The payment experience is identical from Paystack's side. Card collection, 3DS challenges, bank transfer instructions, and OTP prompts all work the same way. The only difference is whether the customer sees it in a new page or in a popup on your page.

For a detailed comparison of the two approaches and when to choose each one, see redirect vs inline checkout.

How Long Do Access Codes Live?

Paystack does not publish an official TTL (time to live) for access codes. In practice, they expire after a period of inactivity, generally within 24 hours of creation. This is a deliberate design choice: checkout sessions should not live forever because amounts, exchange rates, and inventory can change.

Here is what this means for your integration:

  • If a customer clicks "Pay" and you initialize a transaction, the access code is valid for long enough to complete a normal checkout flow (minutes to a few hours).
  • If you initialize a transaction, store the access code, and try to use it the next day, it will almost certainly be expired.
  • If a customer opens the checkout popup but walks away for several hours without completing payment, the session may expire and the popup will show an error.

The practical rule: initialize the transaction as close to the moment of payment as possible. Do not pre-initialize transactions during page load or when the user adds items to a cart. Initialize when the user clicks the "Pay Now" button.

What Happens When an Access Code Expires

When you try to use an expired access code with PaystackPop, the behavior varies depending on the library version and the browser. Common outcomes include:

  • The popup opens but shows an error message like "This transaction has expired"
  • The popup opens to a blank or loading screen that never resolves
  • The checkout form appears but fails when the customer tries to submit payment

If you are using redirect checkout with the authorization URL, an expired session typically shows an error page on Paystack's checkout domain.

None of these are good experiences for your customer. The fix is to detect the failure and re-initialize.

// Frontend: handle checkout with expiration recovery
async function openCheckout() {
  // Always get a fresh access code from your server
  var response = await fetch('/api/pay', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: customerEmail,
      amount: orderAmount,
      orderId: currentOrderId,
    }),
  });

  var result = await response.json();

  var popup = new PaystackPop();
  popup.checkout({
    accessCode: result.access_code,
    onSuccess: function(transaction) {
      verifyPayment(transaction.reference);
    },
    onCancel: function() {
      // Customer closed the popup
      // The access code may still be valid for a retry
      // But safest to re-initialize on next attempt
      console.log('Checkout cancelled');
    },
  });
}

The key pattern: call your server to initialize a fresh transaction every time the customer clicks "Pay." Do not cache access codes on the frontend.

Common Mistakes with Access Codes

Mistake 1: Pre-initializing transactions on page load

Some developers call the initialize endpoint when the checkout page loads, store the access code in a variable, and use it when the customer clicks "Pay" five or thirty minutes later. If the customer takes too long, the access code might expire. Worse, if the order details change (quantity updated, coupon applied), the pre-initialized transaction has the wrong amount.

Initialize when the customer commits to paying, not when they land on the page.

Mistake 2: Storing access codes in a database for later use

Access codes are ephemeral. They are tied to a specific checkout session that expires. Storing them in your database and trying to reuse them hours or days later will fail. If you need to let a customer resume a payment later, initialize a new transaction with the same reference. Paystack will return the existing transaction if the reference matches and it has not been completed.

Mistake 3: Using the access code as a transaction identifier

The access code identifies the checkout session, not the transaction. Use the reference for tracking, verification, and reconciliation. The reference is the stable identifier that appears in webhooks, verify responses, and your dashboard. The access code is just a checkout entry point.

Mistake 4: Exposing the initialize endpoint without rate limiting

Every call to /transaction/initialize creates a pending transaction on Paystack's side. If your frontend endpoint that triggers initialization has no rate limiting, a bot or a frustrated user clicking rapidly can create hundreds of pending transactions. Add rate limiting on your server and use deterministic references (tied to the order ID) so that duplicate initialize calls return the same transaction.

Access Codes in Mobile Apps

If you are building a mobile app (React Native, Flutter, or native Android/iOS), access codes work the same way. Your mobile app calls your backend to initialize, gets back the access code, and uses it to open a WebView-based checkout.

// React Native example (conceptual)
// 1. Call your backend
var response = await fetch('https://yourapi.com/api/pay', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: email, amount: amount }),
});
var data = await response.json();

// 2. Open the authorization URL in a WebView
// or use a Paystack mobile SDK that accepts the access code
var checkoutUrl = data.authorization_url;
// Navigate to checkoutUrl in your in-app browser

The access code expiration behavior is the same on mobile. Initialize just before the customer is ready to pay. If the app goes to the background and the user comes back much later, initialize again.

Some Paystack mobile SDKs accept the access code directly and handle the WebView internally. Check the SDK documentation for your platform. The core rule stays the same: fresh access code, server-side initialization, verify after payment.

Reusing References vs Reusing Access Codes

There is an important distinction between reusing a reference and reusing an access code.

Reusing a reference: If you call /transaction/initialize with the same reference as an existing pending transaction, Paystack returns the existing transaction (with a fresh access code and authorization URL). This is the correct way to handle retries. If a customer's first checkout attempt fails or is abandoned, you can initialize again with the same reference and Paystack will not create a duplicate.

// Server-side: re-initialize with the same reference
var reference = 'order_' + orderId;

var response = await fetch('https://api.paystack.co/transaction/initialize', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: customerEmail,
    amount: amountInKobo,
    reference: reference, // Same reference as before
  }),
});

var data = await response.json();
// data.data.access_code is a fresh access code
// data.data.authorization_url is a fresh URL
// Both point to the same underlying transaction

Reusing an access code: This does not work reliably. Once an access code expires or the checkout session ends, the code is dead. Always get a fresh one from the initialize response.

The pattern that works: tie your reference to the order, and always call initialize before opening checkout. Let Paystack handle the deduplication through the reference. For deeper patterns on reference design, see transaction reference design patterns.

Debugging Access Code Issues

When the checkout popup fails silently or shows a vague error, here is how to narrow it down.

Check the transaction status on your dashboard

Log into your Paystack dashboard and search for the transaction reference. If the transaction shows as "abandoned" or "failed," the access code has expired or the checkout session ended. Initialize a new transaction.

Check the browser console

PaystackPop logs errors to the browser console when something goes wrong. Open your browser's developer tools and look for messages from the Paystack inline script. Common messages include session expiry notices and network errors.

Verify the access code matches the environment

A test access code (from a transaction initialized with a test secret key) will not work in a live checkout, and vice versa. Make sure your frontend is loading the correct Paystack inline script and that the access code was generated with the matching secret key.

Check the timing

Log timestamps when you initialize the transaction and when you attempt to open checkout. If there is a gap of more than a few hours, the access code may have expired. Restructure your flow to initialize closer to the payment attempt.

For more on debugging payment issues, see the Transaction Timeline API and reading gateway responses.

Stay Up to Date

Paystack occasionally changes how checkout sessions behave, updates expiration windows, or modifies inline library behavior. We keep these guides updated when things change.

Sign up for the McTaba newsletter to get notified when we publish new Paystack integration guides or spot breaking changes.

Key Takeaways

  • An access code is a short string (like "0peioxfhpn") returned when you initialize a transaction. It identifies the checkout session for use with the inline popup.
  • The authorization_url and the access_code point to the same transaction. The URL is for redirect checkout; the access code is for PaystackPop inline checkout.
  • Access codes expire after a period of inactivity. Do not store them for later use. Always initialize a fresh transaction when the customer is ready to pay.
  • If you try to use an expired access code, PaystackPop will show an error or a blank checkout. Your frontend should catch this and re-initialize the transaction.
  • Never expose your secret key to retrieve or refresh access codes on the frontend. The initialize call must always happen server-side.
  • Access codes are single-use in practice. Once a customer completes or abandons the checkout, the access code cannot be reused for a new payment.

Frequently Asked Questions

Can I extend the lifetime of a Paystack access code?
No. There is no API call to extend or refresh an access code. If the code has expired, you need to call /transaction/initialize again to get a new one. If you use the same reference, Paystack returns the existing transaction with a fresh access code.
Is the access code the same as the authorization code?
No. The access code identifies a checkout session and is used to open the payment popup. The authorization code (auth_code) is returned after a successful card payment and can be used to charge the same card again in the future. They serve completely different purposes.
Can I use an access code on a different domain than where the transaction was initialized?
Yes. The access code is not domain-locked. You can initialize a transaction from your server and use the access code on any frontend that loads the Paystack inline script. However, the callback URL you specified during initialization determines where the customer is redirected after payment.
What happens if I call initialize with the same reference twice?
If the first transaction is still pending (not completed, not abandoned), Paystack returns the existing transaction with a new access code and authorization URL. This is the designed behavior for retry scenarios. If the transaction was already completed, Paystack returns an error.
Do I need the access code if I am using redirect checkout?
No. For redirect checkout, you only need the authorization_url. Redirect the customer to that URL and Paystack handles everything. The access code is specifically for inline/popup checkout using PaystackPop.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon