FAQ & Troubleshooting
Frequently asked questions and troubleshooting guide. Payment issues, webhook debugging, chain selection, address modes, security, billing, and common integration problems.
FAQ & Troubleshooting
Answers to common questions about PayzCore integration, payment monitoring, and troubleshooting.
Payments
Why is my payment stuck on "pending"?
A payment stays in pending status until PayzCore detects a matching transfer on the blockchain. Common reasons:
- The customer hasn't sent the funds yet. The payment is waiting for an incoming transfer.
- The transfer is below the dust threshold. Transfers under $0.10 (or your project's
minAmount) are ignored. See Dust Threshold. - Wrong chain or token. If the customer sent USDT on BEP20 but the payment expects TRC20, PayzCore won't detect it. Make sure your UI clearly shows which chain and address to send to.
- Wrong address. Double-check that the customer sent to the exact address returned by the API.
- Blockchain congestion. PayzCore checks for new transactions every 1-2 minutes. During heavy network load, there may be a brief delay.
If the transfer is on-chain but not detected, check the blockchain explorer for the address. If the transfer appears there, contact support.
Why is my payment stuck on "confirming"?
The transfer has been detected but hasn't reached the required number of block confirmations yet. Each chain has a different threshold:
| Chain | Required Confirmations | Typical Wait |
|---|---|---|
| TRC20 | 19 blocks | ~1 minute |
| BEP20 | 15 blocks | ~45 seconds |
| ERC20 | 12 blocks | ~2.5 minutes |
| POLYGON | 64 blocks | ~2.5 minutes |
| ARBITRUM | 40 blocks | ~10 seconds |
This is normal and expected. The payment will automatically move to paid (or another final status) once confirmations are met.
What happens when a payment expires?
When the payment window closes (default: 1 hour) without a sufficient transfer:
- The payment status changes to
expired. - A
payment.expiredwebhook is sent to your server. - The customer needs to start a new payment.
If a partial payment was received before expiry, the status is expired (not partial). You'll need to handle refunds or credit manually.
You can customize the expiry window per payment via the expires_in parameter (300-86400 seconds).
Can I use multiple chains for one project?
Yes. Each payment specifies its own chain and token. A single project can accept payments on all 5 chains simultaneously. The chain is set per payment, not per project.
{ "amount": 50, "chain": "TRC20", "token": "USDT", "external_ref": "cust-1" }
{ "amount": 50, "chain": "POLYGON", "token": "USDC", "external_ref": "cust-2" }Your wallet needs the appropriate xPub keys configured. An EVM xPub covers BEP20, ERC20, Polygon, and Arbitrum. A Tron xPub covers TRC20. See Address Families.
Can customers pay with USDC on TRC20?
No. Circle discontinued USDC on the Tron network in February 2024. TRC20 only supports USDT. If you need USDC, use any of the four EVM chains: BEP20, ERC20, POLYGON, or ARBITRUM.
What are the gas fees?
PayzCore does not charge any gas fees. Gas is only relevant when you sweep (collect) received funds from payment addresses to your main wallet. The customer pays no gas to you either — they pay their own wallet's network fee.
Sweep gas costs vary by chain:
| Chain | Typical Sweep Cost |
|---|---|
| TRC20 | $0.05-$4 (depends on staked energy) |
| BEP20 | $0.03-$0.15 |
| ERC20 | $0.50-$30+ |
| POLYGON | $0.001-$0.01 |
| ARBITRUM | $0.01-$0.15 |
For detailed information, see Sweeping Funds.
Webhooks
Why did my webhook fail?
Check these common issues:
- Webhook URL is not publicly accessible. PayzCore sends webhooks from its servers. Your URL must be reachable from the internet.
localhostURLs will not work in production. - Your server returned a non-2xx status code. PayzCore treats 4xx as permanent failures (not retried) and 5xx/timeouts as transient (retried up to 5 times).
- Your server took too long to respond. PayzCore waits 10 seconds. Return
200 OKimmediately and process the event asynchronously. - SSL certificate issues. Ensure your HTTPS certificate is valid and not self-signed.
- Firewall blocking. Your server's firewall may be blocking incoming POST requests from PayzCore's IP addresses.
- SSRF protection. PayzCore blocks webhook URLs pointing to private/internal IP ranges (10.x, 172.16-31.x, 192.168.x, localhost).
View delivery logs in the dashboard: Payments > [Click a payment] > Webhook Logs. Each log shows the HTTP status code and response body.
How do I verify webhook signatures?
Every webhook includes an X-PayzCore-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your Webhook Secret (whsec_...).
import { createHmac, timingSafeEqual } from 'crypto'
function verify(body: string, signature: string, secret: string): boolean {
const expected = createHmac('sha256', secret).update(body).digest('hex')
return timingSafeEqual(
Buffer.from(signature.toLowerCase()),
Buffer.from(expected)
)
}For complete examples in Node.js, Python, and PHP, see the Webhooks Guide.
How do I test webhooks locally?
Use a tunneling tool to expose your local server to the internet:
- Install ngrok:
npm install -g ngrok - Start your local server (e.g., on port 3000)
- Run
ngrok http 3000to get a public URL - Set the ngrok URL as your project's webhook URL in the PayzCore dashboard
- Create a test payment and send a small amount to the address
- Watch the webhook arrive at your local server
Other tunneling alternatives: Cloudflare Tunnel, localtunnel.
Address Modes
What is the difference between per_payment and per_user address mode?
- per_payment: A new unique address is derived for every payment. The address is deactivated when the payment resolves. Best for e-commerce checkout and one-time purchases.
- per_user: The same address is reused for the same customer (
external_ref) on a given chain. Best for user deposit addresses, top-ups, and subscription payments.
Both require an xPub key. For a detailed comparison of all four modes, see Address Modes.
Can I use PayzCore without an xPub key?
Yes. Use static wallet mode (dedicated or pool). Instead of HD wallet derivation, you manually register your existing wallet addresses:
- Dedicated mode: One static address permanently assigned to each customer.
- Pool mode: Shared addresses with micro-amount offsets or transaction hash matching.
Static wallet modes do not require an xPub key. You add addresses through the wallet management page. See Address Modes.
How do I get my xPub key?
Your xPub (extended public key) is exported from your wallet software:
- Trust Wallet: Settings > Wallets > Info icon > Extended Public Key
- Ledger Live: Account > Advanced Logs > xPub
- Electrum: Wallet > Information > Master Public Key
When creating a wallet in PayzCore, an expandable help panel provides step-by-step instructions for each wallet.
Your xPub is read-only. It allows PayzCore to derive addresses and check balances but cannot sign transactions or move funds.
Billing & Plans
How do I switch from Free to Pro?
- Go to Billing in the PayzCore dashboard.
- Select your preferred chain and token for payment.
- Send the displayed amount to the provided address.
- Once confirmed on-chain, your plan upgrades automatically.
The Pro plan costs $29/month and includes 5 projects, 5 wallets, 10,000 webhooks/day, and 25,000 API calls/day. Payment is in USDT only.
What happens when I exceed my plan limits?
- Project/wallet creation: Blocked. You'll see a message to upgrade.
- Daily API calls: Returns HTTP 429 with
X-RateLimit-Daily: true. Existing payments continue to be monitored. - Daily webhooks: Webhook dispatch is paused for the day. Events are not lost — they will be sent the next day when the counter resets at midnight UTC.
Existing projects and pending payments are never affected by plan limits. You can always read payment statuses even if you've hit your daily API call limit.
Security
Is my API key safe?
Your API key (pk_live_...) authenticates requests to the PayzCore API. To keep it safe:
- Never expose it client-side. Do not include it in JavaScript that runs in the browser, mobile app code, or any public-facing source.
- Store it in environment variables. Use
.envfiles or your hosting platform's secret management. - Rotate if compromised. An admin can regenerate project credentials from the dashboard.
- Use one project per application. Don't share API keys across different services.
What happens if PayzCore goes down?
- Funds are safe. PayzCore is non-custodial and never holds or controls any funds. Customer payments go directly to your blockchain addresses.
- Monitoring pauses temporarily. Blockchain monitoring will not run during downtime.
- Monitoring resumes automatically. When PayzCore comes back online, it catches up on any transfers that occurred during the outage. Payments with detected transfers are updated and webhooks are dispatched.
- Use polling as a fallback. For critical flows, poll
GET /api/v1/payments/:idin addition to relying on webhooks.
Does PayzCore have access to my funds?
No. PayzCore is strictly non-custodial:
- Watch-only access. PayzCore uses your xPub key to derive addresses and read blockchain data. It cannot sign transactions or move funds.
- No private keys. Your private keys never leave your wallet software.
- No fund custody. PayzCore does not hold, transmit, or manage any cryptocurrency at any point.
Integration
How do I check payment status via the API?
Poll the payment endpoint:
curl https://api.payzcore.com/api/v1/payments/PAYMENT_ID \
-H "x-api-key: pk_live_YOUR_KEY"The response includes the current status, paid_amount, transaction details, and confirmation count. See Getting Started for the full response format.
For production use, rely primarily on webhooks and use polling as a fallback.
How do I discover available chains for my project?
Use the config endpoint:
curl https://api.payzcore.com/api/v1/config \
-H "x-api-key: pk_live_YOUR_KEY"This returns the chains and tokens available based on your wallet configuration. It does not count against your daily API call limit. See Supported Chains.
How do I handle partial payments?
When a customer sends less than the expected amount, the payment status becomes partial and a payment.partial webhook is sent. Your options:
- Ask the customer to send the remaining amount. The same address continues to be monitored until expiry.
- Cancel and create a new payment. If the partial amount is too small to be useful.
- Accept the partial payment. Credit the customer for what they sent and handle the difference in your application logic.
PayzCore does not automatically combine multiple transfers into a single payment unless the total meets the expected amount.
How do I handle overpayments?
When a customer sends more than 1% above the expected amount, the status becomes overpaid and a payment.overpaid webhook is sent. The paid_amount field shows the actual amount received.
Handle overpayments in your application logic — for example, credit the full received amount or refund the difference manually.
Can I cancel a payment?
Yes, via the API or dashboard. Cancelled payments stop being monitored and a payment.cancelled webhook is sent. Only pending payments can be cancelled — payments that have already received a transfer cannot be cancelled.
How do I collect/sweep received funds?
PayzCore is monitoring-only and does not move funds. You sweep funds using your own wallet software:
- Open your wallet app (Trust Wallet, Ledger, Electrum, etc.)
- Since it holds the private keys for the same xPub, you can access all derived payment addresses
- Send the received funds from payment addresses to your main treasury wallet
Batch sweeps are more gas-efficient than sweeping each payment individually. See Sweeping Funds for chain-specific gas costs and recommendations.
Troubleshooting
"USDC is not supported on TRC20" error
Circle discontinued USDC on the Tron network. Use USDT for TRC20, or switch to an EVM chain (BEP20, ERC20, POLYGON, ARBITRUM) for USDC support.
"Wallet has no xPub configured for CHAIN" error
Your wallet is missing the xPub key for the requested chain's address family:
- Tron family (TRC20): Needs a Tron xPub key
- EVM family (BEP20, ERC20, POLYGON, ARBITRUM): Needs an EVM xPub key
Go to Wallets in the dashboard and add the missing xPub.
"Project has no wallet assigned" error
The project needs a wallet linked before creating payments. Go to Projects > [Your Project] > Edit and assign a wallet.
"Daily API call limit exceeded" error
You've hit your plan's daily API call limit (Free: 500/day, Pro: 25,000/day). The counter resets at midnight UTC. Options:
- Wait until midnight UTC
- Upgrade to the Pro plan
- Reduce polling frequency (rely on webhooks instead)
The GET /api/v1/config endpoint is free and does not count against this limit.
"Rate limit exceeded" error (per-minute)
You're sending too many requests per minute (default: 60/minute per API key). Implement exponential backoff and check the X-RateLimit-Reset header for when you can retry.
Webhook not received
If webhooks aren't arriving at your server:
- Check the webhook URL in your project settings. It must be a publicly accessible HTTPS URL.
- Check webhook logs in the dashboard: Payments > [Payment] > Webhook Logs.
- Verify your server returns 2xx quickly. PayzCore times out after 10 seconds.
- Check your firewall/reverse proxy. Ensure POST requests are not being blocked.
- Check the payment status. Webhooks are only sent for final statuses (
paid,overpaid,expired,partial,cancelled), not forconfirming.
Payment detected but webhook shows wrong amount
PayzCore reports the exact on-chain amount. If the amounts don't match:
- Pool + micro_amount mode: The expected amount includes a micro-offset (e.g., $50.003 instead of $50.00). This is by design.
- Multiple transfers: In aggregate mode,
paid_amountis the sum of all transfers to the address. - Token decimal precision: Different chains have different decimal precisions (6 or 18). PayzCore normalizes to human-readable amounts.