The Card Declines API is in Beta. Additive changes are normal, and breaking changes may be made with notice while the resource incorporates customer feedback. See Versioning and compatibility.
The Transactions API tells you a card payment failed. This resource tells you why, in words you can hand to whoever is asking.
GET /api/v1/transactions/{transaction_id}/declined-authorizationsEvery declined attempt on a card transaction comes back with the reasons it was declined, a plain-language explanation, and the recommended_actions a person can take. The wording matches what the card decline email tells the cardholder, so the API and the email give the same answer.
Card transactions can carry a declined attempt and still be pending or settled. A merchant that raises an authorization mid-stay - a hotel, a car rental, a fuel pump - sends an incremental authorization, and that increment can be declined after the first one succeeded. So the resource gates on transaction type, not on status, and you should not assume status: failed is the only place declines live.
| Situation | Response |
|---|---|
| A card transaction with declined attempts | 200 with one entry per attempt, oldest first |
| A card transaction where nothing was declined | 200 with declined_authorizations: [] |
| A transaction that is not a card transaction | 400 - wires, ACH, and checks cannot carry card declines |
| No transaction with that id in your business | 404 |
| Cards data could not be read | 503 |
transaction_id is the same identifier GET /api/v1/transactions returns, and this sub-resource lives on the same v1 surface as its parent transaction.
| Field | What it tells you |
|---|---|
amount | The amount of this authorization attempt, in minor units. This is the attempt's own amount, not the transaction's net amount - an incremental authorization is worth less than the transaction it belongs to. |
reasons | Why the attempt was declined. Never empty. More than one reason can apply to a single attempt: a card can hit its own limit and a blocked merchant category in the same authorization. |
Each reason carries three things:
| Field | What it tells you |
|---|---|
code | A stable identifier such as card_locked or card_limit_reached. |
explanation | One or two sentences a person can read, matching what the decline email tells the cardholder. Constant per code, and carries no transaction data. |
recommended_actions | What to do next, in the order to try it. Empty when there is no customer-side remedy - a cash withdrawal is declined because no Rho card supports one, and there is nothing to change. |
curl "https://rhoapi.rho.co/api/v1/transactions/{transaction_id}/declined-authorizations" \
-H "Authorization: Bearer $RHO_API_TOKEN"{
"declined_authorizations": [
{
"amount": { "amount": 10000, "currency": "USD" },
"reasons": [
{
"code": "card_locked",
"explanation": "Your card was declined because it's locked.",
"recommended_actions": [
{
"code": "unlock_card",
"description": "Unlock your card to continue using it. You can do it on the card's detail page in your Rho dashboard or mobile app."
}
]
}
]
}
]
}There is no batch path. List transactions, keep the card ones you care about, and call this resource per transaction. That is one extra call each, which is fine for a support lookup on a handful of transactions and worth telling us about if you are doing it across a whole page.
transactions:read. This is a sub-resource of a transaction the token can already read, so it needs no second grant.
Full endpoint catalogue - paths, parameters, response shapes, and the complete code lists - lives in the API Reference.