https://vaultly.plus/api/v1
← Home

Vaultly API Reference

Multi-currency wallet API with USD-based ledger. Transfer, withdraw, query balances and track withdrawal status — all from four JSON endpoints.

v1.2 JSON over HTTPS USD-pegged ledger

Introduction

Vaultly is a wallet-as-a-service platform. After registering, every user has a personal panel where they can mint API keys (each key represents one wallet) and move funds between wallets, transfer to other users, or submit withdrawal requests. Wallet balances are never stored — they are always computed from the transaction ledger.

All endpoints accept and return application/json. All money values are returned as decimal strings to avoid floating-point drift in JavaScript clients.

Authentication

Every API request authenticates per-call. There are no tokens or sessions. Each request must include the four fields below in its JSON body:

FieldTypeDescription
api_keystringThe source wallet's API key (format vk_live_…).
emailstringThe owner's email address.
password_sha512stringLower-case hex SHA-512 of the user's plaintext password (128 chars).
currencystringUpper-case currency code, e.g. USD, AED, IRR, USDT. Required for all endpoints except /withdraw/status.

The server validates these in a fixed order. Wrong email and wrong password return the same response (INVALID_CREDENTIALS) so attackers cannot enumerate accounts.

Error format

{
  "ok": false,
  "error": "INSUFFICIENT_FUNDS",
  "message": "Insufficient funds"
}
CodeHTTPMeaning
INVALID_CREDENTIALS401Email not found, or password SHA-512 mismatch.
WALLET_NOT_FOUND404The given api_key does not exist.
WALLET_NOT_OWNED403The wallet is not owned by the supplied email.
WALLET_DISABLED403The wallet has been disabled by its owner or by an admin.
CURRENCY_NOT_SUPPORTED422Unknown currency code.
DESTINATION_NOT_FOUND404(transfer) Destination wallet not found.
DESTINATION_DISABLED403(transfer) Destination wallet disabled.
SAME_WALLET422(transfer) Source equals destination.
INSUFFICIENT_FUNDS422Source wallet does not have enough USD to cover the converted amount.
INVALID_AMOUNT422Amount is zero, negative, or malformed.
WITHDRAWAL_NOT_FOUND404(/withdraw/status) Transaction code is unknown or not owned by this wallet.
WITHDRAWAL_DESTINATION_NOT_CONFIGURED500(server) ADMIN_WITHDRAWAL_API_KEY not configured.

Transfer

POST /api/v1/transfer

Move funds from one wallet to any other active wallet — yours or someone else's. Two ledger rows are created in a single DB transaction, sharing one ULID transaction code.

Request body

All authentication fields, plus:

FieldTypeDescription
destination_api_keystringThe receiving wallet's key.
amountstringDecimal string in the chosen currency, e.g. "36725.00000000".
descriptionstring?Optional, max 1000 chars.
cURL
curl -X POST https://vaultly.plus/api/v1/transfer \
  -H 'Content-Type: application/json' \
  -d '{
    "api_key": "vk_live_...",
    "email": "alice@example.com",
    "password_sha512": "<128-hex>",
    "currency": "AED",
    "destination_api_key": "vk_live_...",
    "amount": "36725.00000000",
    "description": "rent"
  }'
PHP (Guzzle)
$client = new \GuzzleHttp\Client();
$res = $client->post('https://vaultly.plus/api/v1/transfer', [
    'json' => [
        'api_key' => 'vk_live_...',
        'email' => 'alice@example.com',
        'password_sha512' => hash('sha512', $plaintextPassword),
        'currency' => 'AED',
        'destination_api_key' => 'vk_live_...',
        'amount' => '36725.00000000',
        'description' => 'rent',
    ],
]);
echo $res->getBody();
JavaScript (fetch)
const res = await fetch('https://vaultly.plus/api/v1/transfer', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    api_key: 'vk_live_...',
    email: 'alice@example.com',
    password_sha512: '',
    currency: 'AED',
    destination_api_key: 'vk_live_...',
    amount: '36725.00000000'
  })
});
console.log(await res.json());
Successful response · 200
{
  "ok": true,
  "transaction_code": "01HXY...",
  "amount_in_currency": "36725.00000000",
  "currency": "AED",
  "amount_in_usd": "10000.00000000"
}

With AED.rate = 3.6725, sending 36725 AED debits the source by exactly 10000 USD and credits the destination by exactly 10000 USD.

Withdraw

POST /api/v1/withdraw

Submit a withdrawal request. Identical to transfer except the destination wallet is fixed (the platform's withdrawal wallet) and a withdrawals record is created in pending status. An admin then changes its status to done, blocked, or refunded. Use /withdraw/status to poll the result.

Request body

All authentication fields, plus:

FieldTypeDescription
amountstringDecimal string in the chosen currency.
destinationstringRequired. External payout target — wallet address, IBAN, card number, etc. (4–500 chars). Stored on the user-leg transaction's user_description.
descriptionstring?Optional user note (max 1000 chars), appended after the destination in user_description.
cURL
curl -X POST https://vaultly.plus/api/v1/withdraw \
  -H 'Content-Type: application/json' \
  -d '{
    "api_key": "vk_live_...",
    "email": "alice@example.com",
    "password_sha512": "<128-hex>",
    "currency": "USDT",
    "amount": "250.00000000",
    "destination": "0xabc1234567890DEADBEEFcafe0000000000111122",
    "description": "monthly payout"
  }'
