Appearance
Top Up Card
Create a top-up request that transfers funds from the user's Holyheld main account to the Holyheld card. The request is accepted synchronously, but the balance update is asynchronous — it may take up to 5 minutes to appear on the card.
Endpoint
POST https://apicore.holyheld.com/v4/ai-agents/topup-requestRequest
| Header | Required | Value |
|---|---|---|
Authorization | ✅ | Bearer <token> |
Content-Type | ✅ | application/json |
Request body:
json
{
"amount": "50.00"
}| Field | Type | Required | Description |
|---|---|---|---|
amount | string | ✅ | Amount in EUR to top up. Must be a decimal string matching ^\d+(\.\d{1,2})?$ |
Amount format rules
The amount field must be a string (not a number) and must match the pattern ^\d+(\.\d{1,2})?$:
| Value | Valid? | Note |
|---|---|---|
"50" | ✅ | Integer amounts are valid |
"50.00" | ✅ | Two decimal places |
"50.5" | ✅ | One decimal place |
"50.123" | ❌ | More than 2 decimal places |
50.00 | ❌ | Number type — must be a string |
"€50" | ❌ | No currency symbol |
"-10" | ❌ | No negative values |
Use amount.toFixed(2) in JavaScript to format a number as a valid amount string.
Response
200 OK — top-up request accepted
json
{
"status": "ok"
}A 200 response means the request was accepted and the top-up process has begun. It does not mean the balance has already updated. Poll GET /balance to confirm the settlement.
Balance updates are asynchronous
After receiving a 200, the card balance may take up to 5 minutes to reflect the top-up. Do not assume the top-up is reflected immediately. Always poll to confirm before reporting success to the user.
The polling pattern
After a successful POST /topup-request, poll GET /balance until the balance increases or a timeout is reached.
javascript
const BASE_URL = 'https://apicore.holyheld.com/v4/ai-agents';
const POLL_INTERVAL_MS = 30_000; // 30 seconds
const TIMEOUT_MS = 5 * 60_000; // 5 minutes
async function topUpAndConfirm(amount, token) {
const headers = {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
};
// 1. Record balance before top-up
const beforeRes = await fetch(`${BASE_URL}/balance`, { headers });
const before = await beforeRes.json();
const balanceBefore = parseFloat(before.payload.balance);
// 2. Request the top-up
const topupRes = await fetch(`${BASE_URL}/topup-request`, {
method: 'POST',
headers,
body: JSON.stringify({ amount: parseFloat(amount).toFixed(2) }),
});
if (!topupRes.ok) {
const err = await topupRes.json();
throw new Error(`Top-up failed: ${err.errorCode} — ${err.error}`);
}
// 3. Poll until balance increases or timeout
const deadline = Date.now() + TIMEOUT_MS;
while (Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
const currentRes = await fetch(`${BASE_URL}/balance`, { headers });
const current = await currentRes.json();
const balanceNow = parseFloat(current.payload.balance);
if (balanceNow > balanceBefore) {
return {
success: true,
previousBalance: balanceBefore,
newBalance: balanceNow,
added: balanceNow - balanceBefore,
};
}
}
// Timeout — top-up may still complete; advise the user to check later
throw new Error(
'Top-up accepted but balance has not updated within 5 minutes. ' +
'Check your Holyheld card balance in a few minutes.'
);
}bash
curl -X POST https://apicore.holyheld.com/v4/ai-agents/topup-request \
-H "Authorization: Bearer $HOLYHELD_AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"amount": "50.00"}'python
import httpx, time, os
BASE_URL = 'https://apicore.holyheld.com/v4/ai-agents'
def topup_and_confirm(amount: float, token: str) -> dict:
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json',
}
# 1. Record balance before
before = httpx.get(f'{BASE_URL}/balance', headers=headers)
balance_before = float(before.json()['payload']['balance'])
# 2. Request top-up
res = httpx.post(
f'{BASE_URL}/topup-request',
headers=headers,
json={'amount': f'{amount:.2f}'},
)
if res.status_code != 200:
err = res.json()
raise RuntimeError(f"{err['errorCode']}: {err['error']}")
# 3. Poll
deadline = time.time() + 300 # 5 minutes
while time.time() < deadline:
time.sleep(30)
current = httpx.get(f'{BASE_URL}/balance', headers=headers)
balance_now = float(current.json()['payload']['balance'])
if balance_now > balance_before:
return {'new_balance': balance_now, 'added': balance_now - balance_before}
raise TimeoutError('Top-up accepted but balance not updated within 5 minutes.')Error responses
400 Bad Request — malformed amount
json
{
"status": "error",
"errorCode": "WRONG_REQUEST",
"error": "Failed to parse request body"
}Check the amount format. See Amount format rules above.
500 — Insufficient balance
json
{
"status": "error",
"errorCode": "AI_TOPUP_INSUFFICIENT_BALANCE",
"error": "Insufficient balance for top up"
}The user does not have enough available balance on their Holyheld main account. The agent cannot resolve this autonomously — notify the user that they need to add funds to their Holyheld account.
500 — Spending limit exceeded
json
{
"status": "error",
"errorCode": "AI_TOPUP_LIMIT_EXCEEDED",
"error": "Limit exceeded"
}The agent's cumulative spending limit has been reached. Only the user can reset this limit from the Holyheld dashboard. Do not retry — further attempts will continue to fail until the user resets the limit. Notify the user immediately.
500 / default — Internal server error
json
{
"status": "error",
"errorCode": "INTERNAL_SERVER_ERROR",
"error": "Internal Server Error"
}An unexpected server-side error occurred. Retry with exponential backoff (1s → 2s → 4s). If the error persists after 3 attempts, surface a generic failure message to the user.
Error handling decision tree:
POST /topup-request
│
├── 200 OK ──────────────────► Poll GET /balance (up to 5 min)
│ │
│ balance increased?
│ ├── Yes ──► Report success
│ └── No ──► Report timeout; advise manual check
│
├── 400 WRONG_REQUEST ────────► Fix amount format and retry immediately
│
├── 401/403 AI_AUTHORIZATION_INVALID ──► Check Bearer token or get new agent instructions
│
├── 500 AI_TOPUP_INSUFFICIENT_BALANCE ──► Notify user: add funds to Holyheld account
│ Do NOT retry — user action required
│
├── 500 AI_TOPUP_LIMIT_EXCEEDED ────────► Notify user: reset limit in dashboard
│ Do NOT retry — user action required
│
└── 500 INTERNAL_SERVER_ERROR ──────────► Retry with exponential backoff (max 3×)See Error Reference for full recovery guidance.
Next steps
Read the Error Reference for handling every error code. Then see Build an MCP Server to wrap these endpoints as Claude tools.
