# Create an account

> Creates a person or company record from the details given: name or company, email, phone and address, with your own reference (crmkey), tags and metadata. Calle

Creates a person or company record from the details given: name or company, email, phone and address, with your own reference (crm_key), tags and metadata. Callers that render Shuttle's dynamic form can send the form's values instead. An account created with a crm_key is a CRM-linked account; one created without is a disconnected account (`disconnected_account: true`), which is what Merchant View's screens always create. If the crm_key already belongs to an account, that account is updated instead of a second one being created.

### Where you can do this

- Merchant View: [Create or edit an account](/platforms/user-guides/admin-account-form/) (Save)
- Merchant View: Save
- API: [Create an account](/platforms/reference/operations/createaccount/) (`POST /accounts`)

### Before you start

- The channel the account is created against exists: `channels[0]` when given, otherwise the client's `web` channel. The new account is attached to that channel's division.
- For a CRM-linked account (a crm_key is given), the client's CRM connector accepts registrations. The built-in CRM always does.

### Inputs

| Input | Required | Meaning and constraints |
|---|---|---|
| first_name | no | The account holder's first name |
| last_name | no | The account holder's last name |
| company | no | Company name, for a business account or alongside a person's names. On a disconnected account it is not returned or searchable until the account is next updated; see Rules |
| email | no | Email address. Invalid addresses are accepted so a payment is never blocked by contact validation |
| phone | no | Phone number, any format |
| address | no | Object with line1 to line6 (line4 city, line5 postcode, line6 state) and country, any values accepted. Stored in full only on a disconnected create; when a crm_key is given the built-in CRM keeps only `country` and the lines are dropped, see Rules |
| crm_key | no | Your identifier for the account. Given: the account is CRM-linked. Omitted: the account is disconnected. If an account already has this key (matched case-insensitively) that account is updated instead; see [Update an account](/platforms/user-guides/rules-account-update/) |
| tags | no | Comma-separated references for searching, stored as given |
| metadata | no | Custom key-value pairs. Dropped by a create: stored only when the crm_key matched an existing account and the update path ran. A remote CRM connector is sent them; the built-in CRM ignores them. See Rules |
| locale | no | The customer's language, used for communications |
| timezone | no | The customer's timezone in IANA format, used for scheduling |

### Rules

*Checked by* **the API** means Shuttle refuses the request however it is sent; a screen name means only that screen refuses it, and a direct API call would be accepted.

| Rule | Checked by | What you see |
|---|---|---|
| The body must carry an `account` object | The API | VALIDATION_ERROR: "API body error: missing account object" |
| The channel named by `channels[0]` (default `web`) must exist for the client | The API | INVALID |
| When `values` is present it is what is stored; the fixed fields (first_name, last_name, company, email, phone, address, locale, timezone) are ignored | The API | (behaviour) |
| A CRM key inside `values` (`crm_key` or `crmkey`) takes precedence over the top-level crm_key | The API | (behaviour) |
| If an account with the same crm_key already exists, it is updated with the details given and returned; no second account is created. The match is case-insensitive | The API | (silent update; the response carries the existing account's id) |
| Without a crm_key, or with disconnected_account true, the account is created disconnected (`disconnected_account: true`); with a crm_key it is CRM-linked and active | The API | (behaviour) |
| On the CRM-linked path, if the platform already holds an account with that crm_key that the duplicate check above did not find, that account is returned and the details given are not written to it | The API | (behaviour) |
| The screen's mandatory and format rules are the channel's configured dynamic form (by default an email-format and phone-format check, no mandatory fields); the API applies none of them and accepts any email or phone | Merchant View screen | inline validation |
| If the CRM connector returns no account, the create fails | The API | INVALID: "BOLT-1123" (CRM account creation failed) |
| A remote CRM's rejection of the registration is returned as the error message | The API | the CRM's message (code not traced) |

### What happens

- A new account is returned in the response (`account`, id `acc_...`) with `disconnected_account: true` when no crm_key was given, or `crm_key` set and status active when it was.
- If the crm_key already belonged to an account, that account is returned, updated with the details given; nothing new is created.
- The merchant receives an ACCOUNT.CREATED webhook (ACCOUNT.UPDATE instead when an existing account was updated), and the account appears in Merchant View's account search shortly afterwards.
- metadata will be missing from the created account, and company will be missing from a disconnected account, until the account is next updated.
- No customer session is opened and no fraud screening runs; the create is an operator action.

### Who can do this

- Roles: Admin and Support.
- Permission keys (for clients managing permissions directly): only when the crm_key matches an existing account is `account`, `checkout` or `*` required on the client or on one of that account's divisions, else UNAUTHORIZED "Unauthorized". The new-account path enforcing no key is a gap: Merchant View gates the screens on `account`, the server on nothing. The existing-account check also passes the wrong account id in its customer-session fallback (the connector id rather than the account id); customer sessions are refused earlier, so it has no visible effect.
- Admin app: the Create account button on the account search needs option `account_edit` and the create screen needs `account` on a division or the client, exactly one division in the user's scope, and an API channel in that division. The terminal person screens need only `account` and use the batch's channel to load the form.

### Related

- [Update an account](/platforms/user-guides/rules-account-update/)