Skip to main content

Overview

The POST /v1/accounts endpoint accepts the full account onboarding graph in a single request. All children (addresses, contacts, payment methods, tags) are written in one database transaction. Any child failure rolls back the parent account and every already-inserted child, so you get a complete record or nothing. The 201 response includes all children hydrated inline; no follow-up GET calls are needed.

Minimal create

Only name is required. account_type is one of business, individual, vendor or lead, and it defaults to business, so send it whenever the account is anything else. Anything you leave out is filled from your entity’s setup where Arcus can: the account takes the default payment term, the pricing level whose “defaults on” list names its account type, and the entity’s default location.
A second active account of the same type with the same name is refused with 422 duplicate_account_name, and the response lists the accounts it matched in existing. If you really want the duplicate, send "force_create": true.

Full B2B onboarding graph

One POST creates the account, 3 addresses, 2 contacts, a payment method, and 2 tags.
Expected 201 response (truncated):

Address field aliases

The endpoint accepts Stripe-style field names as aliases for the internal column names: Both sets of names are accepted; canonical names (line1, state, zip) are returned in all responses.

Default billing and shipping flags

  • At most one address in the request may have is_default_billing: true, and at most one may have is_default_shipping: true. Sending more than one of either returns 422.
  • A create call stores the flags exactly as you send them. Mark the addresses you want as defaults in the request; an address with no flag is saved as a plain billing or shipping address.
  • To add an address later, call POST /v1/accounts/:id/addresses. The first address an account ever gets becomes the default of its type automatically. After that, send is_default_billing, is_default_shipping or is_default to take over the default; the previous default of that type is demoted. Setting is_pickup: true forces the type to shipping.
  • The add-address call also checks the address when address validation is connected, and fills in is_commercial and the coordinates when you did not send them. The create call does not run that check.

Contact title, role and primary

Each contact has two separate fields:
  • title is free text for the job title, such as “Accounts Payable”. It is saved by both the create call and the add-contact call.
  • role is a typed field that takes one of primary, ap, buyer, shipping, decision_maker, technical or other (lowercase), or nothing. The add-contact call (POST /v1/accounts/:id/contacts) saves it and refuses any other value with 400 contact_role_invalid. The inline contacts[] of a create call does not save role, so set it afterward with the add-contact or update-contact call if you need it.
If no contact in a create call has is_primary: true, the first one becomes primary. If you send no contacts at all, Arcus creates one primary contact from the account’s name, email and phone. Adding a contact with is_primary: true later demotes the current primary.

Payment methods: test mode

In test mode, use Stripe test card tokens:
  • pm_card_visa — Visa, succeeds
  • pm_card_mastercard — Mastercard, succeeds
  • pm_card_visa_chargeDeclined — always fails
Stripe must be configured for your entity. If Stripe is not configured, or a token cannot be attached, the whole create call fails with payment_method_attach_failed and no account is left behind; omit the array if you are testing without Stripe.

Credit limit

credit_limit is a JS number (float) in the response, never a Postgres NUMERIC string. credit_balance on a new account equals credit_limit (no outstanding AR yet).

Tags: auto-create

Tags supplied by name are auto-created for the entity if they do not exist. The name is slugified (lowercased, non-alphanumeric chars replaced by _) to form the slug. Applying the same tag name twice in tags[] is idempotent.

Error envelope

All errors follow the canonical envelope:
Common validation errors: Validation failures on the create call return HTTP 422.

Idempotency

Supply Idempotency-Key: <unique-string> to safely retry creates without duplicating records. The key is honored for 24 hours.
  • GET /v1/accounts/:id — retrieve an account by its id or by its account number. The response already includes its addresses, contacts and payment methods, plus recent orders and a timeline, so no expand is needed. An id or number that matches nothing returns 404 account_not_found. Needs accounts:read.
  • POST /v1/accounts/:id/addresses — add an address to an existing account. Accepts type (or address_type), label, name, line1, line2, city, state, zip, country (default US), is_commercial, is_default, is_default_billing, is_default_shipping and is_pickup, with the same aliases as above. Needs accounts:write.
  • POST /v1/accounts/:id/contacts — add a contact to an existing account: first_name, last_name, email, phone (or phone_main), title, role, website and is_primary. Needs accounts:write.
  • POST /v1/accounts/:id/payment-methods — attach a payment method to an existing account. Send payment_method_id, the pm_ token from a Stripe SetupIntent that was already confirmed in the browser with Stripe.js. Needs accounts:write and a Stripe connection for the entity.
  • POST /v1/accounts/:id/merge — merge a duplicate into this account. The account in the path is the one that survives; send the other as loser_account_id and, optionally, a reason. Needs both accounts:write and accounts:delete.

What a merge does

The surviving account takes over the other account’s orders, returns, payment methods, contacts, addresses, vendor bills and the rest of its records in one transaction. Where both accounts have a primary contact or a default address, the surviving account’s stays and the other’s is demoted. The merged-away account is deactivated and marked as merged, and the reason you gave goes into the activity log. Earlier general ledger and inventory history is not rewritten.