Data Formats and IDs
Units, types, timestamps and which identifier each endpoint expects.
This is the reference for how values are represented across the API: amounts and units, field types, timestamps, currencies and networks, and identifiers.
Amounts and units
Every amount is in major units of the currency: dollars, not cents. 25.50 means twenty-five dollars and fifty cents. That holds in both directions.
Amounts you send
Send a JSON number. A numeric string is accepted and read as the same value, so these are equivalent:
JSON
{ "amount": 100 }JSON
{ "amount": "100.00" }Amounts you read
A response carries an amount in one of two forms, fixed per field:
Each endpoint's reference page gives the form for the fields it returns; read a field as the type shown there rather than inferring it from a sibling.
A field carrying no amount, such as a card that has never been funded or an optional product limit, is null rather than a zero.
A zero balance is "0.00". That string is truthy in JavaScript, so a plain if (card.balance) is true for an empty card. Compare the parsed number:
Node.js
if (Number(card.balance) > 0) {
// the card has funds
}_no_rounding fields
On a card-transaction entry, each monetary field appears twice: a rounded value for display, and a _ companion carrying the same amount at full precision for arithmetic and reconciliation. The rounded field is a JSON number and its full-precision companion is a decimal string.
| Rounded — number | Full precision — string |
|---|---|
amount | amount_ |
amount_ | amount_ |
amount_ | amount_ |
amount_ | amount_ |
fees[].amount | fees[].amount_ |
amount is expressed in the card's currency (ledger_); amount_ is the amount the merchant charged, in transaction_. See Fetching card transactions for the entry types these fields belong to.
Flags
Flags you send are JSON booleans. {"frozen": true} freezes a card, and the query-string flags include_, inactive_, include_ and include_ take true or false.
Flags you read come in one of two forms, fixed per field:
| Form | Where | Meaning |
|---|---|---|
1 / 0 | Card frozen, terminated, activated; velocity control enabled | 1 is on, 0 is off |
A card frozen with {"frozen": true} therefore reads back as "frozen": 1. A flag with no value set is 0, not null.
If your language distinguishes the two — Go, Java, C# and typed TypeScript models do — declare the card and velocity flags as integers and compare against 1.
Timestamps and dates
Timestamps you read are ISO-8601 in UTC, with milliseconds: "2030-11-27T19:21:39.000Z". That is the form of expiration on a card, created_ and updated_ on every resource, and expires_ on a KYC link.
Card-transaction entries carry the instant twice, and both are the same moment: datetime in that millisecond form, and datetime_ to the second, "2026-08-16T17:51:01Z".
display_ on a card is not a timestamp: it is the card's expiry rendered as MM/YY for printing on the card face, for example "12/29". Use expiration for logic and display_ for display.
Dates you send are calendar days. GET /v2/api-gateway/accounts/{id}/transactions takes start_ and end_ as inclusive UTC days in YYYY-MM-DD form, and accepts them as a pair.
cURL
curl --request GET \
--url 'https://api.themooncard.com/v2/api-gateway/accounts/6c1c9a37-9c1b-4f6c-9e79-8f8a2f0d5f31/transactions?start_date=2026-08-01&end_date=2026-08-16' \
--header 'accept: application/json' \
--header 'x-api-key: YOUR_API_KEY'Currencies, assets and networks
Fiat currencies are ISO-4217 codes. Where a field is open — transaction_ on a simulated transaction, currency on an account or card product, ledger_ on a transaction — send or expect the standard three-letter code.
Where the API constrains the choice, these are the accepted values:
| Field | Accepted values |
|---|---|
card_ (V1 create card) | USD (default), MXN |
account_ (V2 create account) | USD (default), MXN |
merchant_ on a simulated transaction is an ISO-3166 alpha-2 code, for example US.
Identifiers
There are two families of identifier: the one you choose for a cardholder, and the ones Moon assigns.
Your identifier for a cardholder
external_ is your own identifier for a cardholder. It is a free-form string — customer_ is fine — unique within your organization. V1 request bodies and query strings accept external_ as an alias for the same value.
| Endpoint | Takes |
|---|---|
POST /v1/api-gateway/card/{card_ | your cardholder identifier in the body |
GET /v1/api-gateway/card, GET /v2/api-gateway/cards | your cardholder identifier as a filter |
GET /v1/api-gateway/cardholder/{end_ | your cardholder identifier in the path |
POST /v1/api-gateway/cardholder/{end_ | your cardholder identifier in the path |
PATCH /v1/api-gateway/end-customer/{id} | your cardholder identifier in the path |
GET /controls/velocity/cardholder/{external_ (V1 and V2) | your cardholder identifier in the path |
POST /v2/api-gateway/cardholders | external_ in the body |
POST /controls/velocity (V1 and V2) | external_ in the body |
Moon's identifiers
Moon assigns these and returns them to you. Store the ones you will need again.
| Identifier | Format | Where it comes from | Where it is used |
|---|---|---|---|
| Card id | UUID | id on any card object | {card_ on every card route, card_ on velocity controls |
| Cardholder id | UUID | id on a cardholder object | {id} on the V2 cardholder routes, {cardholder_ on V1 check and verification-documents, cardholder_ in create-card and velocity-control bodies |
| Organization id | UUID | id from GET /v2/api-gateway/organizations | {id} on the organization routes, organization_ on create account, create cardholder, list filters |
| Transaction id | UUID on card-purchase, DECLINE and TOP_ entries; a number on REFUND, MOON_ and DELETION entries | data.id of a card-transaction entry | {transaction_ on the get-transaction-by-id routes, which take the UUID form |
| Velocity control id | opaque string | id from GET /controls/velocity | {id} on the velocity-control routes; send it back verbatim |
Card id and transaction id
GET /v1/api-gateway/card/{card_ takes both, in that order. card_ is the card's id. transaction_ is data.id of an entry in that card's feed; data.transaction_ is the network's own reference on card-purchase entries. The V2 route GET /cards/{card_ follows the same rule.
Fields for Moon's internal reference
user_, ledger_ and the numeric card_ inside transaction entries are Moon's internal references and are documented as such in the reference. Identify a card by card.public_ or card_, and a transaction entry by data.id.
Id validation
Path parameters typed as UUIDs are validated before the lookup runs, so an id that is not a well-formed UUID returns a validation 400:
JSON
{
"errors": [
{ "msg": "Invalid uuid", "param": "cardId", "location": "query" }
]
}A well-formed UUID that does not exist, or that belongs to another organization, returns a 404. An unknown id used as a list filter returns 200 with an empty list — see Pagination. Full error rules are on Errors.
Related
- Pagination — list parameters, the
paginationobject and empty-result behaviour. - Errors — the error envelope and the code catalogue.
- Fetching card transactions — the transaction entry types.
Last updated September 25, 2026