Successful response · 200
{
  "ok": true,
  "transaction_code": "01HZX2K8M9P3R7T2V5W8Y0Z4B6",
  "amount_in_currency": "250.00000000",
  "currency": "USDT",
  "amount_in_usd": "250.00000000"
}

Save the transaction_code — you'll need it to query /withdraw/status.

Withdraw status

POST /api/v1/withdraw/status

Look up the current status of a previously-submitted withdrawal. The wallet that originally submitted the withdrawal is the only one that can read it. The currency field is not required for this endpoint.

Request body

FieldTypeDescription
api_keystringThe wallet that submitted the withdrawal.
emailstringOwner email.
password_sha512stringSHA-512 hex of the password.
transaction_codestringThe transaction_code returned by /withdraw.
cURL
curl -X POST https://vaultly.plus/api/v1/withdraw/status \
  -H 'Content-Type: application/json' \
  -d '{
    "api_key": "vk_live_...",
    "email": "alice@example.com",
    "password_sha512": "<128-hex>",
    "transaction_code": "01HZX2K8M9P3R7T2V5W8Y0Z4B6"
  }'
Successful response · 200
{
  "ok": true,
  "transaction_code": "01HZX2K8M9P3R7T2V5W8Y0Z4B6",
  "status": "done",
  "admin_description": "Paid via TRC-20, tx 0x9f2a…",
  "user_description": "Destination: 0xabc1234567890DEADBEEFcafe0000000000111122\nmonthly payout",
  "amount_in_currency": "250.00000000",
  "currency": "USDT",
  "created_at": "2026-05-04T10:14:00+00:00",
  "updated_at": "2026-05-04T11:02:18+00:00"
}

Status values

StatusMeaning
pendingAwaiting admin review. admin_description will be null.
doneAdmin marked the withdrawal as completed. admin_description typically contains the on-chain tx hash or bank reference.
blockedAdmin rejected the withdrawal but did not refund the user. Funds remain in the platform's withdrawal wallet.
refundedAdmin refunded the user's wallet. admin_description includes the refund transaction code.

Balance

POST /api/v1/balance

Return the wallet's balance in USD plus the equivalent in any supported currency. This endpoint never writes a transaction.

cURL
curl -X POST https://vaultly.plus/api/v1/balance \
  -H 'Content-Type: application/json' \
  -d '{
    "api_key": "vk_live_...",
    "email": "alice@example.com",
    "password_sha512": "<128-hex>",
    "currency": "AED"
  }'
Successful response · 200
{
  "ok": true,
  "balance_in_currency": "36725.00000000",
  "currency": "AED",
  "balance_in_usd": "10000.00000000"
}

Rates

GET /api/v1/rates

Return every supported currency together with its current USD rate. Public endpoint — no authentication required. The rate_to_usd field is the multiplier such that amount_in_currency = amount_in_usd × rate_to_usd.

cURL
curl https://vaultly.plus/api/v1/rates
Successful response · 200
{
  "ok": true,
  "base": "USD",
  "count": 162,
  "rates": [
    { "code": "USDC", "type": "crypto", "rate_to_usd": "1.00000000", "updated_at": "2026-05-04T08:00:00+00:00" },
    { "code": "USDT", "type": "crypto", "rate_to_usd": "1.00000000", "updated_at": "2026-05-04T08:00:00+00:00" },
    { "code": "AED",  "type": "fiat",   "rate_to_usd": "3.67250000", "updated_at": "2026-05-04T11:00:12+00:00" },
    { "code": "EUR",  "type": "fiat",   "rate_to_usd": "0.92810000", "updated_at": "2026-05-04T11:00:12+00:00" },
    { "code": "GBP",  "type": "fiat",   "rate_to_usd": "0.79420000", "updated_at": "2026-05-04T11:00:12+00:00" },
    { "code": "IRR",  "type": "fiat",   "rate_to_usd": "905000.00000000", "updated_at": "2026-05-04T11:14:33+00:00" },
    { "code": "USD",  "type": "fiat",   "rate_to_usd": "1.00000000", "updated_at": "2026-05-04T11:00:12+00:00" }
    /* …rest of currencies… */
  ]
}

Currency codes

All currency codes are upper-case ISO 4217 (fiat) or ticker symbols (crypto). Vaultly supports the full set returned by exchangerate-api.com (≈160 fiat currencies) plus a handful of manually-pegged crypto stablecoins. Use GET /api/v1/rates for the canonical, live list.

Highlights

CodeTypeSourceRefresh
USDfiatBase — always 1.00000000
EUR, GBP, AED, JPY, CNY, TRY, INR, SAR, CAD, AUD, CHF… (~160 codes)fiatexchangerate-api.comhourly
IRRfiatWallex (USDT/TMN price × 10)every 15 min
USDT, USDCcryptoManually pegged to 1.00000000manual

Sample of supported fiat codes: AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, STN, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XDR, XOF, XPF, YER, ZAR, ZMW, ZWL — and more added by the upstream provider.

Rate limits

The API enforces 60 requests per minute per IP across all endpoints. Excess traffic returns HTTP 429.

Changelog

  • v1.2 — added GET /api/v1/rates; documented full ISO 4217 fiat coverage (~160 currencies) plus pegged stablecoins.
  • v1.1 — added /api/v1/withdraw/status; /withdraw now requires a destination field (wallet address, IBAN, etc.) which is persisted on the user-leg transaction.
  • v1.0 — initial release with transfer, withdraw, balance.