Skip to main content

Error format

All Platform API errors follow a consistent response format:
{
  "ok": false,
  "error": {
    "code": "MERCHANT_NOT_ACTIVE",
    "message": "The merchant shp_xxx is not in ACTIVE status",
    "status": 403,
    "requestId": "req_cm5x7k2a000001j0g8h3f9d2e"
  }
}
FieldTypeDescription
codestringMachine-readable error code. Stable across API versions. Use this for programmatic error handling.
messagestringHuman-readable description of the error. May change between versions. Do not match against this string.
statusintegerHTTP status code
requestIdstringUnique identifier for the request. Include this when contacting support.

HTTP status codes

StatusMeaningWhen it occurs
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid parameters, missing required fields, or business rule violation
401UnauthorizedInvalid or missing credentials, expired timestamp, or signature mismatch
403ForbiddenValid credentials but insufficient permissions for this action
404Not FoundThe requested resource does not exist
409ConflictThe request conflicts with the current state of the resource
422Unprocessable EntityThe request is well-formed but cannot be processed due to semantic errors
429Too Many RequestsRate limit exceeded
500Internal Server ErrorSomething went wrong on our end. Retry with exponential backoff.
503Service UnavailableThe API is temporarily unavailable. Retry with exponential backoff.

Authentication errors

CodeStatusDescriptionResolution
MISSING_AUTHORIZATION401The Authorization header is missingInclude Authorization: Platform plt_xxx in the request
INVALID_PLATFORM_ID401The platform ID in the Authorization header is not recognizedVerify you are using the correct plt_ credential for the environment (sandbox vs production)
SIGNATURE_MISMATCH401The X-Platform-Signature does not match the expected valueVerify you are signing with HMAC-SHA512 (not SHA-256) using your raw psk_ secret. Check the canonical request construction.
TIMESTAMP_EXPIRED401The X-Request-Timestamp is older than 5 minutesUse the current Unix timestamp in milliseconds. Check for clock drift on your server.
TIMESTAMP_MISSING401The X-Request-Timestamp header is missingInclude the current Unix timestamp in milliseconds
PLATFORM_SUSPENDED403Your platform account is suspendedContact platforms@pandabase.io
PLATFORM_TERMINATED403Your platform account has been terminatedContact platforms@pandabase.io
ENVIRONMENT_MISMATCH401Sandbox credentials used against production, or vice versaUse the correct credentials for the target environment

Debugging signature errors

