First administrator setup
Create the first administrator, organization, wallet security, identity, system, currency, and token factories by API.
Use this guide to bootstrap a DALP instance by API instead of the web interface.
The flow creates the first administrator, binds that user to an organization, and secures the signing wallet. The final steps create the on-chain identity, initialize the system, and enable the first asset factories.
The first administrator becomes the starting point for later API keys, administrator roles, asset configuration, and operational workflows.
For the web interface approach, see the user guide.
Prerequisites
- Platform URL, such as
https://your-platform.example.com - ETH or the chain's native token for gas fees when you deploy on a public chain
- Email address for the administrator account
Critical security warning
When you create the account by API, keep the password out of scripts, logs, and version control. Load it from a secrets manager or a protected environment variable, then rotate it after setup if automation handled it. For manual setup, prefer the web interface because the password stays in the browser.
Overview
You complete the bootstrap in this order:
- Create the administrator account.
- Create and activate the organization.
- Create an API key for the remaining setup calls.
- Create a blockchain wallet, PIN, and recovery codes.
- Create the administrator's on-chain identity.
- Initialize the system infrastructure.
- Configure the base currency and token factories.
First user privileges
Only the first user can initialize the system. That setup deploys the identity registry, access manager, system registries, and compliance framework used by later platform operations.
Steps
Create administrator account
Register the first administrator account with an email address and password:
curl -i -c cookies.txt -X POST "https://your-platform.example.com/api/auth/sign-up/email" \
-H "Content-Type: application/json" \
-H "Origin: https://your-platform.example.com" \
-d '{
"name": "Platform Admin",
"email": "[email protected]",
"password": "YOUR_SECURE_PASSWORD"
}'Response:
{
"token": "1CL....UdI",
"user": {
"name": "Platform Admin",
"email": "[email protected]",
"emailVerified": false,
"image": null,
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"role": "admin",
"banned": false,
"banReason": null,
"banExpires": null,
"twoFactorEnabled": false,
"wallet": "0x0000000000000000000000000000000000000000",
"lastLoginAt": null,
"walletPincodeEnabled": false,
"walletPincodeVerificationId": null,
"walletTwoFactorEnabled": false,
"walletTwoFactorVerificationId": null,
"walletSecretCodeVerificationId": null,
"walletSecretCodesConfirmed": false,
"id": "usr_abc123"
}
}The session is now stored in cookies.txt. All subsequent authentication requests will use this session cookie automatically.
Save the user.id value, such as usr_abc123. You need it for the KYC profile step later. You can also retrieve your user information at any time using:
curl -X GET "https://your-platform.example.com/api/user/me" \
-H "X-Api-Key: YOUR_API_KEY"Password security
If automating this step, ensure the password is sourced from a secure secrets manager and never persisted in logs, scripts, or version control. Consider deleting the password from memory immediately after use.
Name your organization
Enter the name of the primary entity operating the platform. The example below creates Financial Institution S.A. and uses its slug as the organization context:
curl -b cookies.txt -X POST "https://your-platform.example.com/api/auth/organization/create" \
-H "Content-Type: application/json" \
-H "Origin: https://your-platform.example.com" \
-d '{
"name": "Financial Institution S.A.",
"slug": "financial-institution-sa"
}'Response:
{
"name": "Financial Institution S.A.",
"slug": "financial-institution-sa",
"logo": null,
"createdAt": "2024-01-15T10:00:00.000Z",
"id": "org_abc123",
"members": [
{
"organizationId": "org_abc123",
"userId": "usr_abc123",
"role": "owner",
"createdAt": "2024-01-15T10:00:00.000Z",
"id": "mem_abc123"
}
]
}After creating the organization, set it as your active context:
curl -b cookies.txt -X POST "https://your-platform.example.com/api/auth/organization/set-active" \
-H "Content-Type: application/json" \
-H "Origin: https://your-platform.example.com" \
-d '{
"organizationId": "org_abc123"
}'Response:
{
"name": "Financial Institution S.A.",
"slug": "financial-institution-sa",
"logo": null,
"createdAt": "2024-01-15T10:00:00.000Z",
"metadata": null,
"id": "org_abc123"
}Save the organization id from the response. You need it when creating API keys.
Create API key
Create an API key to authenticate subsequent requests:
curl -b cookies.txt -X POST "https://your-platform.example.com/api/auth/api-key/create" \
-H "Content-Type: application/json" \
-H "Origin: https://your-platform.example.com" \
-d '{
"name": "Platform Setup Key",
"expiresIn": 86400,
"metadata": {
"organizationId": "org_abc123"
}
}'Response:
{
"name": "Platform Setup Key",
"start": "sm_atk",
"prefix": "sm_dalp_",
"key": "sm_dalp_xxxxxxxxxxxxxxxx",
"userId": "usr_abc123",
"enabled": true,
"rateLimitEnabled": true,
"rateLimitTimeWindow": 60000,
"rateLimitMax": 10000,
"requestCount": 0,
"expiresAt": "2024-01-16T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"permissions": {
"user": ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update"],
"session": ["list", "revoke", "delete"],
"organization": ["update", "delete"],
"member": ["create", "update", "delete"],
"invitation": ["create", "cancel"],
"team": ["create", "update", "delete"],
"ac": ["create", "read", "update", "delete"],
"setting": ["read", "list", "upsert", "remove"],
"system": ["read", "list", "create"],
"exchangeRates": ["read", "list", "remove", "sync", "update"]
},
"metadata": {
"organizationId": "org_abc123"
},
"id": "key_abc123"
}Store API key securely
The full API key (sm_dalp_...) is shown only once. Store it immediately in a secure location. All subsequent
requests will use this key in the X-Api-Key header.
Create blockchain wallet
Create a blockchain wallet for the administrator:
curl -X POST "https://your-platform.example.com/api/user/create-wallet" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json"Response:
{
"wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}Save the wallet address for reference.
Secure with PIN
Enable PIN-based wallet verification for secure transaction signing:
curl -X POST "https://your-platform.example.com/api/auth/wallet/pincode/enable" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"pincode": "123456"
}'Response:
{
"success": true
}PIN security
Choose a unique 6-digit PIN that you can remember. This PIN is required to authorize blockchain transactions. Store it securely and never share it.
Save backup codes
Generate backup recovery codes in case you lose access to your PIN:
curl -X POST "https://your-platform.example.com/api/auth/wallet/secret-codes/generate" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{}'Response:
{
"secretCodes": ["ABCD-1234-EFGH", "IJKL-5678-MNOP", "QRST-9012-UVWX", "YZAB-3456-CDEF", "GHIJ-7890-KLMN"],
"rotated": false,
"verificationId": "018f7b0a-1234-7890-abcd-ef0123456789"
}Critical: Save recovery codes securely
These codes are your only way to recover wallet access if you forget your PIN. Store them securely using a secrets manager (HashiCorp Vault, AWS Secrets Manager, etc.) or offline (printed in a secure location). Never store them in plaintext in code, logs, or unsecured cloud storage. Each code can only be used once.
After securely storing the codes, send this request to confirm to the API that the secret codes have been stored securely.
Echo the verificationId returned by /generate so the server can reject confirmations against a rotated-away set:
curl -X POST "https://your-platform.example.com/api/auth/wallet/secret-codes/confirm" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"stored": true,
"verificationId": "018f7b0a-1234-7890-abcd-ef0123456789"
}'Response:
{
"success": true
}Create on-chain identity
Deploy the on-chain identity contract for the administrator account:
curl -X POST "https://your-platform.example.com/api/identity" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"walletVerification": {
"secretVerificationCode": "123456",
"verificationType": "PINCODE"
}
}'Response:
{
"id": "0x1234567890abcdef1234567890abcdef12345678",
"account": {
"id": "0xabcdef1234567890abcdef1234567890abcdef12",
"contractName": null
},
"isContract": false,
"hasIdentity": false,
"claims": []
}The id is your identity contract address. The hasIdentity field will be false until the system is initialized and the identity is registered.
Complete profile (optional)
Add your profile information for KYC purposes:
curl -X POST "https://your-platform.example.com/api/user/usr_abc123/kyc/upsert" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Platform",
"lastName": "Admin",
"dob": "1990-01-15T00:00:00.000Z",
"country": "BE",
"residencyStatus": "resident",
"nationalId": "123-45-6789"
}'Response:
{
"changed": true,
"currentVersion": {
"id": "kyc_version_123",
"number": 1,
"contentHash": "0xabcdef...",
"createdAt": "2024-01-15T10:00:00.000Z"
},
"profile": {
"id": "kyc_profile_123",
"userId": "usr_abc123",
"firstName": "Platform",
"lastName": "Admin",
"dob": "1990-01-15T00:00:00.000Z",
"country": "BE",
"residencyStatus": "resident",
"nationalId": "123-45-6789",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z"
}
}Initialize the system
Deploy the core platform infrastructure. This step may take several minutes on public chains:
curl -X POST "https://your-platform.example.com/api/systems" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"walletVerification": {
"secretVerificationCode": "123456",
"verificationType": "PINCODE"
}
}'Response:
{
"systemAddress": "0x9876543210fedcba9876543210fedcba98765432"
}This deploys:
- Identity Registry: manages user identities
- Access Manager: controls role-based permissions
- System Registries: track deployed contracts
- Compliance Framework: enforces regulatory rules
Poll for deployment status
On public chains, monitor the deployment status:
curl -X GET "https://your-platform.example.com/api/system/default" \
-H "X-Api-Key: YOUR_API_KEY"Response (key fields for status polling):
{
"id": "0x9876543210fedcba9876543210fedcba98765432",
"status": "completed",
"userIdentityRegistered": true,
"canResume": false,
"updatedAt": "2024-01-15T10:05:00.000Z",
"deployedInTransaction": "0x00feaa...",
"tokenFactoryRegistry": { "id": "0x...", "tokenFactories": [] }
// ... additional contract registries and configuration
}The full response includes all deployed contract addresses, compliance modules, and access control settings. For polling, check these key fields:
| Field | Value | Meaning |
|---|---|---|
status | bootstrapping | Deployment in progress |
status | completed | Deployment finished |
userIdentityRegistered | true | Your identity is registered in the system |
canResume | true | Deployment can be resumed (if it was interrupted) |
The system is ready when status is completed and userIdentityRegistered is true.
Deployment time
System initialization may take several minutes on public blockchains. Poll the status endpoint every few seconds until
status is completed and userIdentityRegistered is true.
Configure base currency
Review the provider's current currency snapshot before selecting the platform base currency. The API returns the configured provider key and sorted ISO 4217 alpha-3 currency codes.
curl -X GET "https://your-platform.example.com/api/v2/exchange-rates/supported-currencies" \
-H "X-Api-Key: YOUR_API_KEY"Response:
{
"data": {
"providerKey": "open-er-api",
"currencies": ["AED", "EUR", "USD"]
}
}Set BASE_CURRENCY from an authenticated CLI session. Before you run these commands, sign in to the same DALP instance in the web interface and make the organization you created above the active organization. Then run dalp login and confirm dalp whoami shows that organization.
For CLI bootstrap, choose a base-currency code that is accepted by the CLI and also appears in the provider snapshot. The CLI accepts AED, AUD, CAD, CHF, EUR, GBP, JPY, MYR, SAR, SGD, USD, and ZAR.
dalp login --url https://your-platform.example.com
dalp whoami
dalp settings upsert --key BASE_CURRENCY --value USDAfter setting the currency, refresh exchange rates from the configured provider in the same authenticated session:
dalp exchange-rates syncResponse:
{
"data": {
"ratesUpdated": 132,
"syncedAt": "2026-05-15T10:00:00.000Z"
}
}For the complete exchange-rate command list, see CLI command reference.
Enable asset types
Deploy token factories for each asset type you want to support:
curl -X POST "https://your-platform.example.com/api/system/token-factory" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"factories": [
{ "type": "equity", "name": "Equity" }
],
"walletVerification": {
"secretVerificationCode": "123456",
"verificationType": "PINCODE"
}
}'Response (abbreviated):
{
"id": "0x9876543210fedcba9876543210fedcba98765432",
"tokenFactoryRegistry": {
"id": "0xFDD42C4e9Bd27cCA35b38C2925f1ED7EAE1AAc5b",
"tokenFactories": [
{
"id": "0xA93F2f761DB1B3F8dc0ed6EcC9d38Bf15C8f562B",
"name": "Equity",
"typeId": "equity"
}
]
}
// ... full system configuration
}The response returns the complete system configuration. The newly created factory appears in tokenFactoryRegistry.tokenFactories.
Available asset types:
equity: Tokenized shares and stockbond: Fixed income securitiesfund: Investment fund unitsstablecoin: Stable value tokensdeposit: Tokenized depositsreal-estate: Property tokensprecious-metal: Commodity-backed tokens
Request parameters
Sign up endpoint
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the administrator |
email | string | Yes | Email address (must be unique) |
password | string | Yes | Account password (min 8 characters recommended) |
API key creation
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Descriptive name for the API key |
expiresIn | number | No | Expiration time in seconds (default: no expiration) |
metadata | object | No | Custom metadata to attach to the key |
Wallet verification object
| Field | Type | Required | Description |
|---|---|---|---|
secretVerificationCode | string | Yes | The PIN code, OTP, or recovery code |
verificationType | string | Yes | PINCODE, OTP, or SECRET_CODES |
KYC profile
| Parameter | Type | Required | Description |
|---|---|---|---|
userId (path) | string | Yes | User ID to update KYC for (in URL path) |
firstName | string | No | First name (max 64 characters) |
lastName | string | No | Last name (max 64 characters) |
dob | string | No | Date of birth (ISO 8601, must be 18+ years old) |
country | string | No | ISO country code (e.g., BE, DE, GB) |
residencyStatus | string | No | resident, non_resident, dual_resident, or unknown |
nationalId | string | No | National ID number (max 50 characters) |
Factory creation
| Parameter | Type | Required | Description |
|---|---|---|---|
factories | array | Yes | Array of factory objects (1-10 factories) |
factories[].type | string | Yes | Asset type (see available types above) |
factories[].name | string | Yes | Display name for the factory (max 100 characters) |
factories[].factoryImplementation | string | No | Custom factory implementation address |
factories[].tokenImplementation | string | No | Custom token implementation address |
walletVerification | object | Yes | Wallet verification (see above) |
Best practices
Security considerations
- Store credentials in a secrets manager such as Vault or AWS Secrets Manager.
- Delete passwords from memory after use and keep sensitive values out of logs.
- Create short-lived API keys and rotate them regularly.
- Use a PIN that is not shared with other services.
- Store recovery codes in a secrets manager or offline. Keep them out of source control and unsecured storage.
Transaction timing
- On public chains, wait for sufficient block confirmations.
- Use
/api/system/defaultto monitor deployment status. - Allow 5 to 10 minutes for system initialization on congested networks before treating it as failed.
Error handling
- Use exponential backoff for transient failures.
- Retry idempotent setup calls instead of restarting the whole bootstrap.
- Check that the wallet has enough gas before transaction-bearing operations.
Troubleshooting
| Issue | Solution |
|---|---|
401 Unauthorized | Session expired or API key invalid. Re-authenticate or create a new API key. |
403 Forbidden | Account lacks required permissions. First user should have admin privileges automatically. |
400 Email already exists | Email is taken. Use a different email or sign in to existing account. |
400 Invalid pincode | PIN must be exactly 6 digits. |
| Identity creation fails | Ensure wallet has sufficient gas for contract deployment. |
| System initialization timeout | Normal on public chains. Poll /api/system/default until status is completed. |
| Factory creation fails | System must be fully deployed first. Check system status before creating factories. |
| Transaction reverted | Verify PIN is correct. Check wallet has sufficient gas. |
| API key not working | Verify key hasn't expired. Check X-Api-Key header is set correctly. |
Related guides
- Add Administrators: grant administrative permissions via API
- Change Admin Roles: modify or revoke role assignments via API
- Getting Started: API key setup and authentication
- API Reference: full OpenAPI specification
- First Administrator Setup (User Guide): web interface approach