> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pazy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Expense transaction events

> The expense.transaction.status_changed event for card and UPI transactions

## `expense.transaction.status_changed`

Fired when a card or UPI transaction reaches a **final outcome**. Only final outcomes are sent, so each transaction produces exactly one event. An approved authorization isn't reported on its own. You hear about it when it succeeds or fails.

### Statuses

| `status` | Meaning |
| - | - |
| `DECLINED` | Declined by Pazy because of a spend limit, card control or policy |
| `SUCCEEDED` | The transaction completed successfully |
| `FAILED` | The transaction failed at the bank or card network after authorization |
| `REFUNDED` | The transaction was reversed or refunded |

### Fields

| Field | Type | Description |
| - | - | - |
| `id` | string | The expense id. Use it with [Expense Details](/apis/expense-details) for the full record |
| `status` | string | See the table above |
| `expenseType` | string \| null | `UPI` or `PREPAID_CARD` |
| `amount` | string (decimal) | The transaction amount |
| `amountPaid` | string (decimal) \| null | What actually settled, which can differ from `amount`. `null` when nothing settled, for example on `DECLINED` |
| `currency` | string | ISO 4217 code |
| `utr` | string \| null | Banking reference. `null` on declines |
| `paymentChannel` | string \| null | The payment rail: `UPI`, `ECOM`, `POS`, `ATM` or `CONTACTLESS` |
| `merchant` | object \| null | `{ name, vpa }`. Each value can be `null` |
| `card` | object \| null | `{ name, maskedNumber, id }`, the card the payment used. Also set for `UPI`, which runs on the card instrument |
| `initiator` | object \| null | `{ id, name }`, the cardholder. `name` can be `null` |
| `createdAt` | string (ISO 8601) \| null | When the transaction was recorded |
| `metadata` | object \| null | Extra details for the outcome. See below |

### Metadata

`metadata` is open-ended and can gain keys over time. Every outcome includes `mccCode` (the merchant category code) where available, plus:

| `status` | Additional `metadata` keys |
| - | - |
| `DECLINED` | `rejectionErrorCode` and `rejectionMessage`, explaining why Pazy refused it |
| `SUCCEEDED`, `FAILED` | None |
| `REFUNDED` | `refundAmount`, `refundDate`, and `refundSettlementStatus` (`FULL` or `PARTIAL`, often absent) |

### Example: declined card payment

```json theme={null}
{
  "id": "exp_8fk21ma",
  "status": "DECLINED",
  "expenseType": "PREPAID_CARD",
  "amount": "2499.00",
  "amountPaid": null,
  "currency": "INR",
  "utr": null,
  "paymentChannel": "ECOM",
  "merchant": { "name": "AMAZON RETAIL", "vpa": null },
  "card": { "name": "Marketing Card", "maskedNumber": "****4421", "id": "crd_921kfa" },
  "initiator": { "id": "usr_2mfk1", "name": "A. Sharma" },
  "createdAt": "2026-08-10T09:14:21.000Z",
  "metadata": {
    "mccCode": "5942",
    "rejectionErrorCode": "LIMIT_EXCEEDED",
    "rejectionMessage": "Per-transaction limit exceeded"
  }
}
```

### Things to know

* To tell UPI from card payments, check `expenseType` or `paymentChannel`. Don't rely on whether `card` is present, because one card can transact over both rails.
* Fee-only surcharge transactions don't create an expense record, so they raise no event.
* Receipts usually arrive after the payment. To get them, subscribe to [`expense.attachment.updated`](/webhooks/events/expense-attachment).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.