Signature mismatches are the most common integration issue. Verify the following:
  1. Algorithm: Use HMAC-SHA512, not HMAC-SHA256
  2. Secret: Use the raw psk_ string. Do not hash or encode it before use.
  3. Canonical request format: The signed string must be four lines joined by newline characters:
    METHOD\n
    PATH\n
    TIMESTAMP\n
    SHA256(BODY)
    
  4. Method: Must be uppercase (POST, GET, PATCH)
  5. Path: Must include the leading slash and exclude query parameters (/v2/platforms/intents, not https://api.pandabase.io/v2/platforms/intents)
  6. Body hash: SHA-256 hash of the raw request body. For requests with no body (GET, DELETE), hash an empty string.
  7. Timestamp: Must match the X-Request-Timestamp header exactly

Merchant errors

CodeStatusDescriptionResolution
MERCHANT_NOT_FOUND404No merchant found with the given IDVerify the merchant ID. Check that it belongs to your platform.
MERCHANT_ALREADY_EXISTS409A merchant with this externalId already exists on your platformUse the existing merchant or choose a different externalId
MERCHANT_NOT_ACTIVE403The merchant is not in ACTIVE statusCheck the merchant’s status. Merchants in PENDING_REVIEW, RESTRICTED, SUSPENDED, or TERMINATED status cannot process payments.
MERCHANT_TERMINATED403Cannot perform actions on a terminated merchantTerminated merchants are permanently removed and cannot be reactivated
MERCHANT_RESTRICTED403The merchant’s capabilities are currently restrictedWait for the restriction to be lifted, or contact compliance
INVALID_COUNTRY400The country code is not supported for merchant provisioningCheck the list of supported countries
INVALID_CATEGORY400The merchant category is not recognizedUse one of the supported merchant categories
TIER_UPGRADE_IN_PROGRESS409A tier upgrade is already pending for this merchantWait for the current upgrade to complete before requesting another
CAPABILITY_NOT_AVAILABLE400The requested capability is not available for this merchant’s tierUpgrade the merchant’s tier before requesting this capability
MERCHANT_CONTEXT_MISSING400The X-Merchant-Context header is missingInclude the merchant’s store ID in the header
MERCHANT_CONTEXT_INVALID400The merchant ID in X-Merchant-Context does not belong to your platformVerify the merchant ID belongs to your platform
DOCUMENT_TOO_LARGE400The uploaded document exceeds the 10 MB limitReduce the file size and retry
DOCUMENT_INVALID_FORMAT400The document format is not supportedUpload in PDF, PNG, or JPG format

Intent errors

CodeStatusDescriptionResolution
INTENT_NOT_FOUND404No intent found with the given IDVerify the intent ID
AMOUNT_TOO_LOW400The intent amount is below the $1.00 minimumSet amount to at least 100 (cents)
AMOUNT_TOO_HIGH400The intent amount exceeds the merchant’s per-transaction limitCheck the merchant’s limits.maxTransactionAmount and reduce the amount, or upgrade the merchant’s tier
PLATFORM_FEE_TOO_HIGH400The platform fee exceeds 30% of the intent amountReduce the platformFee to 30% or less of amount
LINE_ITEMS_MISMATCH400The sum of line item amounts does not equal the intent amountEnsure sum(lineItem.amount * lineItem.quantity) equals amount
LINE_ITEMS_REQUIRED400No line items were providedInclude at least one line item
INVALID_RETURN_URL400The returnUrl is not a valid HTTPS URLProvide a fully qualified HTTPS URL
INTENT_NOT_CANCELLABLE409The intent is not in a cancellable statusOnly intents in REQUIRES_PAYMENT or REQUIRES_CAPTURE can be cancelled
INTENT_ALREADY_CAPTURED409The intent has already been capturedThis intent has already moved past the authorization stage
INTENT_CAPTURE_EXPIRED409The 7-day capture window has passedAuthorized intents must be captured within 7 days. The authorization has been voided.
INTENT_EXPIRED409The intent has expiredCreate a new intent. Expired intents cannot be resumed.
MERCHANT_VOLUME_EXCEEDED400This intent would cause the merchant to exceed their daily or monthly volume capWait for the next period or upgrade the merchant’s tier for higher limits
CURRENCY_NOT_SUPPORTED400The specified currency is not supported for platform intentsCurrently only USD is supported
CAPTURE_EXCEEDS_AUTHORIZATION400The capture amount exceeds the authorized amountCapture an amount equal to or less than the original authorization
METADATA_KEY_TOO_LONG400A metadata key exceeds 40 charactersShorten the key to 40 characters or fewer
METADATA_VALUE_TOO_LONG400A metadata value exceeds 500 charactersShorten the value to 500 characters or fewer
METADATA_TOO_MANY_KEYS400More than 20 metadata keys were providedReduce to 20 keys or fewer

Refund errors

CodeStatusDescriptionResolution
REFUND_EXCEEDS_AMOUNT400The refund amount exceeds the remaining refundable amountCheck how much has already been refunded and adjust the amount
REFUND_WINDOW_EXPIRED400The 180-day refund window has passedRefunds can only be issued within 180 days of the original payment
INSUFFICIENT_BALANCE400The merchant’s available balance cannot cover the refundWait for additional settlements or fund the merchant’s balance via transfer
INTENT_NOT_REFUNDABLE409The intent is not in a refundable statusOnly COMPLETED and PARTIALLY_REFUNDED intents can be refunded
REFUND_IN_PROGRESS409A refund is already processing for this intentWait for the current refund to complete

Settlement errors

CodeStatusDescriptionResolution
SETTLEMENT_NOT_FOUND404No settlement found with the given IDVerify the settlement ID
PAYOUT_NOT_FOUND404No platform payout found with the given IDVerify the payout ID
INVALID_DATE_RANGE400The from date is after the to dateSwap the date parameters

Money Management errors

CodeStatusDescriptionResolution
INSUFFICIENT_BALANCE400The merchant’s available balance is insufficient for this operationCheck the merchant’s balance before attempting the operation
HOLD_NOT_FOUND404No hold found with the given IDVerify the hold ID
HOLD_ALREADY_RELEASED409The hold has already been released or consumedNo action needed. The funds are already available.
HOLD_EXPIRED409The hold expired and was automatically releasedNo action needed. The funds were returned to available balance on expiry.
HOLD_EXCEEDS_BALANCE400The hold amount exceeds the merchant’s available balanceReduce the hold amount or wait for additional settlements
TRANSFER_LIMIT_EXCEEDED400The transfer amount exceeds the $50,000 per-transaction limitSplit the transfer into multiple smaller transactions
TRANSFER_DAILY_LIMIT429The merchant has exceeded the 100 transfers per day limitWait until the next day or contact support for a limit increase
TRANSFER_SAME_MERCHANT400The source and destination merchant are the sameTransfers require two different merchants
PAYOUT_MINIMUM400The payout amount is below the $1.00 minimumSet the amount to at least 100 (cents)
EXPRESS_NOT_AVAILABLE400Express payout is not supported for this merchant’s bank accountUse standard priority instead
PAYOUT_IN_PROGRESS409A payout is already processing for this merchantWait for the current payout to complete
BANK_ACCOUNT_MISSING400The merchant has not configured a bank account for payoutsThe merchant must add bank account details before receiving payouts

Rate limit errors

CodeStatusDescriptionResolution
RATE_LIMIT_EXCEEDED429Too many requestsCheck the X-RateLimit-Reset header for when you can retry. Implement exponential backoff.
When you receive a 429 response, the following headers indicate your limit status:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1679000060
Retry-After: 12
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying

Idempotency errors

CodeStatusDescriptionResolution
IDEMPOTENCY_CONFLICT409A different request body was sent with the same X-Idempotency-KeyEach idempotency key must be paired with the same request body. Use a new key for different requests.
IDEMPOTENCY_KEY_TOO_LONG400The idempotency key exceeds 128 charactersShorten the key to 128 characters or fewer
Idempotency keys are scoped to your platform and persist for 24 hours. After 24 hours, the same key can be reused with a different request body.

Webhook delivery errors

These errors appear in the webhook delivery logs, not in API responses.
CodeDescriptionResolution
ENDPOINT_UNREACHABLEYour webhook endpoint did not respond within 10 secondsEnsure your endpoint is publicly accessible and responds quickly. Return 200 immediately and process asynchronously.
ENDPOINT_ERRORYour endpoint returned a non-2xx status codeReturn a 200 status to acknowledge receipt. Non-2xx responses trigger retries.
SSL_ERRORTLS handshake failed with your endpointVerify your SSL certificate is valid and not expired
ENDPOINT_BLOCKEDYour endpoint resolved to a private IP addressWebhook URLs must resolve to public IP addresses. Localhost and private ranges are rejected.

Retry guidance

For transient errors (5xx status codes, network timeouts), implement exponential backoff:
AttemptWait time
1st retry1 second
2nd retry2 seconds
3rd retry4 seconds
4th retry8 seconds
5th retry16 seconds
Add random jitter (0 to 500ms) to each wait time to avoid thundering herd problems. Stop retrying after 5 attempts and log the failure for investigation. For 4xx errors, do not retry. These indicate a problem with the request that must be fixed before retrying.