Troubleshooting

Common issues and solutions for PayDirect integration. If you don't find your answer here, check the Error Codes reference.

Authentication Issues

401 Unauthorized

API returns "Unauthorized" for all requests.

Check:

  • Key format is correct: pd_test_... (sandbox) or pd_live_... (live)
  • Header format is Authorization: Bearer pd_test_abc... (not Token or ApiKey)
  • The key has not been revoked (check Dashboard → Settings → API Keys)
  • No extra whitespace or newlines in the key value

Wrong environment key

Payment created but no real transaction occurs.

Cause: Using a pd_test_ key in production. Sandbox keys simulate the full lifecycle instantly without real on-chain activity.

Fix: Switch to a pd_live_ key for real Base mainnet transactions.

Payment Issues

400 Bad Request — invalid tokenSymbol

"Invalid token symbol"

Cause: The tokenSymbol must be uppercase: "USDC", "ETH", or "ADAO".

Fix: Use the exact uppercase strings. Common mistakes: "usdc", "Usdc", "DAI".

400 Bad Request — invalid merchantWallet

"Invalid merchant wallet address"

Cause: The merchantWallet must be a valid Ethereum address: 42 characters starting with 0x.

Fix: Validate the address matches /^0x[a-fA-F0-9]{40}$/ before sending.

Payment stuck in "pending"

Payment was created but never moves to "detected".

Possible causes:

  • Payer sent funds to the wrong address (not the receivingAddress)
  • Payer sent on the wrong network (must be Base mainnet, not Ethereum mainnet)
  • Payer sent the wrong token (e.g. USDT instead of USDC)
  • Amount doesn't match the expected gross_amount

Fix: Verify the payer sent the exact gross_amount of the correct token to the receivingAddress on Base. Check the transaction on BaseScan.

Payment expired

Status changed to "expired" before funds arrived.

Cause: The payment window (default: 60 minutes) elapsed without detecting the transfer.

Fix: Create a new payment. Optionally increase expiresInMinutes for payments that need more time.

Rate Limiting

429 Too Many Requests

Rate limit exceeded.

Limits: Free: 100 req/min, Pro: 1,000 req/min.

Fix: Read the Retry-After header and wait that many seconds before retrying. Implement exponential backoff for sustained bursts.

Webhook Issues

Webhook signature verification fails

Check:

  • You are using the correct signing secret (whsec_...) from webhook registration
  • You are verifying against the raw request body string, not a parsed/re-serialized object
  • The header name is X-PayDirect-Signature (case-insensitive in most frameworks)
  • You are using timing-safe comparison (e.g. crypto.timingSafeEqual)

Webhooks not being received

Check:

  • Your endpoint URL is publicly accessible (not localhost)
  • Your endpoint is served over HTTPS with a valid certificate
  • You subscribed to the correct events (e.g. payment.forwarded, not payment.completed)
  • Your endpoint returns 200 within a reasonable timeout

Tip: Use a tool like webhook.site to test webhook delivery during development.

Base Network Issues

Wrong network

Funds sent on Ethereum mainnet instead of Base.

PayDirect operates exclusively on Base mainnet (Chain ID: 8453). Funds sent on Ethereum mainnet, Arbitrum, Optimism, or any other chain will not be detected.

Fix: Ensure the payer's wallet is connected to Base. Display the Base network requirement prominently in your payment UI.

Insufficient gas for forwarding

Payment stuck in "confirmed" status.

Cause: The workspace wallet may not have enough ETH for gas to forward the payment. PayDirect auto-funds gas, but in rare cases the gas funder wallet may be depleted.

Fix: Contact support if a payment is stuck in "confirmed" status for more than 15 minutes.

Still Need Help?