Fetching Card Transactions
GET /v1/api-gateway/card/{card_ returns the activity feed of one card: purchases, refunds, declines, the card's own creation and deletion, and — on request — balance loads. It is the record you reconcile against; webhooks are how you learn about the same events as they happen.
Request
cURL
curl --request GET \
--url 'https://api.themooncard.com/v1/api-gateway/card/7c9e6679-7425-40de-944b-e07fc1f90ae7/transactions?current_page=1&per_page=10' \
--header 'accept: application/json' \
--header 'x-api-key: YOUR_API_KEY'| Parameter | In | Default | Notes |
|---|---|---|---|
card_ | path | — | The card's id (a UUID), as returned by the card endpoints. |
current_ | query | 1 | Page number, starting at 1. |
per_ | query | 10 | Items per page. Minimum 1, maximum 50. |
include_ | query | false | Set to true to include balance loads to this card as TOP_ entries. |
This endpoint returns 200 with an empty transactions array for a card_ outside your organization. To confirm a card exists, fetch it with GET /v1/api-gateway/card/{card_, which returns 404 for an id you cannot see.
Response
JSON
HTTP/1.1 200 OK
{
"transactions": [
{
"type": "CARD_TRANSACTION",
"data": {
"id": "500539aa-d323-4fe7-9162-8d6123515ec5",
"card": {
"public_id": "3f0c8a12-5b6d-4e7f-9a01-2b3c4d5e6f70",
"name": "Marketing spend",
"type": "Moon 1X Card",
"last_four": "4242"
},
"transaction_id": "500539aa-d323-4fe7-9162-8d6123515ec5",
"transaction_status": "SETTLED",
"datetime": "2026-08-16T17:51:01Z",
"datetime_iso": "2026-08-16T17:51:01Z",
"merchant": "Starbucks",
"merchant_mid": "mid_123",
"amount": 14.85,
"amount_no_rounding": "14.85",
"ledger_currency": "USD",
"amount_fees_in_ledger_currency": 0.15,
"amount_fees_in_ledger_currency_no_rounding": "0.1485",
"amount_in_transaction_currency": 85,
"amount_in_transaction_currency_no_rounding": "85",
"transaction_currency": "BRL",
"amount_fees_in_transaction_currency": 0.85,
"amount_fees_in_transaction_currency_no_rounding": "0.85",
"fees": [
{
"type": "TRANSACTION_FEE",
"amount": 0.15,
"amount_no_rounding": "0.1485",
"fee_amount_in_transaction_currency": 0.85,
"fee_description": "A 1.00% fee (minimum of $0.00) is charged on all transactions"
}
]
}
}
],
"pagination": {
"total": 42,
"last_page": 5,
"prev_page": null,
"next_page": 2,
"per_page": 10,
"current_page": 1,
"from": 1,
"to": 10
}
}pagination is the same envelope every list endpoint returns: 1-based current_, prev_ and next_ null at the ends, and from/to both 0 when the page is empty. See Pagination.
The transactions array is a union
Each entry is { "type": ..., "data": ... }, and type tells you which data shape to expect. Branch on type before reading anything else, and ignore entries whose type you do not recognise — the feed can gain new kinds of activity.
type | What it is | Shape of data |
|---|---|---|
CARD_ | A purchase, at any point in its lifecycle. | The full transaction shape shown above. |
CARD_ | A refund of a card purchase. | The same shape as CARD_. |
DECLINE | A declined authorization. | id, datetime, merchant, merchant_, amount, customer_, card_, card_, card. |
DELETION | The card being deleted, with any amount returned. | id, datetime, merchant, amount, card_, refunded_. |
TOP_ | A balance load onto this card. Only present with include_. | id, created_, user_, merchant_, amount, datetime, card_, card_. |
Two mappings to hold on to:
- A decline appears in the feed as
type: "DECLINE". The webhook for the same event isCARD_.DECLINE card_andid user_are Moon's internal references wherever they appear above. Identify the card bysub card.public_orid card_, and the entry bypublic_ id data.id.
A declined entry looks like this:
JSON
{
"type": "DECLINE",
"data": {
"id": "8c2f1b45-6a7d-4e83-9012-3f4a5b6c7d8e",
"datetime": "2026-08-16T18:02:44Z",
"merchant": "ONLINE STORE",
"merchant_mid": "mid_456",
"amount": 29.99,
"customer_friendly_description": "Insufficient Funds",
"card_public_id": "3f0c8a12-5b6d-4e7f-9a01-2b3c4d5e6f70",
"card_id": 918273,
"card": {
"public_id": "3f0c8a12-5b6d-4e7f-9a01-2b3c4d5e6f70",
"name": "Marketing spend",
"type": "Moon 1X Card",
"last_four": "4242"
}
}
}Amounts, fees and currencies
ledger_ is the card's own currency; transaction_ is the currency the merchant charged in. When they differ, the amount was converted at the rate in force at the time. Both are ISO 4217 codes.
amountandamount_are the principal excluding fees, rounded for display.in_ transaction_ currency amount_andfees_ in_ ledger_ currency amount_are the total fees for this entry in each currency.fees_ in_ transaction_ currency - Every field ending in
_is the same value as a full-precision string. Use those for arithmetic and reconciliation; use the numbers for display.no_ rounding
fees breaks the total down, one object per fee line:
| Field | Type | Notes |
|---|---|---|
type | string | TRANSACTION_. |
amount | number | The fee in the ledger currency, rounded to that currency's decimal places. |
amount_ | string | The same fee at full precision. |
fee_ | number | null | The fee in the transaction currency, or null when it cannot be expressed there. |
fee_ | string | Human-readable explanation of the fee. |
sum(fees[].amount) equals amount_ exactly: the total is the sum of the rounded lines, not a separately rounded figure. When the rounded total is zero — a small refund whose proportional fee lands below one cent, for instance — fees is an empty array while the _ fields still carry the real figure.
Timestamps
Both timestamp fields are ISO-8601 UTC, in two precisions:
datetime_—iso 2026-08-16T17:51:01Z. Read this one.datetime—2026-08-16T17:51:01.000Z, the same instant with milliseconds.
created_ on the MOON_ and TOP_ entries has the same millisecond form as datetime. See Data formats and ids.
Fetching a single transaction
GET /v1/api-gateway/card/{card_ (reference) returns one entry in the same { type, data } form, with no list or pagination envelope around it. transaction_ is the data.id of an entry in the feed.
It answers 404 with CARD_ when the card is unknown or not yours, and TRANSACTION_ when the transaction is not on that card.
In V2
GET /v2/api-gateway/cards/{card_ (reference) returns the identical envelope and the identical union, and takes the same current_, per_ and include_. Two differences:
- It also accepts a cardholder session token. With a session token the card must belong to that cardholder; if it does not, the response is
404rather than an empty list. With an API key the empty-list behaviour is the same as V1. See Authentication. - Its single-transaction sibling is
GET /v2/api-gateway/cards/{card_.id}/transactions/{transaction_ id}
V2 adds GET /v2/api-gateway/accounts/{id}/transactions (reference), which returns the same union for every card on an account plus account-level credits, and adds three filters — start_, end_ (inclusive UTC calendar days, YYYY-MM-DD, valid only together) and transactionType. Those keys are camelCase as well. transactionType selects by activity type (CARD_, CARD_, CARD_, CARD_, DELETION, MOON_, TOP_); the entries come back with the type values in the union table above, so transactionType=CARD_ selects entries whose type is DECLINE.
See API versions for the full V1 ↔ V2 map.
Testing this in Sandbox
A new card's feed is empty. Generate activity first with the simulate endpoint, then read it back here — the entries and the webhooks you receive describe the same events.
Last updated August 17, 2026