> ## Documentation Index
> Fetch the complete documentation index at: https://docs-v2.reeple.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Common problems and what causes them

<AccordionGroup>
  <Accordion title="400 — Something went wrong while trying to decrypt your payload">
    The `data` string could not be decrypted. In order of likelihood:

    * **Wrong padding.** It must be PKCS#1 v1.5, not OAEP. Browser `SubtleCrypto` only does
      OAEP, so a hand-rolled WebCrypto implementation will always fail here.
    * **Wrong environment.** A test encryption key with a live API key (or vice versa).
    * **Not base64.** The ciphertext bytes must be base64-encoded before being placed in `data`.
    * **Key not parsed correctly.** Remember to base64-decode the key, split on `!`, and use the
      *second* half. See [Encryption](/encryption#the-key-format).
    * **Payload too large.** RSA encrypts a limited number of bytes per block. Trim optional
      fields if a payload has grown unusually large.
  </Accordion>

  <Accordion title="401 — api-key was not passed in the header">
    The `api-key` header is missing entirely. Check for a typo in the header name — it is
    `api-key`, not `apikey`, `API-Key` or `Authorization`.
  </Accordion>

  <Accordion title="401 — Invalid public key passed / Invalid SECRET key">
    You sent the wrong *kind* of key. Order creation, payment, status, fees, banks and events
    take the **public** key; verify, refunds, chargebacks and tokenized charges take the
    **secret** key. See [Authentication](/api-reference/authentication) for the full split.

    This error also appears when a key from one environment is used against the other.
  </Accordion>

  <Accordion title="13 — Order not found at the moment">
    The reference in your payload doesn't match an order. Usually one of:

    * The order was never successfully created — check the create-order response.
    * A typo, or a reference from a different environment.
    * You generated a fresh reference for the pay call instead of reusing the one from create.
  </Accordion>

  <Accordion title="13 — Order payment is currently pending">
    A payment has already been submitted for this order and hasn't resolved yet. Don't retry the
    pay call — poll [Get order status](/api-reference/orders/get-order-status) instead. Creating
    a second payment for the same order risks double-charging the customer.
  </Accordion>

  <Accordion title="604 — Cannot find this payment link">
    The payment-link reference doesn't exist, or has expired. Payment-link references are issued
    by Reeple and are not the same thing as your order reference.
  </Accordion>

  <Accordion title="The status never becomes final">
    Expected for the first few minutes on bank transfers — the customer has to actually send the
    money. If a **card** payment stays pending beyond a few minutes, the customer most likely
    abandoned 3-D Secure. Leave the order pending, tell the customer you'll confirm once payment
    completes, and reconcile from your backend. Don't mark it failed: a payment can still land
    after the customer has closed their browser.
  </Accordion>

  <Accordion title="Pay-order returned success but no money arrived">
    A `"status": "success"` on [Pay an order](/api-reference/orders/pay-order) means the payment
    was accepted for processing, not that it completed. Only a final status from
    [Get order status](/api-reference/orders/get-order-status), confirmed with
    [Verify an order](/api-reference/verification/verify-order), tells you the money moved.
  </Accordion>

  <Accordion title="The customer never came back to my callback URL">
    There are no webhooks on this API, so a customer who closes their browser mid-payment leaves
    you with no notification at all — even though the payment may still complete. Run a backend
    job that polls pending orders. See
    [Callbacks and verification](/callbacks-and-verification#there-are-no-webhooks).
  </Accordion>

  <Accordion title="The payment options I expected aren't offered">
    `otherPaymentOptions` depends on the order's **currency** and on what's enabled for your
    account. A USD order typically offers card only, where an NGN order also offers bank
    transfer. Don't hard-code the list — render whatever create-order returns.
  </Accordion>

  <Accordion title="It worked on sandbox and broke in production">
    Almost always the encryption helper. `POST /charge/data/encrypt` does not exist in
    production — if your integration calls it, implement
    [encryption](/encryption) yourself. The other usual cause is only swapping two of the three
    credentials: the public key, the secret key **and** the encryption key all change between
    environments.
  </Accordion>
</AccordionGroup>

## Still stuck?

Have your order `reference` and the `statusCode` from the failing response to hand — together
they identify the exact transaction.
