Overview
Every end-user who trades gold through your platform needs a user account on the Oro TradeBook. Creating a user involves:
- Generate a KYC hash from the user’s identity data
- Call the create user endpoint
- Sign and submit the account creation transaction
- Confirm the user was created
All user operations require an API key with PARTNER_EXECUTIVE_AUTHORITY scope. See Authentication & Setup if you haven’t set up your key yet.
Step 1: Generate a KYC Hash
The KYC hash is a SHA-256 hash of the user’s identity information, encoded as a Base58 string (via Solana’s PublicKey). This links on-chain accounts to off-chain KYC data without exposing personal information.
Use a consistent, deterministic format for KYC data. The same user must always produce the same hash. You can optionally store the raw SHA-256 hash bytes or the Base58 KYC hash in your own database for future reference.
import { createHash } from 'crypto';
import { PublicKey } from '@solana/web3.js';
function getKycHashBase58(kycData: Record<string, any>): string {
// Sort keys for deterministic output regardless of object key order
const serialized = JSON.stringify(kycData, Object.keys(kycData).sort());
const hash = createHash('sha256').update(serialized).digest();
// You can store the raw hash bytes if needed before returning the Base58 string
return new PublicKey(hash).toBase58();
}
// Usage
const kycHash = getKycHashBase58({
name: "John Doe",
passport: "AB123456",
dob: "1990-01-01"
});
// Same object with different key order produces the same hash
const sameHash = getKycHashBase58({
passport: "AB123456",
name: "John Doe",
dob: "1990-01-01"
});
// kycHash === sameHash ✓
console.log("KYC Hash (Base58):", kycHash);
Step 2: Create the User
Custodial
For custodial partners, the user does not have their own wallet. You manage their gold balances on their behalf.
Custodial partners must not include userWalletAddress. The API will reject the request if you do.
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/users \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{
"kycHash": "Base58EncodedKycHash",
"metadata": {
"referenceId": "user-123",
"tags": ["retail"]
}
}'
Self-Custody
For self-custody partners, each user has their own Solana wallet and signs their own transactions.
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/users \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{
"kycHash": "Base58EncodedKycHash",
"userWalletAddress": "UserSolanaWalletAddress",
"metadata": {
"referenceId": "user-123",
"tags": ["retail"]
}
}'
Both return the same response shape:
{
"success": true,
"data": {
"userId": "user-id",
"userPda": "user-pda-address",
"kycHash": "Base58EncodedKycHash",
"userWalletAddress": "UserSolanaWalletAddress",
"transaction": {
"serializedTx": "base64-serialized-transaction",
"signingInstructions": {
"walletType": "executive_authority",
"signers": ["ExecutiveAuthorityAddress"],
"expiresAt": "2024-01-15T10:35:00.000Z"
}
}
}
}
Note the userId — you’ll need it for all trading operations. The transaction field contains a serialized transaction that must be signed and sent to finalize user creation on-chain.
Step 3: Sign and Send the Transaction
User creation is a Legacy Transaction that only requires the executive authority signature — the user does not need to sign. Use Transaction (not VersionedTransaction) from @solana/web3.js.
import { Keypair, Transaction, Connection, sendAndConfirmTransaction } from "@solana/web3.js";
const connection = new Connection("https://api.devnet.solana.com");
// Your executive authority keypair
const executiveAuthority = Keypair.fromSecretKey(/* your secret key bytes */);
// Deserialize the transaction from Step 2
const serializedTx = "base64-serialized-transaction"; // from response.data.transaction.serializedTx
const transaction = Transaction.from(Buffer.from(serializedTx, "base64"));
// Sign and send to Solana
const txId = await sendAndConfirmTransaction(connection, transaction, [executiveAuthority]);
console.log("Transaction ID:", txId);
If you prefer not to send the transaction yourself, you can use the POST /api/transactions/submit endpoint instead. Just pass the base64-encoded signed transaction and the API will send it to the network for you.
Step 4: Query Users
Get a Single User
Retrieve details and balances for a specific user by their user ID.
curl -X GET https://oro-tradebook-devnet.up.railway.app/api/users/:userId \
-H "x-api-key: your-api-key"
{
"success": true,
"data": {
"userId": "user-uuid",
"userPda": "user-pda-address",
"kycHash": "Base58EncodedKycHash",
"userWalletAddress": "UserSolanaWalletAddress",
"metadata": {
"referenceId": "user-123",
"tags": ["retail"]
},
"balancesManagedByProgram": {
"gold": {
"amount": 1.5,
"valueUsd": 7500
}
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
The response returns both the userId (used in API calls) and the userPda (the on-chain address).
List All Users
Retrieve a paginated list of all users under your partner account.
Use the filter query parameter for advanced queries. For example, to find users with wallets: ?filter={"hasWalletAddress": true}.
curl -X GET "https://oro-tradebook-devnet.up.railway.app/api/users?partnerId=1&page=1&limit=20" \
-H "x-api-key: your-api-key"
{
"success": true,
"data": {
"users": [
{
"userId": "user-id",
"userPda": "user-pda",
"kycHash": "hash123",
"userWalletAddress": "wallet-address",
"metadata": { "referenceId": "user-123" },
"balancesManagedByProgram": {
"gold": { "amount": 1.5, "valueUsd": 7500 }
},
"createdAt": "2024-01-15T10:30:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 1,
"totalPages": 1
}
}
}
Next Steps
With users created, you can start trading. Proceed to Buying Gold to execute your first purchase.