Troubleshooting
Solutions to common issues and error messages.
Quick fixes for the most common integration issues, errors, and unexpected behaviors.
API errors
401 Unauthorized
Cause: Invalid or missing API key
Solutions:
- Check that you're using the correct key (public for initialize, secret for verify)
- Verify the key hasn't been revoked or rotated
- Ensure the key is included in the
Authorizationheader
# Correct format
Authorization: YOUR_API_KEY400 Bad Request
Cause: Validation failed on required fields
Common fixes:
| Error | Fix |
|---|---|
| "Amount is required" | Include amount in the request body |
| "Invalid email" | Ensure email format is valid |
| "Currency not supported" | Use NGN or USD |
| "Reference already exists" | Generate a unique reference for each transaction |
404 Not Found
Cause: Transaction or endpoint doesn't exist
Solutions:
- For verification: Check that the
transRefis correct - For endpoints: Verify the URL path matches the documentation exactly
500 Internal Server Error
Cause: Something went wrong on our end
Solutions:
- Retry the request after a few seconds
- Check our status page for outages
- Contact support if it persists
Payment issues
Payment initialization fails
Symptoms: API returns error when trying to initialize
Check:
-
Is
amountspecified in lowest currency unit?Wrong:
"amount": 150.00
Correct:"amount": 15000 -
Is
emaila valid email format? -
Are you using the public key (not secret key)?
-
Is your account active and verified?
Debug code:
// Log the full error response
try {
const response = await initializePayment(data);
} catch (error) {
console.log('Status:', error.response.status);
console.log('Message:', error.response.data.message);
console.log('Errors:', error.response.data.errors);
}Customer can't complete payment
Symptoms: Authorization URL loads but payment fails
Common causes:
| Issue | Solution |
|---|---|
| Card declined | Try a different card or payment method |
| Insufficient funds | Customer needs to add funds or use different card |
| 3DS authentication fails | Customer should contact their bank |
| Session expired | Generate a new authorization URL |
| Unsupported card type | Use Visa, Mastercard, or Verve |
Authorization URL not working
Symptoms: Link returns 404 or doesn't load
Check:
- URL hasn't expired (valid for 24 hours)
- No extra characters added to the URL
- Customer has stable internet connection
Verification issues
Transaction not found during verification
Symptoms: 404 error when calling verify endpoint
Check:
- Are you using the correct
transRef(notreference)? - Is the transaction in the right environment?
- Sandbox transactions can't be verified in production
- Wait 10-30 seconds after payment before verifying
// Use credoReference from initialization response
const transRef = initializeResponse.data.credoReference;
// NOT: const transRef = initializeResponse.data.reference;Verification returns wrong status
Symptoms: Status shows failed but customer says they paid
Solutions:
- Always rely on server-side verification, not client feedback
- Check if webhook was received (more reliable than callback)
- Allow 1-2 minutes for status to update
- Contact support with
transReffor investigation
Webhook issues
Webhooks not being received
Checklist:
- URL is publicly accessible (not localhost)
- URL uses HTTPS
- Webhook is configured in the correct environment (sandbox vs production)
- Firewall allows requests from Credo IPs
- Endpoint responds with HTTP 200 within 5 seconds
Debug with webhook.site:
- Go to webhook.site
- Copy the unique URL
- Add it to your Credo dashboard
- Make a test payment
- Check if events appear on webhook.site
Only receiving some event types
Cause: Your handler only checks for transaction.successful
Credo sends 4 event types. Make sure you handle all the ones relevant to your integration:
| Event | When it fires |
|---|---|
transaction.successful | Payment processed successfully |
transaction.failed | Payment declined or insufficient funds |
transaction.transaction.transfer.reverse | Bank transfer amount mismatch — reversed to customer |
transaction.settlement.success | Settlement paid out to merchant |
Duplicate webhook deliveries
Cause: Your endpoint didn't respond with 200 quickly enough
Solution:
- Respond with HTTP 200 immediately
- Process the event asynchronously
- Implement idempotency checks using
transRef+eventas a composite key
app.post('/webhook', (req, res) => {
// Respond immediately
res.status(200).send('OK');
// Process asynchronously
processWebhook(req.body);
});Webhook signature verification fails
Cause: Incorrect signature calculation
Correct formula (HMAC-SHA512 with your secret key):
const signature = crypto
.createHmac('sha512', process.env.CREDO_SECRET_KEY)
.update(JSON.stringify(payload))
.digest('hex');Check:
- Using your secret key (not public key)
- Payload isn't modified before verification (use the raw request body)
- Using HMAC-SHA512 (not SHA-256 or plain SHA-512)
- Comparing against the
credo-signatureheader value
Settlement issues
Settlement not received
Check:
- Is it a business day? (No settlements on weekends/holidays)
- Was transaction before 12 PM? (After 12 PM settles next day)
- Is bank account verified and active?
Timeline:
| Transaction time | Settlement time |
|---|---|
| Monday 10 AM | Monday by 6 PM |
| Monday 3 PM | Tuesday by 6 PM |
| Friday 10 AM | Friday by 6 PM |
| Friday 3 PM | Monday by 6 PM |
Settlement amount is wrong
Common causes:
| Expected | Actual | Reason |
|---|---|---|
| ₦10,000 | ₦9,800 | Merchant bears fee (₦200 deducted) |
| ₦10,000 | ₦10,000 | Customer bears fee (no deduction) |
| Split config | Different split | Rules changed in dashboard |
Check your fee bearer setting:
{
"bearer": 0 // Customer pays fee
"bearer": 1 // You pay fee
}Mobile SDK issues
Flutter SDK: Payment modal not opening
Check:
flutter_webview_pluginis installed- Internet permission added to AndroidManifest.xml
- iOS:
NSAppTransportSecurityallows arbitrary loads (for development)
React Native SDK: "Cannot read property"
Check:
- Ran
cd ios && pod installafter installation - Rebuilt the app after installing package
- Imported from correct path
Testing issues
Test cards not working
Check:
- Using sandbox environment (
api.credodemo.com) - Using test public key (starts with
0PUB) - Card number entered correctly (no spaces)
Valid test cards:
| Card | Number | Result |
|---|---|---|
| Visa | 4012000033330026 | Success |
| MasterCard | 5555555555554444 | Success (no 3DS) |
Callback URL not triggered
Check:
- URL is publicly accessible
- URL returns a valid response
- No CORS issues (for web integrations)
Still having issues?
If none of these solutions work:
- Check our status page for outages
- Search our documentation for detailed guides
- Contact support with:
- Transaction reference
- Error messages
- Timestamp of issue
- Steps to reproduce
Was this page helpful?
Last updated on
