Errors
AccruPay uses the standard GraphQL error envelope for all API-level failures. Transaction declines are a separate concern and are not represented as GraphQL errors.
GraphQL error envelope
When an operation fails at the API level, the response includes an errors array and data is null (or the failing field is null).
{
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHENTICATED"
}
}
],
"data": null
}
The extensions.code field is the machine-readable error code. Always branch on extensions.code, not on message — message text may change without notice.
extensions.code values
| Code | Triggers | Recommended action |
|---|---|---|
UNAUTHENTICATED | Missing or invalid accrupay-api-secret header | Verify the API secret is set correctly and is not expired |
FORBIDDEN | Valid credentials but insufficient permissions for the requested resource | Check that the API key belongs to the correct merchant account and has access to the requested operation |
NOT_FOUND | The requested resource (transaction, payment method, plan, etc.) does not exist or does not belong to this merchant | Verify the ID is correct and was created under this merchant account |
VALIDATION_ERROR | Required field is missing, a value is out of range, or a field fails format validation | Check the message field for field-level detail; fix the input and retry |
INTERNAL_SERVER_ERROR | Unexpected server-side failure | Retry with exponential backoff; if the issue persists, contact AccruPay support with the full error response |
Transaction declines are not API errors
A payment that is declined or fails at the provider level does not produce a GraphQL errors entry. The mutation resolves successfully and returns a transaction object. You must check transaction.status in the response data.
{
"data": {
"merchantApiServerPaymentMethodTransactionCreate": {
"id": "txn-uuid",
"status": "DECLINED",
"providerError": "Insufficient funds"
}
}
}
Transaction terminal statuses
| Status | Meaning | What to show the customer |
|---|---|---|
SUCCEEDED | Payment completed successfully | Confirmation — order fulfilled |
DECLINED | Card network or issuer declined the charge | Ask the customer to try a different payment method |
FAILED | Provider-side processing failure (e.g. timeout, invalid card data) | Generic error — try again or contact support |
CANCELED | Authorization was released without capture | No charge was made |
SUCCEEDED (action: REFUND) | Refund processed | Confirm refund amount in refundedAmount field |
Check the providerError field for the raw decline reason returned by the provider. This is useful for logging and support, but should not be shown verbatim to customers.
providerError field
Most transaction return types include a providerError field:
{
id
status
providerError
}
providerError is populated when status is DECLINED or FAILED. It contains the provider's raw reason string (e.g. "Do not honor", "Insufficient funds", "Invalid card number").
Use providerError for:
- Internal logging and alerting
- Support ticket context
- Reconciliation when a statement entry is unclear
Do not expose providerError directly to end customers. Map it to a user-friendly message in your application layer.
Network errors vs GraphQL errors
HTTP-level failures (5xx, network timeouts, DNS failures) do not produce a GraphQL errors array — the response body may be empty or non-JSON. Handle these separately:
| Scenario | Behavior | Recommendation |
|---|---|---|
HTTP 200 with errors[] | GraphQL error — parseable JSON | Branch on extensions.code |
HTTP 200 with data | Successful response | Check transaction.status for declines |
| HTTP 401 | Authentication rejected at the HTTP layer before GraphQL | Same as UNAUTHENTICATED — check the API secret |
| HTTP 5xx | Server error before GraphQL processing | Retry with backoff |
| Network timeout / no response | Transport-level failure | Retry; use merchantInternalTransactionCode as idempotency key to avoid duplicate charges |
Idempotency and retries
merchantInternalTransactionCode is your idempotency key for charge mutations. If a request times out and you are unsure whether it was processed, do not retry with a new code — first query the transaction by merchantInternalTransactionCode to check whether it was created.
Related
- GraphQL Overview
- Server Payments — where transaction status matters most
- Error Reference — complete lookup table including SDK error classes