Skip to main content
Version: 0.62.0-rc.1267

GraphQL Integration

This guide covers integrating client applications with Lana's GraphQL APIs.

API Endpoints​

Lana exposes three GraphQL APIs, each with its own identity and authorization context:

APIPurposeTypical URL
Admin APIAdministrative operations — customers, credit, accountinghttps://admin.your-instance.com/graphql
Customer APICustomer-facing operations — account info, facility statushttps://app.your-instance.com/graphql
Partner APIPartner-scoped operationshttps://partner.your-instance.com/graphql

Making Requests​

With curl​

curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "{ customers(first: 10) { edges { node { customerId status level } } } }"}' \
https://admin.your-instance.com/graphql

With JavaScript (Apollo Client)​

npm install @apollo/client graphql
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

const httpLink = createHttpLink({
uri: 'https://admin.your-instance.com/graphql',
});

const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
authorization: `Bearer ${getAccessToken()}`,
},
}));

const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});

With Python​

import requests

url = "https://admin.your-instance.com/graphql"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}

query = """
query {
customers(first: 10) {
edges {
node {
customerId
status
level
}
}
}
}
"""

response = requests.post(url, json={"query": query}, headers=headers)
data = response.json()

Pagination​

Lana APIs use cursor-based pagination following the Relay specification:

query GetCustomers($first: Int!, $after: String) {
customers(first: $first, after: $after) {
edges {
cursor
node {
customerId
status
level
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}

To fetch the next page, pass the endCursor value as the after parameter.

Error Handling​

Check both the top-level errors array and the operation's payload. Typed mutations return expected business rejections as a union under data, not as top-level GraphQL errors:

mutation FreezeCustomer($input: CustomerFreezeInput!) {
customerFreeze(input: $input) {
__typename
... on CustomerFreezePayloadSuccess {
customer {
customerId
status
}
}
... on CustomerFreezePayloadError {
code
}
}
}

The typed fault boundary uses these top-level error extensions:

extensions.codeextensions.retryableMeaning
UNAUTHORIZEDfalseThe subject is not authorized
UNAVAILABLEtrueA transient dependency failure
INTERNALfalseAn internal failure

Query domain rejections and validated scalars can return operation-specific codes with retryable: false. Some operations still use legacy error paths, so do not assume every error has these extensions. Invalid or expired tokens can also be rejected at the HTTP authentication layer before GraphQL execution.

Inspect the current operation's payload types in the API reference, handle HTTP failures separately, and do not blindly retry mutations: reconcile their result or use the operation's idempotency contract before retrying.

Required Headers​

Authorization: Bearer <access-token>
Content-Type: application/json

API References​