Multiple Tenant Accounts

Power Multiple Tenant Accounts - Integration Guide

Introduction

This guide provides a comprehensive overview of integrating joint accounts within the Zero Hash platform, aligning with the latest API specifications and account structures.

Use Cases

  • Early Wealth Building via Crypto Gifting: Parents or guardians can gift Bitcoin or other cryptocurrencies to a child at birth. Crypto assets held in a UTMA account can appreciate over time and be sold when the child reaches the age of majority. The proceeds can be used for major life expenses such as college tuition, a vehicle purchase, or a down payment on a first home.

  • Estate Planning or Wealth Management: Individuals can open a Trust account to hold and manage investments on behalf of beneficiaries. Cryptocurrencies placed in a revocable or irrevocable trust can grow over time while remaining protected under the terms of the trust.

  • Married Couples: Spouses may open a joint brokerage account—such as a Joint Tenants with Right of Survivorship (JTWROS) or Community Property account—to manage shared investments. This allows both partners equal access to the account and ensures that, upon the death of one spouse, the surviving spouse automatically inherits the assets without going through probate.

Account Types

Zero Hash supports various account types, each with specific tenant configurations and authorization models:

Account TypesDefinition
Uniform Transfers to Minors Act (UTMA)Custodial accounts for minors, managed by a custodian until the minor reaches the age of majority
TrustManaged by a trustee for the benefit of beneficiaries
Joint Tenants in Common (JTIC)Multiple individuals with potentially unequal ownership; upon death, the deceased's share passes to their estate
Joint Tenants with Right of Survivorship (JTWROS)Equal ownership among individuals; upon death, the deceased's share automatically transfers to surviving tenants
Community PropertyAssets held jointly by a married couple, each owning a 50% interes

Each account type has predefined tenant roles and authorization levels, ensuring compliance and proper access control.

Tenant Types

Joint accounts have multiple tenants with associated authorizations, as described below:

Tenant TypesDefinition
IndividualA natural person who is granted authorizations to access the account
UTMA BeneficiaryThe minor child for whom the custodial account is helf under the Uniform Transfers to Minors Act. The beneficiary is the legal owner of the funds, but has no control over the account until reaching the age of majority (18 or 21)
UTMA CustodianThe legally authorized adult who manages a UTMA account on behalf of the minor beneficiary
TrusteeThe person or institution legally responsible for managing the trust’s assets
Trust BeneficiaryThe individual or entity entitled to receive distributions or benefits from the Trust

Tenant Designations

Each multiple tenant account must have one Primary Participant, and at least one Secondary Participant.

Tenant DesignationsDefinition
PrimaryThe primary participant associated with the account creation
SecondaryThe secondary participant(s) associated with the account

Tenant Authorizations

Tenant authorizations define the level of access and control over an account. These authorizations are assigned based on the account type and tenant configuration.

AuthorizationPermissions
Full TradingThe ability to withdrawal funds, trade, and access statements & receipts
Limited TradingThe ability to trade and access statements & receipts. Cannot withdrawal funds
View OnlyThe ability to access statements & receipts. Cannot withdrawal funds or trade

Authorization Matrix

The below matrix represents the default authorizations for each Account Type and Tenant Type. Tenant authorizations can be updated after account creation.

Steps for Setting Up Multiple Tenant Accounts and Tenants

  1. Create the primary and secondary participants using POST /participants/customers/new
  2. Create an account using POST /accounts/new
    1. Assign the primary articipant participant_code: the primary participant's participant code
    2. Set account type bytype: the AccountTypeEnum
    3. Add the additional tenant(s) by tenants: the secondary participant(s)' participant codes

Example: UTMA Account Purchases Crypto

High Level Flow

  1. Create a custodian
  2. Query the custodian
  3. Create the minor
  4. Query the minor
  5. Establish the UTMA account
  6. Query the UTMA account
  7. Get a quote
  8. Execute a quote
  9. Query the trade
  10. View the UTMA account balance

Initial Setup

The Platform will need to onboard its business to the Zero Hash platform. They then need to add additional users, create API keys, and whitelist IP addresses. See instructions here.

1. Create the Custodian

