Skip to main content

Make your first GraphQL request

This walkthrough uses an ARC user JWT. It is the quickest way to explore the GraphQL schema with a real seller account. For a machine-to-machine connector, use the service API instead.

Prerequisites​

You need:

  • an ARC API host, supplied by the organization administrator;
  • an active ARC staff user in that organization;
  • the tenant subdomain if the host serves more than one tenant;
  • curl, or any HTTP client that can send JSON POST requests.

Set local variables. Keep the password out of shell history in a real environment.

export ARC_API_URL="https://<arc-host>"
export ARC_EMAIL="developer@example.com"
export ARC_PASSWORD="<password>"
export ARC_SUBDOMAIN="<tenant-subdomain>"

1. Exchange credentials for a JWT​

jq -n \
--arg email "$ARC_EMAIL" \
--arg password "$ARC_PASSWORD" \
--arg subdomain "$ARC_SUBDOMAIN" \
'{query: "mutation Login($input: LoginInput!) { login(loginInput: $input) { accessToken refreshToken expiresIn tokenType organizationId user { id email } } }", variables: {input: {email: $email, password: $password, subdomain: $subdomain}}}' \
| curl --fail-with-body --request POST "$ARC_API_URL/graphql" \
--header "Content-Type: application/json" \
--data @-

The response contains an access token and a refresh token. Store them in memory for this walkthrough; store them in a server-side secret/session store in a real integration.

{
"data": {
"login": {
"accessToken": "<access-token>",
"refreshToken": "<refresh-token>",
"expiresIn": 3600,
"tokenType": "Bearer",
"organizationId": "<organization-id>",
"user": { "id": "<user-id>", "email": "developer@example.com" }
}
}
}

If the workspace enforces two-factor authentication for this user, login does not return tokens. Instead the response carries a partial-auth state: requires2FA: true with a userId and a single-use tempToken when the user has 2FA set up, or requires2FASetup: true when the user has not enrolled yet (finish enrolment in the ARC console first). To complete a requires2FA login, call verifyTwoFactor(input: { tempToken, token, userId }) with the current authenticator code as token; it returns the same token fields as login. Alternatively, repeat login with the code in the twoFactorToken field of LoginInput. Repeated failures can temporarily lock the account, so back off between attempts rather than retrying in a loop.

For a copy-paste-friendly shell, set the token from a trusted JSON parser rather than using grep or string slicing:

export ARC_ACCESS_TOKEN="<access-token-from-login>"

2. Read the catalog​

ARC's product list uses an opaque cursor, limit, nextCursor, and hasNextPage. The field is items, not edges/nodes like some GraphQL APIs.

curl --fail-with-body --request POST "$ARC_API_URL/graphql" \
--header "Authorization: Bearer $ARC_ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data @- <<'JSON'
{
"query": "query Products($cursor: String, $limit: Int!, $filter: ProductFilterInput) { products(cursor: $cursor, limit: $limit, filter: $filter) { items { id name sku status variantCount variants { id sku salePrice isActive } } nextCursor hasNextPage totalCount } }",
"variables": {
"cursor": null,
"limit": 20,
"filter": { "status": ["ACTIVE"], "search": "" }
}
}
JSON

To get the next page, send the returned nextCursor as cursor:

{ "cursor": "<opaque-next-cursor>", "limit": 20 }

Do not decode, sort, manufacture, or persist assumptions about cursor contents. Persist the cursor only as a checkpoint for your own sync job.

3. Inspect a price before creating a document​

The schema exposes a small convenience query for quantity pricing:

query VariantPrice($variantId: ID!, $quantity: Int!, $customerTier: String) {
calculateVariantPrice(
variantId: $variantId
quantity: $quantity
customerTier: $customerTier
) {
isValid
originalPrice
price
discount
tierName
}
}

Use API-returned prices and totals. Do not reproduce the pricing waterfall in your application. Price resolution can depend on quantity tiers, discounts, promotions, UOM, partner context, currency, and tenant configuration.

4. Handle the response correctly​

A GraphQL HTTP response can contain both data and errors. Check errors even when the HTTP status is 200. For example, a user whose role lacks sales:quote:read who sends query { quotes { id quoteNumber status } } receives:

{
"data": null,
"errors": [
{
"message": "Missing required permission: sales:quote:read",
"path": ["quotes"],
"extensions": { "code": "FORBIDDEN" }
}
]
}

quotes returns a non-null list, so when it fails GraphQL cannot put null in its place and data itself becomes null. A nullable root field fails as "data": { "<field>": null } instead. The error object carries more keys than shown, such as locations and extensions.originalError. Read errors[].extensions.code for machine handling and preserve the message for diagnostics. Never log the Authorization header.

Next steps​