Troubleshooting#
Common issues and solutions for AuxCORE API integration.
🔐 Authentication Issues#
TOKEN_EXPIRED / INVALID_TOKEN (401)#
Cause: JWT expired or malformed on an Admin API route
Solution:
# Get a new token (or exchange your refresh token)
curl -X POST https://uat.auxcore.net/api/v1/auth/login \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: your-tenant-id" \
-d '{"email": "...", "password": "..."}'"API key required" / "API key validation failed" (401)#
Cause: No key, or a revoked/unknown/deactivated key, on /api/v1/public/*
Solution: Send the key in the x-api-key header. On these routes error is a string, e.g. { "success": false, "error": "API key validation failed", "message": "..." }.
"Origin required" / "Origin not allowed" (403)#
Cause: An SDK public key (lpk_live_…) with allowed origins configured, called without an Origin / X-Merchant-Origin header (e.g. from a server) or from an unlisted site
Solution: Use a secret key server-side, or add the origin to the SDK key at /settings/developer/api-keys.
TENANT_REQUIRED (400)#
Cause: Missing tenant ID on an Admin API route (/api/v1/*)
Solution:
# Admin routes require JWT + tenant ID
curl -H "Authorization: Bearer YOUR_JWT" \
-H "X-Tenant-ID: your-tenant-id" ...Public API keys resolve the tenant from the key — this error should not appear on /api/v1/public/*. Tenant-wide ERP keys (lv_erp_…) must send X-Merchant-ID instead, or merchant-specific calls fail with VALIDATION_ERROR.
💳 Transaction Issues#
PCI_SCOPE_VIOLATION (400)#
Cause: A raw CardNumber was sent to a payment endpoint
Solution: Tokenize with the PCI SDK (or POST /tokenize-card server-side) and send pciToken.
"Transaction declined" (402)#
The public /transaction endpoint answers 402 with status: "declined", a readable message, and data.ResponseCode (NMI-style, e.g. 202 insufficient funds, 223 expired card, 225 invalid CVV).
Causes:
- Insufficient funds
- Card expired
- Invalid card details
- AVS/CVV mismatch
Solutions:
- Ask customer for different card
- Verify card details
- Check AVS/CVV responses
"This transaction has already been settled and cannot be voided"#
Cause: Transaction already settled (only approved, unsettled transactions can be voided)
Solution: Use refund instead of void
"Only approved or settled transactions can be refunded"#
Cause: Refund attempted on a declined, voided or pending transaction
Solution: Void a pending/approved one instead, or nothing is owed
🔄 Subscription Issues#
Subscription payment failed#
Cause: Card declined, expired, or insufficient funds
Solution:
- Retry the failed charge with
POST /api/v1/recurring/:id/retry-failed - Send the customer a card-update link with
POST /api/v1/recurring/:id/send-method-update-link - Watch for
transaction.declinedwebhooks on the recurring charges
📧 Webhook Issues#
Webhooks not received#
Checks:
- URL publicly accessible?
- HTTPS enabled?
- Returns a 2xx status?
- Not timing out?
- Endpoint subscribed to the event (e.g.
transaction.approved) and active?
Solution:
# Send a webhook.test event to the endpoint
curl -X POST https://uat.auxcore.net/api/v1/webhooks/endpoints/4e3d2c1b-0a9f-4e8d-7c6b-5a4f3e2d1c0b/test \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
# Inspect delivery attempts
curl https://uat.auxcore.net/api/v1/webhooks/endpoints/4e3d2c1b-0a9f-4e8d-7c6b-5a4f3e2d1c0b/deliveries \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-ID: your-tenant-id""Invalid signature"#
Cause: Signature verification failing — usually because the body was parsed and re-serialized before hashing, the wrong secret is used, or the timestamp is outside your tolerance
Solution: Hash the raw body: HMAC-SHA256(secret, "<t>.<rawBody>") and compare with v1 from X-Webhook-Signature: t=<unix>,v1=<hex>. The secret is shown only once at creation; if lost, call POST /api/v1/webhooks/endpoints/:id/regenerate-secret.
Use the Node.js verifier to reject absent or malformed headers with 401 instead of a buffer-length exception. Mount the raw-body route before express.json(). Repeated deliveries with the same event.id should return 2xx after confirming that the durable inbox already holds the event; do not repeat its business effects.
🐛 Common Errors#
Rate limit exceeded (429)#
Solution: Implement exponential backoff using the RateLimit-* headers. Public token/checkout endpoints return { "success": false, "error": { "code": "RATE_LIMITED", ... } } (30 requests / 15 min per IP).
Gateway timeout#
Cause: The response was lost or the gateway timed out. The processor may still have accepted the payment.
Solution:
- On
POST /api/v1/public/transaction, do not automatically submit another charge. This endpoint does not forwardIdempotency-Key, andOrderIddoes not enforce uniqueness. - Query
GET /api/v1/public/transaction-list?orderId=…and match the results to your payment attempt. Wait for the webhook or confirm with the processor if the outcome is unknown; an empty lookup immediately after a timeout is not proof that no charge occurred. - For an endpoint that supports idempotency, retry with the same persisted key and exact payload. Wait before retrying
409 IDEMPOTENCY_REQUEST_IN_PROGRESS; investigate422 IDEMPOTENCY_KEY_REUSEDwithout generating a replacement key to bypass it. - For voids and refunds, look up the current transaction/refund status before submitting another reversal. A refund may already be queued for a server-side retry.
See Use Idempotency Keys.
Invalid JSON#
Solution: Verify JSON syntax
Need help? Contact support@auxcore.net