Skip to main content

User Onboarding

Before a customer can fund, trade, or withdraw on a payments-core account, they need a user (end customer), an account linked to that user, a submitted identity, and confirmed agreements. Then poll until the account is open.


Step 1: Create User

Register the end customer under your organization.

  • POST /user
  • Optional externalId: your own customer key (unique per org, write-once; generated if omitted)
  • Optional name: display name
  • Store the returned userId
{
"externalId": "customer-123",
"name": "Jane Doe"
}

Duplicate externalId within your org returns 409. To look up an existing customer, use GET /user?externalId=... or GET /user/{id}.

See Core Concepts: User.


Step 2: Create Account

Register a payments-core account for the customer with provider: "BITGO" and the userId from Step 1.

  • POST /account
  • Body: { "provider": "BITGO", "userId": "<userId>", "async": false }
  • Store the returned accountId
{
"provider": "BITGO",
"userId": "<userId>",
"async": false
}
Prefer async: false while integrating

Synchronous create fails the request if provider provisioning fails immediately, which is easier to debug. Use async: true only when you intentionally want background reconciliation.

See Core Concepts: Account.


Step 3: Submit Identity

Submit KYC data for the account.

  • POST /identity
  • Tie the identity to the account with accountId
  • Use identityType: "natural_person" for individuals (companies use a company identity type)
  • async: false provisions the identity inline when possible

Example natural-person payload:

{
"accountId": "<accountId>",
"accountRoles": "owner",
"identityType": "natural_person",
"email": "[email protected]",
"firstName": "Jane",
"lastName": "Doe",
"primaryAddress": "123 Main St",
"primaryCity": "San Francisco",
"primaryPhoneNumber": "+15555551234",
"primaryPostalCode": "94102",
"dateOfBirth": "1998-02-11",
"occupation": "Other",
"politicallyExposedPerson": false,
"taxCountry": "US",
"taxIdNumber": "123456789",
"taxState": "CA",
"sex": "male",
"async": false
}
caution

KYC can leave the account pending (with a statusReason such as pending identity) until the identity is approved. Do not assume create-identity alone opens the account.


Step 4: Confirm Agreements

List seeded agreements, then agree to each required row.

  • GET /agreement: find rows for this accountId
  • PUT /agreement/{id}/agree: body can be {} for payments-core agree

For accounts with provider: "BITGO", expect at least:

  1. MAGFI_AGREEMENT_TERMS_OF_SERVICE (TOS)
  2. BITGO_AGREEMENT_CSA (CSA)
  3. BITGO_AGREEMENT_MPA (MPA) when present
Agreements must be confirmed before open

Agreeing submits the signature. For CSA/MPA, status becomes confirmed only after the provider accepts it. The account will not open while required agreements are still outstanding.


Step 5: Poll Until Open

  • GET /account/{id}
  • Wait for status: "open" before funding or trading

Common pending reasons include identity still in review or agreements not yet confirmed. Treat status as the gate; use statusReason for diagnostics.


Putting It Together


Next Steps