Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.arcuserp.com/llms.txt

Use this file to discover all available pages before exploring further.

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 — 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 and account_type are required.
curl -X POST https://api.arcuserp.com/v1/accounts \
  -H "Authorization: Bearer ark_live_ent_acme_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "account_type": "business",
    "name": "Acme Wholesale"
  }'

Full B2B onboarding graph

One POST creates the account, 3 addresses, 2 contacts, a payment method, and 2 tags.
curl -X POST https://api.arcuserp.com/v1/accounts \
  -H "Authorization: Bearer ark_live_ent_acme_xxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: acme-wholesale-onboard-2026-05-12" \
  -d '{
    "account_type": "business",
    "name": "Acme Wholesale",
    "email": "ap@acme.example",
    "phone": "+1-555-0100",
    "credit_limit": 25000.00,
    "addresses": [
      {
        "type": "billing",
        "label": "HQ",
        "is_default_billing": true,
        "street1": "1 Acme Way",
        "city": "Austin",
        "region": "TX",
        "postal_code": "78701",
        "country": "US"
      },
      {
        "type": "shipping",
        "label": "Main Warehouse",
        "is_default_shipping": true,
        "street1": "100 Industrial Dr",
        "city": "Austin",
        "region": "TX",
        "postal_code": "78702",
        "country": "US"
      },
      {
        "type": "shipping",
        "label": "Branch Warehouse",
        "street1": "200 Branch Rd",
        "city": "Houston",
        "region": "TX",
        "postal_code": "77001",
        "country": "US"
      }
    ],
    "contacts": [
      {
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "jane@acme.example",
        "phone": "+1-555-0101",
        "is_primary": true,
        "role": "AP"
      },
      {
        "first_name": "John",
        "last_name": "Smith",
        "email": "john@acme.example",
        "role": "Operations"
      }
    ],
    "payment_methods": [
      {
        "stripe_payment_method_id": "pm_card_visa",
        "is_default": true
      }
    ],
    "tags": ["VIP", "Wholesale-Tier-1"]
  }'
Expected 201 response (truncated):
{
  "data": {
    "id": "a1b2c3d4-...",
    "account_type": "business",
    "display_name": "Acme Wholesale",
    "account_number": "CUST-00042",
    "credit_limit": 25000.0,
    "credit_balance": 25000.0,
    "addresses": [
      { "id": "...", "type": "billing",  "label": "HQ",             "line1": "1 Acme Way",      "is_default_billing": true,  ... },
      { "id": "...", "type": "shipping", "label": "Main Warehouse",  "line1": "100 Industrial Dr", "is_default_shipping": true, ... },
      { "id": "...", "type": "shipping", "label": "Branch Warehouse", "line1": "200 Branch Rd",  ...                          }
    ],
    "contacts": [
      { "id": "...", "first_name": "Jane", "last_name": "Doe",   "is_primary": true,  "title": "AP",         ... },
      { "id": "...", "first_name": "John", "last_name": "Smith", "is_primary": false, "title": "Operations",  ... }
    ],
    "payment_methods": [
      { "id": "...", "type": "card", "stripe_payment_method_id": "pm_card_visa", "last_four": "4242", "is_default": true, ... }
    ],
    "tags": [
      { "id": "...", "name": "VIP",              "slug": "vip" },
      { "id": "...", "name": "Wholesale-Tier-1", "slug": "wholesale_tier_1" }
    ]
  }
}

Address field aliases

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

Default billing and shipping flags

  • Exactly one billing address may have is_default_billing: true.
  • Exactly one shipping address may have is_default_shipping: true.
  • If no address explicitly sets the flag, the first address of each type is auto-defaulted.
  • Sending more than one is_default_billing: true (or is_default_shipping: true) returns 422.

Contact role vs title

The role field in the API payload is stored internally as title. Both field names are accepted in the request body; title is returned in responses.

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, payment_methods[] will return an error; 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:
{
  "error": "missing_required_field",
  "code": "missing_required_field",
  "type": "validation_error",
  "hint": "Account 'name' is required.",
  "param": "name"
}
Common validation errors:
error codeparamdescription
missing_required_fieldnamename (or an alias) not provided
invalid_enumaccount_typeaccount_type not one of: business, individual, vendor, lead
invalid_enumaddresses[N].typeaddress type must be billing or shipping
invalid_valueaddresses[N].countrycountry must be ISO 3166-1 alpha-2
invalid_valueaddresses[].is_default_billingmore than one billing default
invalid_valueaddresses[].is_default_shippingmore than one shipping default
invalid_valuecontacts[].is_primarymore than one primary contact
missing_required_fieldpayment_methods[N].stripe_payment_method_idPM token missing
forbidden_fieldentity_identity_id may not be set in request body

Idempotency

Supply Idempotency-Key: <unique-string> to safely retry creates without duplicating records. The key is honored for 24 hours.
  • GET /v1/accounts/:id?expand[]=addresses,contacts — retrieve with children expanded
  • POST /v1/accounts/:id/addresses — add an address to an existing account
  • POST /v1/accounts/:id/contacts — add a contact to an existing account
  • POST /v1/accounts/:id/payment-methods — attach a payment method to an existing account
  • POST /v1/accounts/:id/merge — merge two accounts