Paste this page's URL into Lovable, Replit, Bolt, Cursor or any AI coder. It will read the spec and wire up the entire crypto-payment flow on your site — no language lock-in.
One copy. The AI will read this entire page automatically and implement every step.
You are integrating the Crypto Invoice API into my website/app.
Read the full machine-readable spec at:
https://pay.itemodeverify.com/websetup
https://pay.itemodeverify.com/llms.txt
https://pay.itemodeverify.com/api/openapi.json
Implement the FULL flow end-to-end. Do NOT skip steps.
REQUIREMENTS
1. Store 3 secrets in the project's secret manager (NOT in code):
- CRYPTO_API_KEY
- CRYPTO_API_SECRET
- CRYPTO_WEBHOOK_SECRET
Add a setup screen / .env example showing the names only.
2. Build a backend endpoint POST /api/checkout that:
- Reads { amount, currency?, customer_email?, description? } from the request.
- Optionally calls GET https://pay.itemodeverify.com/api/public/v1/wallets to pick an active wallet.
- Calls POST https://pay.itemodeverify.com/api/public/v1/invoices with:
Authorization: Bearer <CRYPTO_API_KEY>:<CRYPTO_API_SECRET>
body: { amount, currency: currency || "USDT",
description, customer_email,
expires_in_minutes: 30,
success_redirect_url: "<MY_SITE>/payment/success?inv={id}" }
- Returns { pay_url, invoice_id } to the frontend.
- Frontend then redirects the user to pay_url (hosted pay page with QR + address).
3. Build a webhook endpoint POST /api/crypto-webhook that:
- Reads the RAW request body (do not re-serialize JSON).
- Verifies header X-Webhook-Signature = HMAC_SHA256(CRYPTO_WEBHOOK_SECRET, raw_body) in constant time.
- On event "invoice.paid": mark the order paid, credit the user's balance, send confirmation. Handler MUST be idempotent (same invoice id may arrive more than once).
- On "invoice.expired" / "invoice.cancelled": update the order status.
- Always reply HTTP 200 within 5s. Process heavy work async.
4. Add a 30-second polling fallback for any invoice still "pending":
- Server-side cron OR client-side setInterval on the success page.
- GET https://pay.itemodeverify.com/api/public/v1/invoices/<id> every 30s until status != "pending" or 30 minutes elapsed.
- This guarantees balance updates even if the webhook is temporarily down.
5. Success page at /payment/success?inv=<id>:
- Fetch the invoice, show status, amount, tx hash.
- If still pending, show "Confirming…" and poll every 30s.
- When paid, show success + redirect to dashboard.
6. Admin test panel at /admin/crypto-test with ONE button "Run integration test":
- Verifies auth (lists wallets).
- Creates a $1 test invoice.
- Cancels it.
- Shows pass/fail for each step. Use this to debug without real payments.
CONSTRAINTS
- Default invoice expiry: 30 minutes.
- Default polling interval: 30 seconds.
- Never expose API_SECRET or WEBHOOK_SECRET to the browser.
- Never trust webhook payloads without HMAC verification.
- Use the framework already in this project (do not introduce a new one).
When done, print: the 3 secret names to set, the webhook URL to paste into the Crypto Invoice dashboard at https://pay.itemodeverify.com/api → Webhooks, and a checklist of what to test manually.Generate the API key/secret at https://pay.itemodeverify.com/api. The webhook secret is shown once when you add a webhook URL — copy it immediately.
# .env.example — names only, fill values in your secret manager
CRYPTO_API_KEY=
CRYPTO_API_SECRET=
CRYPTO_WEBHOOK_SECRET=
CRYPTO_API_BASE=https://pay.itemodeverify.comStore these in your platform's secret manager — Lovable Cloud secrets, Replit Secrets, Bolt env, Vercel/Netlify env vars. Never commit values.
BASE URL
https://pay.itemodeverify.com
AUTH (server-side only)
Authorization: Bearer <API_KEY>:<API_SECRET>
ENDPOINTS
GET /api/public/v1/wallets -> list active wallets
POST /api/public/v1/invoices -> create invoice
GET /api/public/v1/invoices/{id} -> read invoice (use for polling)
POST /api/public/v1/invoices/{id}/cancel -> cancel a pending invoice
CREATE INVOICE BODY
{
"amount": 10,
"currency": "USDT",
"description": "Wallet top-up",
"customer_email": "user@example.com",
"expires_in_minutes": 30,
"success_redirect_url": "https://yoursite.com/payment/success?inv={id}"
}
CREATE INVOICE RESPONSE
{
"id": "inv_...",
"status": "pending",
"pay_url": "https://pay.itemodeverify.com/pay/inv_...",
"wallet_id": "...",
"amount": 10,
"currency": "USDT",
"expires_at": "2026-..."
}
INVOICE STATUSES
pending | paid | expired | cancelledFull machine-readable schema: /api/openapi.json
/api/checkout.pay_url.success_redirect_url.WEBHOOK DELIVERY
Method: POST (your URL)
Header: Content-Type: application/json
Header: X-Webhook-Signature: <hex>
Body: { "type": "invoice.paid" | "invoice.expired" | "invoice.cancelled" | "ping",
"data": { ...invoice... } }
VERIFY (pseudo-code, any language)
raw = read raw request body bytes
expected = HMAC_SHA256(WEBHOOK_SECRET, raw).hex()
if not constant_time_equals(expected, header["X-Webhook-Signature"]):
return 401
RETRIES
We auto-retry failed deliveries with exponential backoff:
1m, 5m, 30m, 2h, 6h, 24h (6 attempts total)
Your handler MUST be idempotent.
REGISTER YOUR URL
https://pay.itemodeverify.com/api → Webhooks → Add URL
The WEBHOOK_SECRET is shown ONCE on creation — store it immediately.POLLING FALLBACK (use alongside webhooks)
Interval: 30 seconds (default)
Stop when: status != "pending" OR 30 minutes elapsed
Endpoint: GET https://pay.itemodeverify.com/api/public/v1/invoices/{id}
WHERE TO POLL
- /payment/success page (browser side) — instant UX update
- Server cron job for invoices still "pending" past 1 minute — safety net
WHY BOTH WEBHOOK + POLLING
Webhooks are instant but can fail (network, downtime, firewall).
Polling guarantees the balance eventually updates even if every webhook fails.Pass success_redirect_url when creating the invoice. Use {id} — we substitute the invoice id automatically.
https://yoursite.com/payment/success?inv={id}The AI builder should add a single page at /admin/crypto-test with one "Run integration test" button that hits: list wallets → create $1 invoice → cancel it. Each step shows pass/fail.
MANUAL TEST CHECKLIST
[ ] GET /wallets returns 200 with at least one active wallet
[ ] POST /invoices returns pay_url, status="pending"
[ ] Opening pay_url shows QR + crypto address
[ ] Cancelling moves status to "cancelled"
[ ] Webhook URL receives a "ping" test from the dashboard
[ ] Signature verification rejects a tampered body (returns 401)
[ ] After a real payment: webhook fires "invoice.paid" AND polling sees "paid"
[ ] Balance/order is credited exactly ONCE (idempotency works)
[ ] success_redirect_url sends the user back with {id} substitutedMost integration failures are 401 Unauthorized — auth header missing, malformed, or called from the browser. Full list with causes and fixes below. Have your AI builder read this section before debugging.
HTTP ERROR CODES — CAUSES & FIXES
================================================================
401 Unauthorized ← MOST COMMON
================================================================
Meaning: API rejected your auth header.
Causes & fixes:
1. Missing Authorization header
→ Add: Authorization: Bearer <API_KEY>:<API_SECRET>
2. Wrong format (using only the key, or "Bearer KEY" without secret)
→ Must be EXACTLY: Bearer <API_KEY>:<API_SECRET> (colon-separated)
3. API_KEY or API_SECRET is empty / undefined
→ Check your secret manager. Names: CRYPTO_API_KEY, CRYPTO_API_SECRET
→ Do NOT hardcode. Do NOT expose to the browser.
4. Calling from the browser (frontend)
→ Auth must run on YOUR server. Frontend → your /api/checkout → our API.
5. Old / revoked API key
→ Regenerate at https://pay.itemodeverify.com/api → API Keys
6. Extra whitespace, quotes, or newline pasted into the env var
→ Re-paste the value cleanly. Trim it.
7. Using the WEBHOOK_SECRET as API key
→ They are 3 DIFFERENT secrets. Don't mix.
Quick test (run from your server, never the browser):
curl -H "Authorization: Bearer $CRYPTO_API_KEY:$CRYPTO_API_SECRET" \
https://pay.itemodeverify.com/api/public/v1/wallets
Expected: 200 + JSON list. If 401 → key/secret is wrong.
================================================================
400 Bad Request
================================================================
Cause: Invalid body — missing "amount", bad currency, malformed JSON.
Fix: Send Content-Type: application/json. Required: { amount: number }.
amount must be > 0. currency defaults to "USDT" if omitted.
================================================================
403 Forbidden
================================================================
Cause: Your API key is valid but doesn't own the wallet you referenced,
OR the account is suspended / unverified.
Fix: Use a wallet_id from GET /api/public/v1/wallets (same account).
Check account status at https://pay.itemodeverify.com/api.
================================================================
404 Not Found
================================================================
Cause: Wrong invoice id, or wrong URL path.
Fix: Check the id you stored. Endpoint is /api/public/v1/invoices/{id}
— note the "v1" and the "public" segments.
================================================================
409 Conflict
================================================================
Cause: Trying to cancel an invoice that's already paid / expired / cancelled.
Fix: Only "pending" invoices can be cancelled. Check status first.
================================================================
422 Unprocessable Entity
================================================================
Cause: Amount below wallet minimum, or currency not supported by the wallet.
Fix: Call GET /wallets/{id}/quote first — it returns min/max and rate.
================================================================
429 Too Many Requests
================================================================
Cause: Rate limit hit (default 60 req/min per API key).
Fix: Back off. Respect Retry-After header. For polling: 30s interval is fine.
Don't poll faster than every 10s.
================================================================
500 / 502 / 503 Server Error
================================================================
Cause: Temporary issue on our side.
Fix: Retry with exponential backoff (1s, 2s, 4s, 8s, max 5 tries).
If it persists > 5 min, check status page.
================================================================
WEBHOOK-SPECIFIC ERRORS (your endpoint receives, or we log)
================================================================
401 on webhook → Signature mismatch
• You're hashing the parsed JSON instead of the RAW body. Use raw bytes.
• Wrong WEBHOOK_SECRET. It was shown ONCE — regenerate the webhook URL
in dashboard if you lost it.
• Encoding mismatch — compare hex lowercase, constant-time.
"Failed to fetch" / CORS error in browser
• You're calling our API directly from the frontend. Don't. Route through
your own backend: browser → /api/checkout (your server) → our API.
• Our API does NOT send CORS headers for /api/public/v1/* — by design.
Webhook never arrives
• URL not publicly reachable (localhost won't work — use a tunnel, or deploy).
• Your handler returns non-2xx → we retry 6× then give up.
• URL not registered. Add it at https://pay.itemodeverify.com/api → Webhooks.
Balance not updated after payment
• Webhook handler crashed before crediting → check your logs.
• Not idempotent → duplicate event was ignored AND the first one failed.
• Polling not enabled → enable the 30s fallback on /payment/success.
================================================================
DEBUG CHECKLIST (run in this order when something breaks)
================================================================
1. curl /wallets with your key → must return 200
2. curl POST /invoices → must return pay_url
3. Open pay_url in browser → must show QR
4. Send "ping" from dashboard webhook page → your endpoint must return 200
5. Verify signature on the ping → must pass
6. Make a $1 test payment → webhook fires + GET /invoices/{id} shows "paid"API_SECRET or WEBHOOK_SECRET to the browser.invoice.id may arrive twice./invoices/{id} result before crediting balance.