Once API keys are created and approved, the Platform can begin to integrate to the API. For the following examples, we’ll assume the Platform's platform code is PLAT01.

The Platform submits the Custodian via POST /participants/customers/new:

{
    "first_name": "John",
    "last_name": "Smith",
    "email": "[email protected]",
    "phone_number": "+12345834789",
    "date_of_birth": "1985-09-02",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "city": "Chicago",
    "zip": "12345",
    "jurisdiction_code": "US-IL",
    "sanction_screening": "pass",
    "sanction_screening_timestamp": 1603378501282,
    "signed_agreements": [{
        "type": "user_agreement",
        "region": "us",
        "signed_timestamp": 1603378501286
    }],
}

Note: The Custodian will be agreeing to the Zero Hash User Agreement and associated terms. The platform indicates to Zero Hash that they accepted the terms by sending a value in the signed_agreement object as shown above.

  • type: the type of user agreement being signed. For Remittances, the Sender is signing the standard user agreement, so a value of user_agreement is expected.
  • signed_timestamp: is the timestamp that the Sender accepted the terms and conditions.
  • region: represents the Zero Hash entity that the Sender is entering into a contract with. The only acceptable value right now is US.

POST /participants/customers/new response:

 {
     "first_name": "John",
     "last_name": "Smith",
     "email": "[email protected]",
     "address_one": "1 Main St.",
     "address_two": "Suite 1000",
     "country": "United States",
     "state": "IL",
     "jurisdiction_code": "US-IL",
     "city": "Chicago",
     "zip": "12345",
     "date_of_birth": "1985-09-02",
     "id_number_type": "unknown",
     "id_number": "",
     "non_us_other_type": "",
     "id_issuing_authority": "",
     "signed_timestamp": -62135596800000,
     "risk_rating": "",
     "metadata": {},
     "platform_code": "PLAT01",
     "participant_code": "CUSTD1", <-- Custodian Participant Code
     "tax_id": "",
     "citizenship": "",
     "citizenship_code": "",
     "kyc": "unknown",
     "kyc_timestamp": null,
     "onboarded_location": "US-IL",
     "sanction_screening": "pass",
     "sanction_screening_timestamp": null,
     "liveness_check": "unknown",
     "phone_number": "+12345834789",
     "employment_status": "unknown",
     "industry": "unknown",
     "source_of_funds": "unknown",
     "signed_agreements": [{
         "region": "us",
         "signed_timestamp": 1603378501,
         "type": "user_agreement"
     }]
 }

Note: The response contains a participant_code for the Custodian. This uniquely identifies the Custodian indefinitely and should be use in subsequent API calls where applicable. We’ll use CUSTD1 as the participant_code throughout the examples.

3. Create the Minor

The Platform submits the Custodian via POST /participants/customers/minor:

{
    "first_name": "John",
    "last_name": "Smith",
    "email": "[email protected]",
    "phone_number": "+12345834789",
    "date_of_birth": "1985-09-02",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "city": "Chicago",
    "zip": "12345",
    "jurisdiction_code": "US-IL",
    "partial": true,
    "sanction_screening": "pass",
    "sanction_screening_timestamp": 1603378501282
    }],
}

Note: The Minor will not need to agree to Zero Hash User Agreement and associated terms, but they are subject to KYC.

POST /participants/customers/minor response:

{
    "first_name": "John",
    "last_name": "Smith",
    "email": "[email protected]",
    "phone_number": "+12345834789",
    "date_of_birth": "1985-09-02",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "city": "Chicago",
    "zip": "12345",
    "jurisdiction_code": "US-IL",
    "partial": true,
    "sanction_screening": "pass",
    "sanction_screening_timestamp": 1603378501282,
    "platform_code": "PLAT01",
    "participant_code": "MINOR1", <-- Minor Participant Code
}

Note: The response contains a participant_code for the Minor. This uniquely identifies the Minor indefinitely and should be use in subsequent API calls where applicable. We’ll use MINOR1 as the participant_code throughout the examples.

5. Create the UTMA account

The Platform will create the UTMA account via a POST /accounts/new call:

