Customers and organizations

The B2B buying side on revenexx — organizations and the people inside them, roles and permissions, segments, tenant value lists, and the storefront account routes a shop front-end calls.

The customers app is the largest in the commerce domain: 13 entities and 72 capability routes under https://api.revenexx.com/v1/customers.

The shape of the domain

It is B2B-first, and two entities carry the weight:

  • An organization is the buying company — the unit a contract, a credit limit and a price list belong to.
  • A contact is a person, and the unit that logs in: one login identity, one email, one role inside its organization.

A contact without an organization is a standalone buyer, not an error — that is how B2C works here. Deleting an organization sets its contacts' organization_id to null and keeps the people.

Both are mirrored into platform auth: an organization gets an external_team_id, a contact an external_user_id. Both are written by the platform and ignored on any write you send.

Events

Publishing is automatic for the records: organization.created, .updated and .deleted, the same three for contact and address, and contact_event.created for each timeline row. The app adds contact.registered, contact.registration_approved, contact.registration_rejected, contact.blocked, organization.blocked and segment.recomputed. A rejection publishes only contact.registration_rejected, never contact.blocked as well. Copy the exact topic strings from the topic list in Cockpit's webhook endpoint form (Event types).

Two separate axes, deliberately

New integrators collapse these and it goes wrong quietly:

ColumnIs aboutValues
organizations.statusAccess — may this company's people log inactive, blocked
organizations.lifecycle_stageSales pipeline — how far along the company isOne of the tenant's own stages
organizations.delivery_blockShipments only — they may order, nothing shipsboolean
contacts.statusWhether the person may actinvited, active, blocked
contacts.registration_statusWhere their application standspending, approved, rejected
contacts.roleThe only input to permissionsOne of the tenant's roles

A prospect that may log in and a customer that may not are both ordinary states; one column cannot express that. And job_title is free text with no authority attached — the ladder is role.

Routes at a glance

AreaBase path
Companies and people/v1/customers/organizations, /contacts, /addresses
Buying metrics/v1/customers/organization_metrics, /refresh, /freshness
Timeline/v1/customers/contact_events, POST /contacts/{id}/events, POST /organizations/{id}/events
Registration decisionsPOST /v1/customers/contacts/{id}/registration/approve and /reject
RolesGET /v1/customers/roles, PUT /roles/{key}/permissions, GET /contacts/{id}/permissions, POST /principal/resolve
Segments/v1/customers/segments, /segment_members, /segments/{id}/rules/preview, /rules/recompute
Value lists/v1/customers/payment-terms, /address-types, /lifecycle-stages, /contact-event-kinds, /vocabularies
Storefront accounts/v1/customers/auth/register, /login, /logout, /me, /recovery

In this group