Programmatic Access
Overview
This page is your starting point for calling the MoneyHash API directly: the base URL, how to authenticate test vs live with your API keys, the headers to send, and how requests and responses are shaped. After reading it, you'll be able to make a correctly-formed, authenticated API call without guessing.
MoneyHash exposes a JSON REST API over HTTPS. Every server-to-server request is authenticated with an account API key sent in the x-api-key header, and every response comes back in a consistent JSON envelope. The environment a call runs against - Test or Live - is decided entirely by which API key you use, not by a different URL.
Prerequisites
- An account API key (test and/or live) for the account you're integrating. See Organization and Account for how keys are organized.
- A server-side environment to send requests from. API keys are secrets and must never be shipped in a frontend or mobile app - the only client-side key is the public API key, which is used by the SDKs, not the REST API.
- A tool to make HTTP requests (cURL, your backend HTTP client, etc.).
Base URL
All endpoints share a single base URL, with the API version in the path:
https://web.moneyhash.io/api/v1.4/
The version segment (currently v1.4) may change as newer versions are released - always use the latest documented version rather than hardcoding assumptions around it. The same base URL serves both Test and Live; the environment is selected by your key (see below).
API keys
| Key | Used for | Where |
|---|---|---|
| Account API key | Account-level operations (payments, intents, transactions) | Your backend, in x-api-key |
| Organization API key | Organization-level endpoints (e.g. creating accounts) | Your backend, in x-api-key |
| Public API key | SDK & frontend usage only | Client (not used for REST) |
Each account has separate keys per environment - a test account API key and a live account API key (and likewise for the public key). For full detail on the key hierarchy and where each one lives, see Organization and Account.
Authentication & security
Authenticate every request by sending your key in the x-api-key header:
curl --location 'https://web.moneyhash.io/api/v1.4/payments/intent/' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <YOUR_ACCOUNT_API_KEY>' \
--data '<REQUEST_BODY>'Test vs Live is determined solely by the key you use. Send your test account API key to operate in Test mode, or your live account API key to operate in Live mode - the endpoint and base URL are identical for both. There's no environment header or query flag to set; the key carries the environment.
Account vs organization endpoints. Most endpoints are account-level and use the account API key. Some endpoints are organization-level and accept only the organization API key - for example, creating an account:
curl --location 'https://web.moneyhash.io/api/v1.4/accounts/' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <YOUR_ORGANIZATION_API_KEY>' \
--data '<REQUEST_BODY>'Keep all API keys on the server, store them as secure secrets, and never expose them client-side.
Headers
| Header | Required | Notes |
|---|---|---|
x-api-key | Yes | Your account (or organization) API key. Required on every request. |
Content-Type | Yes for requests with a body | Use application/json. |
X-Idempotency-Key | Optional | A v4 UUID to make write requests safe to retry. See Idempotency. |
HTTP header names are case-insensitive, so x-api-key and X-Api-Key are equivalent.
Request bodies may be sent as application/json (recommended, and used throughout this page) or application/x-www-form-urlencoded.
Request and response format
Requests and responses are JSON. Every response uses the same envelope:
{
"status": { "code": 200, "message": "success", "errors": [] },
"data": { },
"count": null,
"next": null,
"previous": null
}status-code(mirrors the HTTP status), amessage, and anerrorsarray (empty on success).data- the result: an object for a single resource, or an array for a list.count/next/previous- pagination fields (see below);nullfor non-list responses.
The envelope never changes shape, so you can rely on the same fields for every call - check status.code first, then read data. Lists add the pagination fields; single-resource responses leave them null.
Time format
All timestamps are ISO 8601 in UTC, where the trailing Z means UTC - for example 2026-06-28T08:11:31.170743Z.
Pagination
List endpoints return count (total number of items) along with next and previous - fully-qualified URLs for the adjacent pages, or null when there is no such page. Control the page with the limit and offset query parameters; limit has a maximum of 100.
https://web.moneyhash.io/api/v1.4/accounts/?limit=20&offset=20
To page through a full result set, follow next until it is null — don't compute offsets yourself; next already carries the correct limit/offset (and any required tokens):
{
"status": { "code": 200, "message": "success", "errors": [] },
"data": [
{ "id": "Vgln9", "name": "string", "payment_methods": [] },
{ "id": "A9eEg", "name": "string", "payment_methods": ["CARD"] }
],
"count": 442,
"next": "https://web.moneyhash.io/api/v1.4/accounts/?limit=20&offset=20",
"previous": null
}Errors
On failure, status.code carries a 4xx code, status.errors lists what went wrong (each entry maps a field to a message), and data is empty:
{
"status": {
"code": 400,
"message": "",
"errors": [
{ "operation": "\"pay\" is not a valid choice." },
{ "webhook_url": "This field is required." }
]
},
"data": {},
"count": null,
"next": null,
"previous": null
}A missing resource returns 404:
{
"status": { "code": 404, "message": "", "errors": [ { "detail": "Not found." } ] },
"data": {},
"count": null,
"next": null,
"previous": null
}Status codes
The HTTP status code and status.code mirror each other, so you can check either.
| Code | Meaning | What to do |
|---|---|---|
200 | Success | Read data. |
400 | Validation / bad request |