Skip to main content

Tenancy and permissions

ARC is a multi-tenant system. Every seller workspace is an Organization, and every tenant-owned record belongs to exactly one organization. Your integration must treat the credential's organization as part of the connection, not as a request parameter.

The tenant comes from the credential​

CredentialHow ARC chooses the organization
User JWTThe signed JWT contains the organization claim; ARC checks it against the active user.
Tenant API keyThe key record belongs to one organization; the service guard derives the organization from that record.
MCP OAuth tokenThe authorization grant records one user and one organization; the MCP adapter carries that context into every tool call.

Do not send or trust any of these as tenant selectors:

  • organizationId in a body, query string, or GraphQL argument;
  • an X-Organization-Id header;
  • a tenant id copied from a browser or user-controlled form;
  • an MCP tool argument named tenant or organization.

If a resource id belongs to another organization, ARC should not disclose its existence. Treat a not-found result as not found for your current tenant.

Authorization is separate from authentication​

A valid credential answers who is calling and which organization is active. Authorization answers what that caller can do.

  • GraphQL user operations use ARC's permission strings and, for some admin operations, role and plan gates.
  • API keys work only on the /api/service/* routes; GraphQL does not accept them. On those routes a key acts as the user who created it. Reads need that user's current read permission for the resource (see the table in the Service API reference); if the creator loses the permission, the key's read is refused with 403 Missing required permission: <permission>, and if the creator is deactivated the key stops working (401). Writes need a READ_WRITE key and the plan's API access. For writes, ARC does not yet check whether the user who created the key holds sales:quote:create or sales:sales_order:create; that user is recorded as the actor, and on the order route their permissions are passed into order creation for override checks (for example a price or credit-limit override). They are not a gate on the route itself. Treat a READ_WRITE key as able to create any quote or sales order in the workspace, and store it accordingly.
  • Within what its creator may read, a key reads the whole workspace. The service read routes apply no sales-rep visibility scope, and the quote list returns every quote, not only those created by the key's creator. Mint keys from a dedicated integration user whose role holds only the read permissions the integration needs, and rotate the key when that person leaves.
  • MCP first filters the visible tool catalogue by OAuth scopes, the user's current ARC permissions, and plan features, then re-checks authorization at execution time.

Permissions can change without minting a new JWT because ARC resolves effective permissions from the current user/role assignments. Do not treat a previously successful operation as proof that a later operation is authorized.

Design your connection model​

Store a connection record like this in your system:

arcHost exact host used for the tenant
organizationId observed from the authenticated response; never user-editable
credentialReference secret-manager reference, not the token itself
credentialType api_key | jwt_session | mcp_oauth
lastSuccessfulRequestAt operational metadata
schemaOrContractVersion the schema snapshot or docs version you tested against

For API keys, keep the host and key together in your records. The key alone selects the workspace: ARC does not compare the key's organization with the request host, so a key sent to another host still acts on the key's own workspace. It never reaches another tenant's data.

Least privilege​

  • A READ_ONLY key can call every GET route under /api/service/*: the catalog, stock, units of measure, payment terms, warehouses, customers, the status of sales orders and quotes, and bulk-import status and preview. See Read endpoints. It cannot create or change anything.
  • Use READ_WRITE only for the service operations that must create or mutate data: creating quotes and sales orders, and running bulk imports. A READ_WRITE key can also read.
  • Data that has no service route, such as invoices and payments, still needs a GraphQL user. Keys are not accepted on GraphQL.
  • For GraphQL users, grant only the module/resource/action permissions the integration needs.
  • For MCP, request only read unless the agent genuinely needs to propose or apply writes.

Data visibility is not data ownership​

A user can have a role that limits which representatives, customers, or documents they can see. The generated schema tells you that a field exists; the authenticated caller's permissions and data-visibility scope still decide whether it returns data.

Build integrations to handle:

  • an empty list caused by legitimate scope, not only by missing data;
  • FORBIDDEN when the permission is absent;
  • a resource becoming unavailable after a role, status, or organization change;
  • a tenant plan not including a feature.

Security checklist​

  • Never accept an organization id from an end user as authority.
  • Never use a platform superadmin credential for an ordinary tenant integration.
  • Never put an ARC token in client-side code.
  • Never log complete Authorization headers, API keys, refresh tokens, or MCP tokens.
  • Reconcile access after an administrator revokes a key or disables a user.

Next: Errors, pagination, and idempotency.