BrainArk Enterprise API
Tokenize real-world assets on BrainArk’s private EVM chain (ID 1236) without running your own node. Authenticate with an API key, fund your custodial wallet with BAK, and start issuing NFT-backed assets in minutes. The API is custodial — BrainArk signs all transactions server-side on your behalf.
Quick Start
From zero to your first on-chain asset in three steps.
Contact BrainArk to register your organization. You’ll receive an API key and a custodial wallet address.
Each organization gets a dedicated custodial wallet on chain 1236. BrainArk holds the private key server-side and signs all transactions. You never manage keys.
Check your wallet’s BAK balance. Each asset tokenization stakes a minimum of 0.1 BAK on-chain.
curl https://rwa.brainark.online/api/enterprise/wallet \ -H 'X-API-Key: rwa_live_YOUR_KEY' # Response { "walletAddress": "0xYourCustodialWallet", "balance": "10.0", "balanceWei": "10000000000000000000", "chain": 1236 }
Send BAK to your wallet address from any BrainArk wallet. 10 BAK supports ~100 asset issuances.
Send a single POST request. The API mints an NFT on chain 1236 and returns the token ID.
curl -X POST https://rwa.brainark.online/api/v1/write/issue-asset \ -H 'Content-Type: application/json' \ -H 'X-API-Key: rwa_live_YOUR_KEY' \ -d '{ "assetType": "Real Estate", "name": "123 Main Street", "description": "3BR/2BA single family residence", "image": "https://cdn.yourapp.com/property.jpg", "externalUrl": "https://yourapp.com/assets/123", "stakedAmount": "0.1", "password": "my-secret-phrase" }' # Response { "success": true, "tokenId": "73", "txHash": "0xa887c3d1...", "wallet": "0x0913915e..." }
Authentication
All API requests are authenticated via a header key. There are two credential types depending on what you’re doing.
| Header | Used For | Format |
|---|---|---|
| X-API-Key | All write and management endpoints | rwa_live_<64 hex chars> |
| X-Admin-Token | Onboarding new organizations (BrainArk staff only) | ent_admin_<64 hex chars> |
curl https://rwa.brainark.online/api/v1/write/... \ -H 'X-API-Key: rwa_live_1adda180d5dab754...' \ -H 'Content-Type: application/json'
API keys are tied to a custodial wallet. Never expose them in client-side code. Always call the API from your server. Treat them like private keys.
Scopes
Each API key carries a set of scopes. Calling an endpoint without the required scope returns a 403 Forbidden.
| Scope | Grants Access To |
|---|---|
| read | Wallet balance, key list, webhook list |
| write:issue | /issue-asset and /batch-issue |
| write:transfer | /transfer — move NFTs between wallets |
| write:marketplace | /marketplace/list, /marketplace/buy, /marketplace/delist |
| webhooks | Register and manage webhook endpoints |
| admin:types | /register-asset-type — extend the type registry |
| write:all | Alias for all write scopes combined |
Endpoints
All write routes are under /api/v1/write/ and accept application/json bodies. Transactions are signed by your custodial wallet server-side.
Tokenize a single real-world asset. Mints one ERC-721 NFT on AR_V3 and stakes the specified BAK amount on-chain. Requires scope write:issue
| Field | Type | Required | Description |
|---|---|---|---|
| assetType | string | Required | Registered asset type. See Asset Types for valid values. |
| name | string | Required | Human-readable name for the asset. |
| description | string | Required | Short description stored in the NFT metadata. |
| image | string | Optional | URL to asset image (HTTPS or IPFS URL). |
| externalUrl | string | Optional | Canonical URL for this asset on your platform. |
| ipfsHash | string | Optional | IPFS CID for the full metadata document. |
| stakedAmount | string (BAK) | Optional | BAK to stake. Default: "0.1". Minimum: "0.1". |
| password | string | Optional | Owner password (plaintext). Stored as keccak256(password) on-chain. |
{
"assetType": "Real Estate",
"name": "123 Main St",
"description": "3BR/2BA home",
"image": "https://cdn.co/img.jpg",
"externalUrl": "https://app.co/asset/1",
"stakedAmount": "0.5",
"password": "hunter2"
}
{
"success": true,
"tokenId": "73",
"txHash": "0xa887...",
"wallet": "0x0913..."
}
Tokenize up to 50 assets in a single request. Assets are issued sequentially. Check each item’s success flag for partial failures. Requires scope write:issue
| Field | Type | Required | Description |
|---|---|---|---|
| assets | Asset[] | Required | Array of 1–50 asset objects. Each follows the same schema as issue-asset. |
{
"assets": [
{
"assetType": "Real Estate",
"name": "Unit A",
"description": "Studio apt",
"stakedAmount": "0.1"
},
{
"assetType": "Bond",
"name": "Corp Bond 2030",
"description": "5Y fixed rate",
"stakedAmount": "1.0"
}
]
}
{
"issued": 2,
"failed": 0,
"results": [
{
"index": 0,
"success": true,
"tokenId": "74",
"txHash": "0xb2cc..."
},
{
"index": 1,
"success": true,
"tokenId": "75",
"txHash": "0xc4dd..."
}
]
}
Transfer an NFT from your custodial wallet to any address on chain 1236. Requires scope write:transfer
| Field | Type | Required | Description |
|---|---|---|---|
| tokenId | string | number | Required | Token ID to transfer. |
| toAddress | string (0x…) | Required | Recipient wallet address. |
{
"tokenId": "73",
"toAddress": "0xRecipient..."
}
{
"success": true,
"txHash": "0xd91f...",
"from": "0x0913...",
"to": "0xRecip...",
"tokenId": "73"
}
List an asset for sale on the BrainArk marketplace. Automatically approves the marketplace contract and creates the listing. Requires scope write:marketplace
| Field | Type | Required | Description |
|---|---|---|---|
| tokenId | string | number | Required | Token ID to list. |
| priceInBAK | string (BAK) | Required | Listing price in BAK, e.g. "1.5". |
| durationDays | number | Optional | Listing duration in days. Default: 30. |
{
"tokenId": "73",
"priceInBAK": "2.5",
"durationDays": 30
}
{
"success": true,
"listingId": "42",
"txHash": "0xe3a1...",
"tokenId": "73",
"priceInBAK": "2.5"
}
Purchase an active marketplace listing using the buyer’s custodial wallet. Requires scope write:marketplace
| Field | Type | Required | Description |
|---|---|---|---|
| listingId | string | number | Required | ID of the active listing to purchase. |
| maxPriceInBAK | string (BAK) | Optional | Slippage guard. Transaction reverts if current price exceeds this value. |
{
"listingId": "42",
"maxPriceInBAK": "2.5"
}
{
"success": true,
"txHash": "0x9f22...",
"listingId": "42",
"tokenId": "73",
"pricePaid": "2.5",
"buyer": "0xBuyer..."
}
Cancel an active listing. The asset returns to the seller’s custodial wallet. Requires scope write:marketplace
| Field | Type | Required | Description |
|---|---|---|---|
| listingId | string | number | Required | ID of the listing to cancel. |
{ "listingId": "42" }
{
"success": true,
"txHash": "0x60b8...",
"listingId": "42"
}
Register a new asset type on the AR_V3 registry. Once registered, any org can tokenize assets of this type. Requires scope admin:types
| Field | Type | Required | Description |
|---|---|---|---|
| typeName | string | Required | Type name to register (e.g. "Agricultural Land"). |
{ "typeName": "Agricultural Land" }
{
"success": true,
"typeName": "Agricultural Land",
"txHash": "0x7a3c..."
}
Organization Management
Endpoints for managing organizations, wallets, API keys, and webhook registrations.
Onboard a new enterprise organization. Requires the admin token. Returns a one-time API key and custodial wallet to fund.
| Field | Type | Required | Description |
|---|---|---|---|
| orgName | string | Required | Display name for the organization. |
| walletMode | "custodial" | Optional | Currently only "custodial" is supported. |
| scopes | string[] | Optional | Scopes to grant. Default: ["read","write:issue","write:transfer","write:marketplace","webhooks"] |
curl -X POST https://rwa.brainark.online/api/enterprise/register \ -H 'Content-Type: application/json' \ -H 'X-Admin-Token: ent_admin_0d19a7e678...' \ -d '{ "orgName": "Acme Corp", "scopes": ["read", "write:issue", "write:marketplace", "webhooks"] }' # Response — save the apiKey immediately, shown only once { "orgId": "org_a1b2c3d4...", "apiKey": "rwa_live_...", "walletAddress": "0xNewWallet...", "scopes": ["read", "write:issue", ...] }
The API key is shown only once at registration. Store it in a secrets manager immediately. Fund the custodial wallet with BAK before making write calls.
Check your custodial wallet’s live BAK balance. Requires scope read
curl https://rwa.brainark.online/api/enterprise/wallet \
-H 'X-API-Key: rwa_live_YOUR_KEY'
{
"walletAddress": "0x0913...",
"balance": "9.4",
"balanceWei": "9400000000000000000",
"chain": 1236
}
List, create, and revoke API keys for your organization. Requires scope read
curl https://rwa.brainark.online/api/enterprise/keys \
-H 'X-API-Key: rwa_live_YOUR_KEY'
curl -X POST https://rwa.brainark.online/api/enterprise/keys \ -H 'X-API-Key: rwa_live_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{ "scopes": ["read", "write:issue"], "label": "CI key" }'
curl -X DELETE https://rwa.brainark.online/api/enterprise/keys \ -H 'X-API-Key: rwa_live_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{ "keyId": "key_abc" }'
Manage webhook endpoints for your organization. Requires scope webhooks
curl https://rwa.brainark.online/api/enterprise/webhooks \
-H 'X-API-Key: rwa_live_YOUR_KEY'
curl -X POST https://rwa.brainark.online/api/enterprise/webhooks \ -H 'X-API-Key: rwa_live_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://yourapp.com/hooks/brainark", "events": ["asset.issued", "asset.sold", "asset.transferred"], "secret": "your-32-char-webhook-secret" }'
curl -X DELETE https://rwa.brainark.online/api/enterprise/webhooks \ -H 'X-API-Key: rwa_live_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{ "webhookId": "wh_xyz" }'
Webhook Integration
BrainArk pushes signed events to your HTTPS endpoints whenever assets are issued, sold, transferred, or listed. The indexer polls the chain every 3 seconds.
{
"event": "asset.issued",
"timestamp": 1721203200000,
"orgId": "org_ef64296f...",
"txHash": "0xa887c3d1...",
"blockNumber": 12741900,
"data": {
"tokenId": "73",
"from": "0x0000000000000000000000000000000000000000",
"to": "0x0913915e4e0ad31c27CcC0dF108f0bF9C70781eE"
}
}
const crypto = require('crypto'); function verifyBrainArkSignature(rawBody, signature, secret) { const expected = 'sha256=' + crypto.createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); } app.post('/webhook/brainark', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-brainark-signature']; if (!sig || !verifyBrainArkSignature(req.body, sig, process.env.WEBHOOK_SECRET)) { return res.status(401).json({ error: 'Invalid signature' }); } const event = JSON.parse(req.body); // process event.event, event.data ... res.json({ received: true }); // respond 2xx within 5s });
import hmac, hashlib, json, os from flask import Flask, request, jsonify WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET'] @app.route('/webhook/brainark', methods=['POST']) def webhook(): sig = request.headers.get('X-BrainArk-Signature', '') body = request.get_data() expected = 'sha256=' + hmac.new( WEBHOOK_SECRET.encode(), body, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(sig, expected): return jsonify(error='Invalid signature'), 401 event = json.loads(body) return jsonify(received=True)
JavaScript SDK
A lightweight UMD bundle that wraps the REST API. Works in Node.js and the browser. No dependencies.
<script src="https://rwa.brainark.online/sdk/brainark.js"></script>
const BrainArk = require('./brainark.js');
const client = new BrainArk({ apiKey: process.env.BRAINARK_API_KEY }); // Issue a single asset const { tokenId, txHash } = await client.issueAsset({ assetType: 'Real Estate', name: '123 Main St', description: '3BR property', stakedAmount: '0.5' }); // Batch issue const batch = await client.batchIssue({ assets: [ { assetType: 'Bond', name: 'Corp Bond A', description: '5Y fixed' }, { assetType: 'Bond', name: 'Corp Bond B', description: '3Y float' } ] }); // List on marketplace await client.listAsset({ tokenId, priceInBAK: '2.5' });
Registered Asset Types
Pass the exact string (case-sensitive) in the assetType field. New types can be registered via /register-asset-type.
Using an unregistered type string causes the transaction to revert on-chain. If your use case doesn’t fit an existing type, register a custom type first.
Error Codes
All errors return a JSON body with an error string. The HTTP status code indicates the category.
| HTTP | error string | Cause |
|---|---|---|
| 400 | Missing required field: name | Request body is missing a required parameter. |
| 400 | stakedAmount minimum is 0.1 BAK | stakedAmount below AR_V3’s on-chain minimum. |
| 400 | assets must be a non-empty array | batch-issue called with empty or missing assets array. |
| 400 | Listing not active | Attempted to buy an expired or already-sold listing. |
| 401 | Unauthorized | Missing or invalid X-API-Key header. |
| 403 | Insufficient scope | API key lacks the required scope for this endpoint. |
| 403 | Admin token required | Endpoint requires X-Admin-Token, not X-API-Key. |
| 500 | Transaction failed: Below min stake | On-chain revert. The reason string follows the colon. |
| 503 | RPC unavailable | BrainArk node temporarily unreachable. Retry with backoff. |
Best Practices
Each issueAsset call stakes at minimum 0.1 BAK plus ~0.001 BAK in gas. Budget at least 0.15 BAK per asset. Batch operations are more efficient — prefer batch-issue over looping single calls. Monitor your balance via GET /api/enterprise/wallet.
Before retrying a failed write, check whether the transaction landed on-chain using the tx hash from the error context — the RPC may have timed out after the transaction was already broadcast. Query eth_getTransactionReceipt on https://rpc.brainark.online before resubmitting.
The password field is hashed on-chain as keccak256(password). Store the plaintext in your database against the token ID. It is required if the asset owner ever wants to stake, unstake, or transfer via BrainArk’s DApp.
Respond to webhook deliveries within 5 seconds with a 2xx status. If your handler is slow, enqueue the raw payload and acknowledge immediately. Use the txHash field to deduplicate events if your endpoint receives the same delivery twice.
Current limits: 60 requests/minute per API key, 10 concurrent write transactions per org. Batch operations count as one request. A Retry-After header is set on 429 responses.
Your API key controls a funded on-chain wallet. Always call the BrainArk API from your server. Use your own backend as a proxy if you need to trigger blockchain actions from a web frontend.