BrainArk
Enterprise API Reference
Developer Dashboard v1.0 — Live OpenAPI Postman
BASErwa.brainark.online
Overview

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.

~3 s
Asset issuance on-chain
0.1 BAK
Minimum stake per asset
50
Max assets per batch
7
Write endpoints

Getting Started

Quick Start

From zero to your first on-chain asset in three steps.

1
Request an API key

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.

2
Fund your custodial wallet

Check your wallet’s BAK balance. Each asset tokenization stakes a minimum of 0.1 BAK on-chain.

bash
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.

3
Issue your first asset

Send a single POST request. The API mints an NFT on chain 1236 and returns the token ID.

bash
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..."
}

Getting Started

Authentication

All API requests are authenticated via a header key. There are two credential types depending on what you’re doing.

Credential Types
HeaderUsed ForFormat
X-API-KeyAll write and management endpointsrwa_live_<64 hex chars>
X-Admin-TokenOnboarding new organizations (BrainArk staff only)ent_admin_<64 hex chars>
bash — all requests
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.


Getting Started

Scopes

Each API key carries a set of scopes. Calling an endpoint without the required scope returns a 403 Forbidden.

ScopeGrants Access To
readWallet 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
webhooksRegister and manage webhook endpoints
admin:types/register-asset-type — extend the type registry
write:allAlias for all write scopes combined

Write API

Endpoints

All write routes are under /api/v1/write/ and accept application/json bodies. Transactions are signed by your custodial wallet server-side.

POST /api/v1/write/issue-asset

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

Request Body
FieldTypeRequiredDescription
assetTypestringRequiredRegistered asset type. See Asset Types for valid values.
namestringRequiredHuman-readable name for the asset.
descriptionstringRequiredShort description stored in the NFT metadata.
imagestringOptionalURL to asset image (HTTPS or IPFS URL).
externalUrlstringOptionalCanonical URL for this asset on your platform.
ipfsHashstringOptionalIPFS CID for the full metadata document.
stakedAmountstring (BAK)OptionalBAK to stake. Default: "0.1". Minimum: "0.1".
passwordstringOptionalOwner password (plaintext). Stored as keccak256(password) on-chain.
Request
json
{
  "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"
}
Response 200
json
{
  "success": true,
  "tokenId": "73",
  "txHash": "0xa887...",
  "wallet": "0x0913..."
}
POST /api/v1/write/batch-issue

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

Request Body
FieldTypeRequiredDescription
assetsAsset[]RequiredArray of 1–50 asset objects. Each follows the same schema as issue-asset.
Request
json
{
  "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"
    }
  ]
}
Response 200
json
{
  "issued": 2,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "success": true,
      "tokenId": "74",
      "txHash": "0xb2cc..."
    },
    {
      "index": 1,
      "success": true,
      "tokenId": "75",
      "txHash": "0xc4dd..."
    }
  ]
}
POST /api/v1/write/transfer

Transfer an NFT from your custodial wallet to any address on chain 1236. Requires scope write:transfer

Request Body
FieldTypeRequiredDescription
tokenIdstring | numberRequiredToken ID to transfer.
toAddressstring (0x…)RequiredRecipient wallet address.
Request
json
{
  "tokenId": "73",
  "toAddress": "0xRecipient..."
}
Response 200
json
{
  "success": true,
  "txHash": "0xd91f...",
  "from": "0x0913...",
  "to": "0xRecip...",
  "tokenId": "73"
}
POST /api/v1/write/marketplace/list

List an asset for sale on the BrainArk marketplace. Automatically approves the marketplace contract and creates the listing. Requires scope write:marketplace

Request Body
FieldTypeRequiredDescription
tokenIdstring | numberRequiredToken ID to list.
priceInBAKstring (BAK)RequiredListing price in BAK, e.g. "1.5".
durationDaysnumberOptionalListing duration in days. Default: 30.
Request
json
{
  "tokenId": "73",
  "priceInBAK": "2.5",
  "durationDays": 30
}
Response 200
json
{
  "success": true,
  "listingId": "42",
  "txHash": "0xe3a1...",
  "tokenId": "73",
  "priceInBAK": "2.5"
}
POST /api/v1/write/marketplace/buy

Purchase an active marketplace listing using the buyer’s custodial wallet. Requires scope write:marketplace

Request Body
FieldTypeRequiredDescription
listingIdstring | numberRequiredID of the active listing to purchase.
maxPriceInBAKstring (BAK)OptionalSlippage guard. Transaction reverts if current price exceeds this value.
Request
json
{
  "listingId": "42",
  "maxPriceInBAK": "2.5"
}
Response 200
json
{
  "success": true,
  "txHash": "0x9f22...",
  "listingId": "42",
  "tokenId": "73",
  "pricePaid": "2.5",
  "buyer": "0xBuyer..."
}
POST /api/v1/write/marketplace/delist

Cancel an active listing. The asset returns to the seller’s custodial wallet. Requires scope write:marketplace

