VantaTool API
A RESTful API to access all marketplace features programmatically — browse accounts, place boost orders, receive OTP codes, and manage your wallet.
Authentication required. All endpoints require an API key. Get yours from your Developer Dashboard.
There is currently no rate limit enforced on any endpoint. Be a good citizen anyway — batch and cache where you can.
lock Authentication
Include your API key in every request using one of these methods (checked in this order):
# 1. Recommended: custom header curl https://vanta.aces-portal.com/api/v1/me \ -H "X-API-Key: ik_live_YOUR_KEY" # 2. Bearer token curl https://vanta.aces-portal.com/api/v1/me \ -H "Authorization: Bearer ik_live_YOUR_KEY" # 3. Query parameter (less secure — avoid in production, ends up in logs) curl "https://vanta.aces-portal.com/api/v1/me?api_key=ik_live_YOUR_KEY"
Keep your API keys secret. Never expose them in frontend JavaScript or public repositories.
Key types
| ik_live_* | Production key — real transactions, real balance deducted, real provider calls. |
| ik_test_* | Sandbox key — fully simulated, no balance deducted, no provider call made. Works on /api/v1/sandbox/* routes, and also transparently simulates on the 4 live write endpoints (purchase/order/boost-order/sms-order) — see Sandbox. |
A note on 404s
Two different 404 shapes exist. If a resource ID doesn't exist in the database at all, Laravel's own route-model-binding returns its default shape: {"message": "No query results for model [...] 999"}. If the resource exists but doesn't belong to you (or is inactive), the app returns its own consistent shape: {"status": "error", "message": "..."}. Don't assume every 404 has a status field.
data_object Response format
All responses return application/json with a top-level status field of "success" or "error".
// Success { "status": "success", "data": { ... }, "meta": { "current_page": 1, "last_page": 5, "per_page": 20, "total": 98 } } // Error { "status": "error", "message": "Insufficient wallet balance.", "errors": { "quantity": ["The quantity field is required."] } }
Pagination isn't identical everywhere. On /accounts, /orders, /boosts/orders and /sms/orders, meta sits at the top level, a sibling of data. On /wallet, it's nested inside data.meta. Check the response fields table on each endpoint below.
Decimal fields serialize as strings. Any money field backed by a decimal database column (e.g. account price, wallet transaction amount) is returned as a string like "4500.00", not a JSON number — parse it before doing arithmetic. Fields backed by a plain float/computed column (e.g. order total, boost price_ngn) are real numbers. Each response fields table below marks this explicitly.
error HTTP status codes
| 200 | OK — Successful GET/listing, or a state-changing action that isn't a creation (check/resend/cancel). |
| 201 | Created — Order, purchase, or boost/SMS order was created and its status is not failed. |
| 401 | Unauthorized — Missing, invalid, or inactive API key. |
| 403 | Forbidden — A live key (ik_live_*) was used on a /sandbox/* route. (The reverse isn't blocked — a sandbox key works fine on live routes; see Sandbox.) |
| 404 | Not Found — Resource doesn't exist, doesn't belong to you, or (for accounts) is inactive. Two different shapes — see the note above. |
| 409 | Conflict — You already have a purchase/order/boost/SMS request in flight. Wait a moment and retry. |
| 410 | Gone — SMS order expired without receiving an OTP (auto-refunded if it was charged). |
| 422 | Unprocessable — Validation error, insufficient wallet balance, quantity outside the service's min/max, delivery failed (order created with status failed, not charged), or an action not valid for the order's current status. |
| 402 | Payment Required — Rare: the upstream provider accepted the order but the wallet debit failed afterward. The app auto-cancels the provider order and marks the local order cancelled. |
| 500 | Server Error — Unexpected failure. Contact support if persistent. |
| 502 | Bad Gateway — The upstream provider (boost panel or SMSPool) rejected or failed the request. |
shopping_bag Accounts
Browse and purchase social media accounts from the marketplace.
List active accounts, paginated.
science Also at /api/v1/sandbox/accounts — this is a read-only endpoint, sandbox key or live key return identical real data.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| category | Optional | string | Filter by category slug (exact match), e.g. instagram. |
| search | Optional | string | Case-insensitive substring match on account name. |
| per_page | Optional | integer | Items per page. Default 20. Not clamped — very large values are honored as-is. |
Sample request
curl https://vanta.aces-portal.com/api/v1/accounts?category=instagram&per_page=10 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": [
{
"id": 91, "category_id": 3, "source": "local",
"name": "Instagram — 10K followers, verified niche page",
"slug": "ig-10k-verified-niche",
"price": "4500.00", "stock": 4,
"followers": "10.2K", "engagement": "4.2%",
"is_active": true,
"category": { "id": 3, "name": "Instagram", "slug": "instagram" }
}
],
"meta": { "current_page": 1, "last_page": 8, "per_page": 10, "total": 76 }
}
Response fields
| Field | Type | Description |
|---|---|---|
| id | integer | Account ID. |
| category_id | integer|null | FK to categories.id. |
| source | string | local (stock held in our DB) or external (fulfilled via a provider). |
| name / slug / description | string | Display fields. |
| price | string (decimal) | Selling price in NGN, e.g. 4500.00. |
| base_price / markup_value | string (decimal) | Cost basis and markup used to derive price. markup_type is fixed or percentage. |
| stock | integer | Units available. |
| min_quantity / max_quantity | integer|null | Per-order quantity bounds, if set. |
| followers / engagement / avg_likes | string|null | Free-form display text (e.g. 10.2K, 4.2%) — not numeric, do not parse as a number. |
| credentials | — (omitted) | Never included in list or show responses — stripped server-side before serialization. |
| category | object | Full embedded Category object (id, name, slug, icon, sort_order, is_active, products_count not included here). |
| meta | object (top-level) | current_page, last_page, per_page, total — all integers. |
Other responses
{"status":"error","message":"Failed to load accounts."}
List active categories with a live product count.
science Live only — no /sandbox/accounts/categories route exists.
Sample request
curl https://vanta.aces-portal.com/api/v1/accounts/categories \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": [
{ "id": 3, "name": "Instagram", "slug": "instagram", "sort_order": 1, "is_active": true, "products_count": 24 }
]
}
Response fields
| Field | Type | Description |
|---|---|---|
| id / name / slug | integer / string / string | Category identity. |
| sort_order | integer | Display order. |
| is_active | boolean | Always true — inactive categories are excluded. |
| products_count | integer | Count of active accounts in this category. |
Other responses
{"status":"error","message":"Failed to load categories."}
Get a single account. credentials is always stripped.
science Also at /api/v1/sandbox/accounts/{id} — identical, read-only.
Sample request
curl https://vanta.aces-portal.com/api/v1/accounts/91 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": {
"id": 91, "category_id": 3, "source": "local",
"name": "Instagram — 10K followers, verified niche page",
"price": "4500.00", "stock": 4, "is_active": true,
"category": { "id": 3, "name": "Instagram" }
}
}
Other responses
{"status":"error","message":"Account not found."}
{"message":"No query results for model [App\\\\Models\\\\Account] 999"}
{"status":"error","message":"Failed to load account."}
Buy an account immediately ('buy now').
science Also at /api/v1/sandbox/accounts/{id}/purchase, or just call this same path with an ik_test_* key.
Body parameters (JSON)
| Field | Required | Type | Description |
|---|---|---|---|
| quantity | Optional | integer | How many units to buy. min 1, max 100. Defaults to 1. |
Sample request
curl -X POST https://vanta.aces-portal.com/api/v1/accounts/91/purchase \ -H "X-API-Key: ik_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"quantity": 1}'
Success response — 201
{
"status": "success",
"message": "Account purchased successfully.",
"data": {
"id": 4021, "user_id": 12, "type": "account", "total": 4500,
"status": "completed", "external_order_id": null,
"items": [{
"id": 7710, "product_id": 91, "quantity": 1, "price": "4500.00",
"credentials_delivered": { "credentials": "username:password" }
}]
}
}
Success response — sandbox key (201)
Same endpoint — pass an ik_test_* key instead of ik_live_* to get simulated data. No wallet debit, no real stock/provider call.
{
"status": "success", "sandbox": true,
"message": "Sandbox purchase simulated successfully.",
"data": {
"order_id": "sandbox_65123abf9c2e1", "account": "Instagram — 10K followers...",
"quantity": 1, "total": 4500, "status": "completed",
"credentials": { "sandbox": true, "note": "This is a sandbox order — no real credentials delivered." }
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| data (live) | object | The raw Order: id, user_id, type, total (number), status, external_order_id, metadata, created_at, updated_at, items[]. |
| data.status | string | completed on success. If delivery genuinely fails (out of stock / provider error), the API responds 422 instead — see below — you will not see status: failed on a 201. |
| data.items[].credentials_delivered | object | The actual login/credential payload delivered to the buyer. |
Other responses
{"status":"error","message":"Validation failed.","errors":{"quantity":["The quantity must be at least 1."]}}
{"status":"error","message":"Purchase failed. Insufficient balance or account unavailable."}
{"status":"error","message":"Purchase failed. The account could not be delivered \u2014 you were not charged.","data":{"status":"failed","...":"..."}}
{"status":"error","message":"Purchase failed."}
rocket_launch Boost services
Place social media growth orders — followers, likes, views, comments — fulfilled by our upstream growth provider.
List service categories with counts, grouped from the provider's live catalog.
science Live only — no /sandbox/boosts/categories route exists.
Sample request
curl https://vanta.aces-portal.com/api/v1/boosts/categories \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "name": "Instagram", "service_count": 48 } ] }
Response fields
| Field | Type | Description |
|---|---|---|
| name | string | Category name, e.g. Instagram. |
| service_count | integer | Number of services in that category, right now. |
Other responses
{"status":"error","message":"Failed to load categories."}
List purchasable services with NGN/USD pricing.
science Also at /api/v1/sandbox/boosts/services — identical, read-only.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| category | Optional | string | Case-insensitive substring match on the provider category field. |
| search | Optional | string | Case-insensitive substring match on service name. |
| page | Optional | integer | Default 1. |
| per_page | Optional | integer | Default 50, clamped between 10 and 100. |
Sample request
curl https://vanta.aces-portal.com/api/v1/boosts/services?category=instagram \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": [
{ "service": 123, "name": "Instagram Followers - Real", "category": "Instagram",
"rate": "27.0000", "min": "100", "max": "50000",
"price_ngn": 1.35, "price_usd": 0.000818 }
],
"meta": { "current_page": 1, "per_page": 50, "total": 640, "last_page": 13 }
}
Response fields
| Field | Type | Description |
|---|---|---|
| service / name / category / rate / min / max / dripfeed / refill / cancel / type | provider-defined | Passed through verbatim from the upstream provider — exact types (often stringy numbers) are whatever the provider returns, not controlled by this app. |
| price_ngn | number (float) | App-computed: rate marked up per our settings, converted to NGN per unit. |
| price_usd | number (float) | App-computed: same, in USD. |
Other responses
{"status":"error","message":"Failed to load boost services."}
Place a boost order for a specific service and link.
science Also at /api/v1/sandbox/boosts/orders, or call this same path with an ik_test_* key.
Body parameters (JSON)
| Field | Required | Type | Description |
|---|---|---|---|
| service_id | Required | integer | The service field from GET /boosts/services. |
| link | Required | string (URL) | The profile/post URL to grow. Must be a valid URL, max 2048 chars. |
| quantity | Required | integer | Must fall within that service min/max range (see GET /boosts/services). |
Sample request
curl -X POST https://vanta.aces-portal.com/api/v1/boosts/orders \ -H "X-API-Key: ik_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"service_id": 123, "link": "https://instagram.com/yourhandle", "quantity": 500}'
Success response — 201
{
"status": "success",
"message": "Boost order placed successfully.",
"data": {
"order_id": 7, "external_order_id": "98201",
"service_name": "Instagram Followers - Real", "link": "https://instagram.com/yourhandle",
"quantity": 500, "total": 1350.0, "status": "processing"
}
}
Success response — sandbox key (201)
Same endpoint — pass an ik_test_* key instead of ik_live_* to get simulated data. No wallet debit, no real stock/provider call.
{
"status": "success", "sandbox": true,
"message": "Sandbox boost order simulated.",
"data": {
"order_id": "sandbox_boost_65123abf9c2e1", "service_id": 123,
"quantity": 500, "total_ngn": 1350.0, "status": "processing"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| order_id | integer | Local order ID. |
| external_order_id | string | The provider order ID (numeric, but returned as a string). |
| total | number (float) | Amount charged in NGN. |
| status | string | processing immediately after creation. |
Other responses
{"status":"error","message":"Service not found."}
{"status":"error","message":"Quantity must be between 100 and 50000."}
{"status":"error","message":"Insufficient wallet balance.","required":1350,"balance":800}
{"status":"error","message":"Failed to place boost order with provider."}
{"status":"error","message":"Payment failed."}
{"status":"error","message":"Your previous order is still processing. Please wait a moment and try again."}
{"status":"error","message":"Failed to place boost order."}
List your boost orders.
science Live only — no /sandbox/boosts/orders route exists.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| per_page | Optional | integer | Default 15. |
Sample request
curl https://vanta.aces-portal.com/api/v1/boosts/orders \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "id": 7, "type": "boost", "total": 1350.0, "status": "completed" } ], "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 3 } }
Other responses
{"status":"error","message":"Failed to load boost orders."}
Get order status, refreshed live from the provider on every call.
science Live only — no /sandbox/boosts/orders/{id} route exists.
Sample request
curl https://vanta.aces-portal.com/api/v1/boosts/orders/7 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": {
"order_id": 7, "external_order_id": "98201", "quantity": 500,
"start_count": 10230, "remains": 120, "charge": "13.50",
"total": 1350.0, "status": "completed"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| start_count / remains / charge | string|null | Populated once the provider has status data; null until then. |
| status | string | Mapped from the provider: completed → completed, cancelled/refunded → cancelled, anything else → processing. |
Other responses
{"status":"error","message":"Order not found."}
{"status":"error","message":"Failed to get order status."}
sms SMS verification
Rent a virtual phone number and receive OTP codes for any service — WhatsApp, Telegram, Google, and more — via SMSPool.
List available countries.
science Also at /api/v1/sandbox/sms/countries — identical, read-only, cached.
Sample request
curl https://vanta.aces-portal.com/api/v1/sms/countries \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "ID": "1", "name": "United States" } ] }
Other responses
{"status":"error","message":"Failed to load countries."}
List available apps/services (WhatsApp, Telegram, Google, etc.).
science Also at /api/v1/sandbox/sms/services — identical, read-only, cached.
Sample request
curl https://vanta.aces-portal.com/api/v1/sms/services \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "ID": "542", "name": "WhatsApp" } ] }
Other responses
{"status":"error","message":"Failed to load services."}
Get the current NGN/USD price for a country + service combination.
science Also at /api/v1/sandbox/sms/price — identical, read-only.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| country | Required | string | Country name, matched case-insensitively, e.g. United States. |
| service | Required | string | Service name, matched case-insensitively, e.g. WhatsApp. |
| pool | Optional | string | Pin the quote to a specific provider stock pool. |
Sample request
curl "https://vanta.aces-portal.com/api/v1/sms/price?country=United+States&service=WhatsApp" \ -H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": {
"country": "United States", "service": "WhatsApp",
"price_usd": 0.45, "price_ngn": 866.25, "exchange_rate": 1550.0
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| price_usd / price_ngn | number (float) | null | null if the provider has no price for that combination right now (e.g. out of stock). |
| exchange_rate | number (float) | USD → NGN rate used for the conversion. |
Other responses
{"status":"error","message":"Validation failed.","errors":{"country":["The country field is required."]}}
{"status":"error","message":"Country not found: Wakanda"}
{"status":"error","message":"Failed to get price."}
Purchase a virtual number for a country + service combination.
science Also at /api/v1/sandbox/sms/orders, or call this same path with an ik_test_* key.
Body parameters (JSON)
| Field | Required | Type | Description |
|---|---|---|---|
| country | Required | string | Same matching as GET /sms/price. |
| service | Required | string | Same matching as GET /sms/price. |
| pool | Optional | string | Pin to the same pool your price quote used, for price consistency. |
| areacode | Optional | string | US area code targeting, max 10 chars. Passed through to the provider as-is. |
Sample request
curl -X POST https://vanta.aces-portal.com/api/v1/sms/orders \ -H "X-API-Key: ik_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"country": "United States", "service": "WhatsApp"}'
Success response — 201
{
"status": "success",
"message": "SMS number purchased. Waiting for the OTP.",
"data": {
"order_id": 88, "external_id": "SP9911234", "number": "+15551234567",
"country": "United States", "service": "WhatsApp",
"price_ngn": 866.25, "status": "pending",
"expires_at": "2026-08-09T10:20:00.000000Z"
}
}
Success response — sandbox key (201)
Same endpoint — pass an ik_test_* key instead of ik_live_* to get simulated data. No wallet debit, no real stock/provider call.
{
"status": "success", "sandbox": true,
"message": "Sandbox SMS number simulated.",
"data": {
"order_id": "sandbox_sms_65123abf9c2e1", "number": "+15559998877",
"price_ngn": 866.25, "status": "pending",
"note": "This is a sandbox order — no real number was purchased."
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| number | string | The purchased phone number, e.g. +15551234567. |
| price_ngn | number (float) | The actual charged price — recomputed from what the provider really billed, can differ slightly from the price quote. |
| status | string | pending immediately after creation — poll GET /sms/orders/{id}/check for the OTP. |
| expires_at | string (ISO 8601) | When this order auto-expires if no OTP arrives. |
Other responses
{"status":"error","message":"Insufficient wallet balance.","required":866.25,"balance":100}
{"status":"error","message":"Service not found: Discord"}
{"status":"error","message":"No numbers currently available for this country\/service."}
{"status":"error","message":"Payment failed."}
{"status":"error","message":"Your previous order is still processing. Please wait a moment and try again."}
{"status":"error","message":"Failed to purchase SMS number."}
Poll for the OTP. Repeat until status leaves pending.
science Live only — no /sandbox/sms/orders/{id}/check route exists.
Sample request
curl https://vanta.aces-portal.com/api/v1/sms/orders/88/check \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
// OTP received { "status": "success", "message": "OTP received.", "data": { "order_id": 88, "otp_code": "485920", "full_sms": "Your WhatsApp code is 485920", "status": "completed" } } // Still pending { "status": "success", "message": "Still waiting for OTP. Please retry shortly.", "data": { "order_id": 88, "status": "pending", "expires_at": "..." } }
Response fields
| Field | Type | Description |
|---|---|---|
| otp_code / full_sms | string | Only present once status is completed. |
Other responses
{"status":"error","message":"Order not found."}
{"status":"error","message":"Order expired. No OTP was received. Refunded.","data":{"order_id":88,"status":"expired"}}
{"status":"error","message":"Failed to check SMS status."}
Ask the provider to resend the SMS to the same number.
science Live only — no sandbox equivalent.
Sample request
curl -X POST https://vanta.aces-portal.com/api/v1/sms/orders/88/resend \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "message": "SMS resend requested.", "data": { "order_id": 88 } }
Other responses
{"status":"error","message":"Order not found."}
{"status":"error","message":"Only pending orders can be resent."}
{"status":"error","message":"Failed to resend SMS."}
Cancel a pending order.
science Live only — no sandbox equivalent.
Sample request
curl -X DELETE https://vanta.aces-portal.com/api/v1/sms/orders/88 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "message": "Order cancelled.", "data": { "order_id": 88, "status": "cancelled" } }
Other responses
{"status":"error","message":"Order not found."}
{"status":"error","message":"Only pending orders can be cancelled."}
{"status":"error","message":"Failed to cancel order."}
/check above) is refunded automatically.
List your SMS orders.
science Live only — no sandbox equivalent.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| per_page | Optional | integer | Default 15. |
Sample request
curl https://vanta.aces-portal.com/api/v1/sms/orders \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "id": 88, "type": "sms", "status": "completed" } ], "meta": { "current_page": 1, "last_page": 2, "per_page": 15, "total": 19 } }
Other responses
{"status":"error","message":"Failed to load SMS orders."}
receipt_long Orders
View all your orders across every service type in one place, or place an account order without going through the accounts endpoint.
List all your orders, optionally filtered.
science Also at /api/v1/sandbox/orders — identical, read-only.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| type | Optional | string | One of account, boost, sms. Any other value (including email, which exists internally but is not filterable here) is silently ignored — you get unfiltered results. |
| status | Optional | string | One of pending, processing, completed, partial, failed, cancelled, refunded, expired. An unrecognized value just yields an empty result set — it is not validated. |
| per_page | Optional | integer | Default 15. |
Sample request
curl "https://vanta.aces-portal.com/api/v1/orders?type=account&status=completed" \ -H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": [ { "id": 4021, "type": "account", "total": 4500, "status": "completed", "items": [ { "..." : "..." } ] } ], "meta": { "current_page": 1, "last_page": 3, "per_page": 15, "total": 34 } }
Other responses
{"status":"error","message":"Failed to load orders."}
Get a single order (any type) by ID.
science Live only — no /sandbox/orders/{id} route exists.
Sample request
curl https://vanta.aces-portal.com/api/v1/orders/4021 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": { "id": 4021, "type": "account", "total": 4500, "status": "completed", "items": [ { "..." : "..." } ] } }
Other responses
{"status":"error","message":"Order not found."}
{"message":"No query results for model [App\\\\Models\\\\Order] 999"}
{"status":"error","message":"Failed to load order."}
Place an account order directly, by account_id instead of via the URL.
science Also at /api/v1/sandbox/orders, or call this same path with an ik_test_* key.
Body parameters (JSON)
| Field | Required | Type | Description |
|---|---|---|---|
| account_id | Required | integer | Must reference an existing row in accounts — validated with exists:accounts,id before any purchase logic runs. |
| quantity | Optional | integer | min 1, max 100. Defaults to 1. |
Sample request
curl -X POST https://vanta.aces-portal.com/api/v1/orders \ -H "X-API-Key: ik_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"account_id": 91, "quantity": 1}'
Success response — 201
{ "status": "success", "message": "Order placed successfully.", "data": { "id": 4022, "type": "account", "total": 4500, "status": "completed" } }
Success response — sandbox key (201)
Same endpoint — pass an ik_test_* key instead of ik_live_* to get simulated data. No wallet debit, no real stock/provider call.
{ "status": "success", "sandbox": true, "message": "Sandbox order simulated.", "data": { "order_id": "sandbox_65123abf9c2e1", "quantity": 1, "total": 4500, "status": "completed" } }
Other responses
{"status":"error","message":"Validation failed.","errors":{"account_id":["The selected account id is invalid."]}}
{"status":"error","message":"Insufficient balance or account unavailable."}
{"status":"error","message":"Order failed. The account could not be delivered \u2014 you were not charged.","data":{"status":"failed"}}
{"status":"error","message":"Failed to place order."}
account_balance_wallet Wallet
Check your balance and transaction history.
Balance plus paginated transaction history.
science Also at /api/v1/sandbox/wallet — identical, key type has no effect on this read-only endpoint.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| per_page | Optional | integer | Default 20. |
Sample request
curl https://vanta.aces-portal.com/api/v1/wallet?per_page=10 \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": {
"balance": 15000.0, "currency": "NGN",
"transactions": [
{ "id": 501, "type": "debit", "amount": "2500.00", "balance_after": "12500.00", "status": "completed" }
],
"meta": { "current_page": 1, "last_page": 5, "per_page": 10, "total": 47 }
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| balance | number (float) | Current NGN balance. |
| transactions[].amount / balance_after | string (decimal) | e.g. 2500.00 — NOT a JSON number. balance_after can be null on very old rows. |
| transactions[].type | string | credit or debit. |
| transactions[].status | string | pending, completed, or failed. |
| meta | object (nested in data) | Unlike other list endpoints, pagination meta is data.meta, not top-level. |
Other responses
{"status":"error","message":"Failed to load wallet."}
Just the balance — cheaper than /wallet when you don't need history.
science Also at /api/v1/sandbox/wallet/balance — identical.
Sample request
curl https://vanta.aces-portal.com/api/v1/wallet/balance \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{ "status": "success", "data": { "balance": 15000.0, "currency": "NGN" } }
Other responses
{"status":"error","message":"Failed to load balance."}
person Profile
Your account, wallet snapshot, and the API key that authenticated the request.
Get your profile, wallet snapshot, and key metadata.
science Also at /api/v1/sandbox/me — returns the exact same data either way; sandbox is a flag on the response (data.sandbox), not a different dataset.
Sample request
curl https://vanta.aces-portal.com/api/v1/me \
-H "X-API-Key: ik_live_YOUR_KEY"
Success response — 200
{
"status": "success",
"data": {
"id": 12, "name": "Jane Doe", "email": "jane@example.com",
"wallet": { "balance": 15000.0, "currency": "NGN" },
"api_key": { "type": "live", "request_count": 482, "last_used_at": "2026-08-09T10:15:00.000000Z" },
"sandbox": false
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| wallet.balance | number (float) | 0 if you somehow have no wallet row yet. |
| api_key.type | string | sandbox or live, from the key that authenticated this request. |
| api_key.last_used_at | string (ISO 8601) | null | Reflects the value at the start of the request, before this request own usage-tracking update lands. |
| sandbox | boolean | True if the key that authenticated this request is a sandbox key. |
Other responses
{"status":"error","message":"Failed to load profile."}
science Sandbox
Test your integration safely using an ik_test_* key. No real transactions are made, and your wallet is never touched.
Two ways to get sandbox behavior. Either call the dedicated /api/v1/sandbox/* path (which rejects a live key with 403), or simply authenticate with an ik_test_* key on the plain live path for /accounts/{id}/purchase, /orders, /boosts/orders, and /sms/orders — the key type alone decides whether you get simulated or real data on those four.
Endpoints with a dedicated /sandbox/ path
All read-only endpoints below return the same real catalog/wallet data either way — sandbox only changes behavior on the four write endpoints.
| /me | /wallet | /wallet/balance |
| /accounts | /accounts/{id} | /accounts/{id}/purchase (simulated) |
| /orders (list + create) | /boosts/services | /boosts/orders (create only, simulated) |
| /sms/countries | /sms/services | /sms/price |
| /sms/orders (create only, simulated) |
Live-only — no sandbox path exists
Mostly read endpoints scoped to already-created real orders, which can't be meaningfully simulated.
| /accounts/categories | /orders/{id} | /boosts/categories |
| /boosts/orders (list + status) | /sms/orders (list) | /sms/orders/{id}/check, /resend, DELETE |
Sample sandbox request
# Test SMS purchase (no real cost) curl -X POST https://vanta.aces-portal.com/api/v1/sandbox/sms/orders \ -H "X-API-Key: ik_test_YOUR_SANDBOX_KEY" \ -H "Content-Type: application/json" \ -d '{"country": "United States", "service": "WhatsApp"}' // Returns mock data instead of real number { "sandbox": true, "number": "+15557859130", "otp_code": null }
Ready to integrate?
Get your API keys from your developer dashboard and start building.
person_add Create an account