{
  "message": {
    "type": "utma",
    "participant_code": "MINOR1",
    "tenants":"CUSTD1"
    "prefunded": true,
    "account_label": "general",
    "tier": "pro"
  }
}

Example response:

{
    "type": "utma",
    "participant_code": "MINOR1",
    "tenants":"CUSTD1"
    "prefunded": true,
    "account_label": "general",
    "tier": "pro",
    "multi_tenant_account_id": "d72d68f3-55ae-4c26-aebc-4298c56f10f1"
}

📘

When the UTMA account is created and the minor is associated as the primary participant_code, the minor will automatically inherit the UTMA Beneficiary authorizations, which is View Only. The Custodian will automatically inherit the UTMA Custodian authorizations, which is Full Trading

7. Get a Quote

The UTMA account is ready fro trading. Start by getting a quote via POST /liquidity/rfq using the Custodian's participant code

{
  "participant_code" :'CUSTD1',
  "multi_tenant_account_id": "d72d68f3-55ae-4c26-aebc-4298c56f10f1",
  "side": "buy",
  "underlying": "BTC",
  "quoted_currency": "USD",
  "total": 1000
}

Example response:

{
  "message": {
    "request_id": "d72d68f3-55ae-4c26-aebc-4298c56f10f1",
    "participant_code": "PLAT01",
    "multi_tenant_account_id": "d72d68f3-55ae-4c26-aebc-4298c56f10f1",
    "quoted_currency": "USD",
    "side": "buy",
    "quantity": "0.0091",
    "price": "109776",
    "quote_id": "c2efaa66-a06f-40e7-8da4-35f525c80847",
    "expire_ts": 1714527280072,
    "account_group": "00SCXM",
    "account_label": "general",
    "obo_participant": {
      "participant_code": "CUSTD1",
      "account_group": "PLAT01",
      "account_label": "general"
    },
    "parent_link_id": "",
    "parent_link_id_source": 0,
    "underlying": "BTC",
    "asset_cost_notional": "1000",
    "spread_notional": "2",
    "spread_bps": "200"
  }
}

📘

You can monetize this purchase by assessing a disclosed spread. Contact your Zero Hash rep to make the configuration

8. Execute a Quote

To execute a quote, we need to pass the active quote_id that was obtained from the POST /liquidity/rfq endpoint, as a parameter into the POST /liquidity/execute endpoint:

{
  "quote_id": "c2efaa66-a06f-40e7-8da4-35f525c80847"
}

Example response:

{
  "message": {
    "request_id": "39b54e0f-6af1-4d79-a7b5-a9cf036794f9",
    "quote": {
      "request_id": "d72d68f3-55ae-4c26-aebc-4298c56f10f1",
      "participant_code": "PLAT01",
      "quoted_currency": "USD",
      "side": "buy",
      "quantity": "0.0091",
      "price": "109776",
      "quote_id": "c2efaa66-a06f-40e7-8da4-35f525c80847",
      "expire_ts": 1714527280072,
      "account_group": "00SCXM",
      "account_label": "general",
      "obo_participant": {
        "participant_code": "CUSTD1",
        "account_group": "PLAT01",
        "account_label": "general"
      },
      "parent_link_id": "",
      "parent_link_id_source": 0,
      "underlying": "BTC",
      "asset_cost_notional": "1000",
      "spread_notional": "2",
      "spread_bps": "200",
      "transaction_timestamp": 1714527260659
    },
    "trade_id": "041fb0aa-5382-49c3-9a6a-aff473221c8d",
    "status": "Completed",
    "trade_ids_list": [
      "041fb0aa-5382-49c3-9a6a-aff473221c8d"
    ]
  }
}

Note: The .0091 BTC is ledgered to the Minor's account (MINOR1)

9. Query the Trade

The Platform can query trades retroactively via GET /trades or GET /trades/{trade_id}:

10. View the UTMA Account Balance

In order to query current balances, call the GET /accounts endpoint with the following parameters:

  • participant_code: MINOR1
  • account_group: PLAT01
  • account_label: general
  • asset: BTC

Example request: GET /accounts?participant_code=MINOR1&account_group=PLAT01&account_label=general&asset=BTC