Request Body
FieldTypeRequiredDescription
listingIdstring | numberRequiredID of the listing to cancel.
Request
json
{ "listingId": "42" }
Response 200
json
{
  "success": true,
  "txHash": "0x60b8...",
  "listingId": "42"
}
POST /api/v1/write/register-asset-type

Register a new asset type on the AR_V3 registry. Once registered, any org can tokenize assets of this type. Requires scope admin:types

Request Body
FieldTypeRequiredDescription
typeNamestringRequiredType name to register (e.g. "Agricultural Land").
Request
json
{ "typeName": "Agricultural Land" }
Response 200
json
{
  "success": true,
  "typeName": "Agricultural Land",
  "txHash": "0x7a3c..."
}

Management

Organization Management

Endpoints for managing organizations, wallets, API keys, and webhook registrations.

POST /api/enterprise/register

Onboard a new enterprise organization. Requires the admin token. Returns a one-time API key and custodial wallet to fund.

Request Body
FieldTypeRequiredDescription
orgNamestringRequiredDisplay name for the organization.
walletMode"custodial"OptionalCurrently only "custodial" is supported.
scopesstring[]OptionalScopes to grant. Default: ["read","write:issue","write:transfer","write:marketplace","webhooks"]
bash
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.

GET /api/enterprise/wallet

Check your custodial wallet’s live BAK balance. Requires scope read

Request
bash
curl https://rwa.brainark.online/api/enterprise/wallet \
  -H 'X-API-Key: rwa_live_YOUR_KEY'
Response 200
json
{
  "walletAddress": "0x0913...",
  "balance": "9.4",
  "balanceWei": "9400000000000000000",
  "chain": 1236
}
GET /api/enterprise/keys

List, create, and revoke API keys for your organization. Requires scope read

GET — List keys
bash
curl https://rwa.brainark.online/api/enterprise/keys \
  -H 'X-API-Key: rwa_live_YOUR_KEY'
POST — Create additional key
bash
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" }'
DELETE — Revoke a key
bash
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" }'
GET /api/enterprise/webhooks

Manage webhook endpoints for your organization. Requires scope webhooks

GET — List webhooks
bash
curl https://rwa.brainark.online/api/enterprise/webhooks \
  -H 'X-API-Key: rwa_live_YOUR_KEY'
POST — Register a webhook
bash
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"
  }'
DELETE — Remove webhook
bash
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" }'

Guide

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 Types
asset.issuedNew NFT minted via issueAsset. Includes tokenId, assetType, name, wallet.
asset.transferredNFT moved between wallets (includes secondary market transfers).
asset.listedAsset listed on the marketplace. Includes listingId, tokenId, price.
asset.soldMarketplace sale completed. Includes buyer, seller, tokenId, price.
asset.delistedListing cancelled by the seller.
Event Payload Shape
json
{
  "event": "asset.issued",
  "timestamp": 1721203200000,
  "orgId": "org_ef64296f...",
  "txHash": "0xa887c3d1...",
  "blockNumber": 12741900,
  "data": {
    "tokenId": "73",
    "from": "0x0000000000000000000000000000000000000000",
    "to": "0x0913915e4e0ad31c27CcC0dF108f0bF9C70781eE"
  }
}
Verifying the Signature (Node.js)
node.js — Express
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
});
Verifying the Signature (Python)
python — Flask
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)

Guide

JavaScript SDK

A lightweight UMD bundle that wraps the REST API. Works in Node.js and the browser. No dependencies.

Load
html
<script src="https://rwa.brainark.online/sdk/brainark.js"></script>
node.js
const BrainArk = require('./brainark.js');
Usage
javascript
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' });

Reference

Registered Asset Types

Pass the exact string (case-sensitive) in the assetType field. New types can be registered via /register-asset-type.

Real Estate Bond Insurance Policy Carbon Credit Stock / Equity Treasury RECEIPT Retail Product Event Ticket Membership Card Gift Voucher Other

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.


Reference

Error Codes

All errors return a JSON body with an error string. The HTTP status code indicates the category.

HTTPerror stringCause
400Missing required field: nameRequest body is missing a required parameter.
400stakedAmount minimum is 0.1 BAKstakedAmount below AR_V3’s on-chain minimum.
400assets must be a non-empty arraybatch-issue called with empty or missing assets array.
400Listing not activeAttempted to buy an expired or already-sold listing.
401UnauthorizedMissing or invalid X-API-Key header.
403Insufficient scopeAPI key lacks the required scope for this endpoint.
403Admin token requiredEndpoint requires X-Admin-Token, not X-API-Key.
500Transaction failed: Below min stakeOn-chain revert. The reason string follows the colon.
503RPC unavailableBrainArk node temporarily unreachable. Retry with backoff.

Guide

Best Practices

Keep your custodial wallet funded

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.

Idempotency and retries

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.

Password security

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.

Webhook reliability

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.

Rate limits

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.

Never expose your API key client-side

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.