curl --request POST \
--url https://api.sandbox.brickken.com/prepare-transactions \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"method": "approve",
"chainId": "aa36a7",
"signerAddress": "0x1111111111111111111111111111111111111111",
"tokenSymbol": "USDT",
"spenderAddress": "0x2222222222222222222222222222222222222222",
"amount": "100",
"tokenizerAddress": "0x1111111111111111111111111111111111111111"
}
'import requests
url = "https://api.sandbox.brickken.com/prepare-transactions"
payload = {
"method": "approve",
"chainId": "aa36a7",
"signerAddress": "0x1111111111111111111111111111111111111111",
"tokenSymbol": "USDT",
"spenderAddress": "0x2222222222222222222222222222222222222222",
"amount": "100",
"tokenizerAddress": "0x1111111111111111111111111111111111111111"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
method: 'approve',
chainId: 'aa36a7',
signerAddress: '0x1111111111111111111111111111111111111111',
tokenSymbol: 'USDT',
spenderAddress: '0x2222222222222222222222222222222222222222',
amount: '100',
tokenizerAddress: '0x1111111111111111111111111111111111111111'
})
};
fetch('https://api.sandbox.brickken.com/prepare-transactions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.brickken.com/prepare-transactions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'method' => 'approve',
'chainId' => 'aa36a7',
'signerAddress' => '0x1111111111111111111111111111111111111111',
'tokenSymbol' => 'USDT',
'spenderAddress' => '0x2222222222222222222222222222222222222222',
'amount' => '100',
'tokenizerAddress' => '0x1111111111111111111111111111111111111111'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.brickken.com/prepare-transactions"
payload := strings.NewReader("{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.brickken.com/prepare-transactions")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.brickken.com/prepare-transactions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}"
response = http.request(request)
puts response.read_body{
"transactions": [
{
"from": "0x1234567890abcdef1234567890abcdef12345678",
"to": "0xabcdef1234567890abcdef1234567890abcdef12",
"value": "0x00",
"nonce": 3792,
"chainId": 11155111,
"data": "0xd362e8a70000000000000000000000000000000000000000000000000000000000000040...",
"type": 2,
"maxPriorityFeePerGas": "1150000",
"maxFeePerGas": "1156037",
"gasLimit": "0xccef"
}
],
"txId": "0x46adea7bdf49c576a760102e0d6bc9ecd650b3998588cd3d7f576a7973426aad",
"info": {
"tokenizerEmail": "tokenizer@example.com",
"tokenSymbol": "EXMPL",
"investorEmail": "investor@example.com"
}
}approve
Grant an ERC-20 allowance before an investment or a dividend distribution.
curl --request POST \
--url https://api.sandbox.brickken.com/prepare-transactions \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"method": "approve",
"chainId": "aa36a7",
"signerAddress": "0x1111111111111111111111111111111111111111",
"tokenSymbol": "USDT",
"spenderAddress": "0x2222222222222222222222222222222222222222",
"amount": "100",
"tokenizerAddress": "0x1111111111111111111111111111111111111111"
}
'import requests
url = "https://api.sandbox.brickken.com/prepare-transactions"
payload = {
"method": "approve",
"chainId": "aa36a7",
"signerAddress": "0x1111111111111111111111111111111111111111",
"tokenSymbol": "USDT",
"spenderAddress": "0x2222222222222222222222222222222222222222",
"amount": "100",
"tokenizerAddress": "0x1111111111111111111111111111111111111111"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
method: 'approve',
chainId: 'aa36a7',
signerAddress: '0x1111111111111111111111111111111111111111',
tokenSymbol: 'USDT',
spenderAddress: '0x2222222222222222222222222222222222222222',
amount: '100',
tokenizerAddress: '0x1111111111111111111111111111111111111111'
})
};
fetch('https://api.sandbox.brickken.com/prepare-transactions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.brickken.com/prepare-transactions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'method' => 'approve',
'chainId' => 'aa36a7',
'signerAddress' => '0x1111111111111111111111111111111111111111',
'tokenSymbol' => 'USDT',
'spenderAddress' => '0x2222222222222222222222222222222222222222',
'amount' => '100',
'tokenizerAddress' => '0x1111111111111111111111111111111111111111'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.brickken.com/prepare-transactions"
payload := strings.NewReader("{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.brickken.com/prepare-transactions")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.brickken.com/prepare-transactions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"method\": \"approve\",\n \"chainId\": \"aa36a7\",\n \"signerAddress\": \"0x1111111111111111111111111111111111111111\",\n \"tokenSymbol\": \"USDT\",\n \"spenderAddress\": \"0x2222222222222222222222222222222222222222\",\n \"amount\": \"100\",\n \"tokenizerAddress\": \"0x1111111111111111111111111111111111111111\"\n}"
response = http.request(request)
puts response.read_body{
"transactions": [
{
"from": "0x1234567890abcdef1234567890abcdef12345678",
"to": "0xabcdef1234567890abcdef1234567890abcdef12",
"value": "0x00",
"nonce": 3792,
"chainId": 11155111,
"data": "0xd362e8a70000000000000000000000000000000000000000000000000000000000000040...",
"type": 2,
"maxPriorityFeePerGas": "1150000",
"maxFeePerGas": "1156037",
"gasLimit": "0xccef"
}
],
"txId": "0x46adea7bdf49c576a760102e0d6bc9ecd650b3998588cd3d7f576a7973426aad",
"info": {
"tokenizerEmail": "tokenizer@example.com",
"tokenSymbol": "EXMPL",
"investorEmail": "investor@example.com"
}
}POST /prepare-transactions with method=approve.
Fields
tokenSymbolselects the token being approved, not the asset it relates to.spenderAddressis the address allowed to spend it. It is never derived — you must pass it.tokenizerAddressis additionally required whentokenSymbolis a shared payment token (USDT,USDC,BKN,HAI). UsecompanyWalletAddressfromGET /get-tokenizer-info.amountis in whole tokens. Send"100"for 100 USDT; the API applies the token’s decimals for you. Do not pre-multiply.
spenderAddress is validated as an EVM address, and a malformed value is rejected with a
validation error naming that field. Two things trip it most often: an invalid EIP-55 checksum, and
leading or trailing whitespace picked up from a copied value or an environment variable. Trim the
value, or send the address in all lowercase, which always passes the checksum rule.Sending the field as spender instead of spenderAddress returns
Missing spender address parameter.Choosing the spender
Allowances are per spender. An allowance granted to one contract gives nothing to another, so an investor who has invested in one offering still has to approve the next offering’s escrow separately.| Purpose | tokenSymbol | spenderAddress |
|---|---|---|
| Investing in an offering | the offering’s payment token | escrowAddress |
| Distributing dividends | the asset’s payment token | tokenAddress (the STO token contract) |
curl --request GET \
--url 'https://api.sandbox.brickken.com/get-tokenizer-info?tokenSymbol=EXMPL' \
--header 'x-api-key: YOUR_API_KEY'
Approving payment tokens for dividend distributions
Before callingdividendDistribution, approve the tokenized asset’s configured payment token and set spenderAddress to the STO token contract address.
Use the response fields as follows:
tokenAddress→spenderAddressin theapproverequestpaymentTokenAddress→ the ERC-20 contract being approved; use its configured symbol, such asUSDT, astokenSymbolcompanyWalletAddress→tokenizerAddresswhen approving a shared payment tokenescrowAddress→ do not use this as the spender fordividendDistribution
escrowAddress does not satisfy the dividend allowance check. The allowance must be from signerAddress to the STO tokenAddress.get-tokenizer-info returns the STO address 0x2222222222222222222222222222222222222222 and the configured payment token is USDT:
{
"method": "approve",
"signerAddress": "0x1111111111111111111111111111111111111111",
"chainId": "aa36a7",
"tokenSymbol": "USDT",
"spenderAddress": "0x2222222222222222222222222222222222222222",
"amount": "100",
"tokenizerAddress": "0x1111111111111111111111111111111111111111"
}
dividendDistribution.
Replacing an existing allowance
Some payment tokens refuse to change a non-zero allowance directly. When the signer already has a non-zero allowance for that spender, the response therefore contains two transactions — a reset to0 followed by the new amount — and txId is an array rather than a single value.
{
"transactions": [ { "…reset to 0…" }, { "…new amount…" } ],
"txId": ["0xaaa…", "0xbbb…"]
}
"data": "0x").If it does: check the current allowance with GET /get-allowance. If it already covers the amount
you need, skip the approval entirely. Otherwise prepare and send amount: "0" on its own first,
wait for it to confirm, then prepare the new amount.Next step
Preparing does not touch the chain. The response gives youtxId and an array of unsigned transactions — you still have to sign and submit them.
Sign every returned transaction
signerAddress, or investorAddress for newInvest and claimTokens. It must be whitelisted by Brickken, and it needs native gas on the target chain.Submit the signed payloads
POST them to /send-transactions as { txId, signedTransactions } and Brickken broadcasts for you.If you would rather broadcast yourself, prepare with executionMode: "client-broadcast" and confirm afterwards with { txId, txHash } instead.Poll until it confirms
GET /get-transaction-status with the txId. A pending status means it is broadcast but not yet mined — do not resubmit.Authorizations
Body
Required. Operation to prepare. Must be approve for this endpoint.
approve "approve"
Required. Blockchain network identifier. Hex format is recommended, for example Sepolia aa36a7.
"aa36a7"
Required. Wallet that signs the approval.
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
Required. Symbol of the token to approve. Accepts a tokenized asset symbol or a payment token symbol such as USDT, USDC, BKN or HAI.
"EXMPL"
Required. Address allowed to spend the approved amount. Allowances are per spender, so each offering's escrow must be approved separately. For an investment, use that offering's escrowAddress. For a payment-token approval before dividendDistribution, use the STO tokenAddress returned by GET /get-tokenizer-info; never use escrowAddress for that allowance. A malformed value is rejected with a validation error naming this field; whitespace and a bad EIP-55 checksum are the usual causes.
^0x[a-fA-F0-9]{40}$"0x2222222222222222222222222222222222222222"
Required. Amount the spender is allowed to spend, in whole tokens. The API applies the token's decimals, so send 100 for 100 USDT rather than the raw six-decimal value.
"100"
Optional. Token owner address when approving on behalf of an investor. If omitted, signerAddress is used as the owner.
^0x[a-fA-F0-9]{40}$"0x1111111111111111111111111111111111111111"
Optional. Tokenizer email used as a fallback when the tokenizer cannot be resolved from the token.
"tokenizer@example.com"
Optional. Required when tokenSymbol is a payment token (HAI, BKN, USDC, USDT). Tokenizer wallet the approval is scoped to; use companyWalletAddress from GET /get-tokenizer-info for the related tokenized asset.
^0x[a-fA-F0-9]{40}$"0x1111111111111111111111111111111111111111"
Response
Successful response
Array of unsigned transaction objects ready for signing
Show child attributes
Show child attributes
Unique identifier for this transaction batch (required for /send-transactions). This is NOT a blockchain transaction hash.
"0x46adea7bdf49c576a760102e0d6bc9ecd650b3998588cd3d7f576a7973426aad"
Metadata about the operation
Show child attributes
Show child attributes