Skip to content

Onboard a client end to end ​

The core CRM flow: a lead becomes a client, passes KYC, gets a trading account and makes the first deposit.

text
clients.create → clients.approve → accounts.create → clients.linkAccount → accounts.balance
ts
export async function onboardClient(masterPassword: string, investorPassword: string) {
  // 1. The client record: the CRM contact, owned by a manager.
  const client = await staff.clients.create({
    type: "individual",
    first_name: "Ann",
    last_name: "Smith",
    email: "ann@example.com",
    phone: "+44 20 7946 0000",
    country: "United Kingdom",
    preferred_group: "real\\standard",
    assigned_manager: 1001,
  });

  // 2. KYC checked: approve (status and kyc_status become approved).
  await staff.clients.approve(client.id, { comment: "Documents checked" });

  // 3. A trading account in the client's group, starting with zero money.
  const account = await staff.accounts.create({
    name: "Ann Smith",
    email: "ann@example.com",
    group: "real\\standard",
    leverage: 100,
    master_password: masterPassword,
    investor_password: investorPassword,
    trading_enabled: true,
  });

  // 4. Link the account to the client.
  await staff.clients.linkAccount(client.id, { login: account.login });

  // 5. First deposit. A new request_id per operation: repeating it never pays twice.
  const deposit = await staff.accounts.balance(account.login, {
    request_id: crypto.randomUUID(),
    action: "balance",
    amount: "1000.00",
    comment: "First deposit",
  });
  if (deposit.status !== "done") throw new Error(`deposit refused: ${deposit.code}`);

  return { client, account, deposit };
}

Rights needed: clients.view plus clients.create, clients.verify, clients.edit, accounts.edit and accounts.balance. The account's group must be in your group scope, otherwise forbidden.

Notes

  • accounts.create opens the account with zero money: the deposit is a separate, journaled money operation.
  • Linking an account already linked to another client answers conflict: unlink it there first with clients.unlinkAccount.
  • Each step writes a journal line; the client's history shows them (see timeline).