Authentication
ARC has three authentication contracts. Pick one based on the transport you are using; do not mix credentials between them.
| Credential | Transport | Best for | Lifetime / rotation |
|---|---|---|---|
| ARC user JWT | GraphQL and JWT-protected REST/SSE | An integration acting as a signed-in ARC user | Access token: 1 hour. Refresh token: 7 days and rotated on use. |
| Tenant API key | /api/service/* REST routes | Server-to-server catalog, customer and document reads, quotes, orders, and product imports | Created per organization; optional expiry and IP allowlist; full key shown once. |
| MCP OAuth token | /mcp | AI agents and MCP clients | Access token: 1 hour. Refresh tokens rotate and are bound to the MCP origin. |
Tenant API keys: machine integrations
An organization administrator or manager with API access creates a key in Settings → API keys. The API key feature is plan-gated; ask your Growmax account manager if the setting is unavailable.
A key has:
- a
gm_live_prefix followed by 48 hexadecimal characters; - a tenant scope — one key can access only the organization that created it;
READ_ONLYorREAD_WRITEscope (READ_ONLYis the default);- optional expiry (
expiresAtorexpiresInDays, 1–3650 days); - optional IPv4, IPv6, or CIDR allowlist;
- a
rateLimit: requests per minute, an integer from 1 to 10000, 100 by default, enforced per key; - a friendly name and masked prefix for inventory and rotation.
The raw key is returned only by createApiKey at creation time. ARC stores a hash, not the raw credential. If it is lost, revoke it and create a replacement.
Send an API key
curl --fail-with-body \
--header "Authorization: Bearer $ARC_API_KEY" \
"$ARC_API_URL/api/service/payment-terms"
The organization is taken from the validated key. There is no supported organizationId header, query parameter, or body field that changes the tenant.
READ_ONLY keys can call every read route: the catalog, stock, reference lists, customers, sales-order and quote status, and import status and preview. Creating quotes, creating orders, and mutating imports require READ_WRITE. See Service REST API.
Rotate safely
- Create a replacement key first.
- Deploy the replacement to your secret manager.
- Verify a read request and one non-destructive workflow in the target tenant.
- Revoke the old key in Settings → API keys.
- Remove the old value from CI, logs, local shells, and incident notes.
The key's rateLimit is enforced: every request made with the key counts against it, in a fixed one-minute window. Over the limit, ARC answers 429 with code API_KEY_RATE_LIMITED and a Retry-After header. The global per-IP throttle also still applies. A key cannot be edited, so to change its limit, create a replacement key and rotate. Build bounded concurrency, backoff, and retry handling into the integration, and agree higher throughput with Growmax before a large migration. See Rate limits and request limits.
User JWTs: GraphQL and user-scoped REST
GraphQL login is a public mutation that resolves the tenant from the request's subdomain (or the tenant host) and returns an access/refresh pair. The access token is sent as a normal Bearer token.
mutation Login($input: LoginInput!) {
login(loginInput: $input) {
accessToken
refreshToken
expiresIn
tokenType
organizationId
user { id email firstName lastName }
}
}
{
"input": {
"email": "developer@example.com",
"password": "<password>",
"subdomain": "<tenant-subdomain>"
}
}
Authorization: Bearer <accessToken>
Content-Type: application/json
Access tokens expire after one hour. Refresh before expiry with the refreshToken mutation and replace both stored tokens because refresh tokens rotate:
mutation Refresh($input: RefreshTokenInput!) {
refreshToken(refreshTokenInput: $input) {
accessToken
refreshToken
expiresIn
tokenType
}
}
JWT access is permission-driven. A valid login does not grant every resolver: the user's current ARC permissions are loaded and checked on each authenticated operation. This is useful for staff-facing applications, but a long-lived machine integration should normally use a tenant API key and the documented service routes instead of automating a human password.
MCP OAuth
MCP clients do not use API keys or ARC JWTs directly. They discover OAuth metadata from the host, use authorization code + PKCE (S256), show the seller a consent page, and receive a token bound to one user, one organization, and the exact /mcp origin.
See MCP for the handshake, refresh/revocation behavior, tool filtering, and the propose → human approval → apply write contract.
Credential safety
- Keep all credentials in a server-side secret manager.
- Never put an API key, JWT, refresh token, or MCP token in browser JavaScript, a mobile binary, a Git repository, an issue, or a request log.
- Do not send
organizationIdfrom a client and do not trust an organization id returned by a caller's body when selecting a tenant. - Treat a 401 as an authentication or credential configuration problem; do not retry it indefinitely.
- Revoke a compromised key immediately. Revoking a key (
revokeApiKey) takes effect on the next request made with it.