Subscriptions
Subscriptions provide real-time updates over WebSocket connections. Use them to keep your UI synchronized with changes made by other users or systems.
Connection Setup
Subscriptions require a WebSocket connection with authentication:
import { createClient } from 'graphql-ws';
const client = createClient({ url: 'wss://api.stations.build/graphql/realtime', connectionParams: { Authorization: `Bearer ${jwtToken}`, },});
// Subscribe to updatesconst unsubscribe = client.subscribe( { query: ` subscription OnRouteUpdated($tenantId: String!) { routeUpdated(tenantId: $tenantId) { id status } } `, variables: { tenantId: 'your-tenant-id' }, }, { next: (data) => console.log('Update:', data), error: (err) => console.error('Error:', err), complete: () => console.log('Complete'), });
// Later: cleanupunsubscribe();import { ApolloClient, InMemoryCache, split, HttpLink } from '@apollo/client';import { GraphQLWsLink } from '@apollo/client/link/subscriptions';import { createClient } from 'graphql-ws';import { getMainDefinition } from '@apollo/client/utilities';
const httpLink = new HttpLink({ uri: 'https://api.stations.build/graphql', headers: { Authorization: `Bearer ${jwtToken}`, },});
const wsLink = new GraphQLWsLink( createClient({ url: 'wss://api.stations.build/graphql/realtime', connectionParams: { Authorization: `Bearer ${jwtToken}`, }, }));
const splitLink = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, httpLink);
const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(),});Station Subscriptions
stationAdded
Triggered when a new station is created.
subscription OnStationAdded($tenantId: String!) { stationAdded(tenantId: $tenantId) { id tenantId name description remotePortalId }}Triggers: addStation mutation
Access: Free, Owner, Admin, User
stationUpdated
Triggered when a station is modified.
subscription OnStationUpdated($tenantId: String!) { stationUpdated(tenantId: $tenantId) { id tenantId name description remotePortalId }}Triggers: updateStationName, updateStationDescription, unlinkStationFromRemotePortal, linkStationToRemotePortal
Access: Free, Owner, Admin, User
stationDeleted
Triggered when a station is deleted.
subscription OnStationDeleted($tenantId: String!) { stationDeleted(tenantId: $tenantId) { id tenantId }}Triggers: deleteStation mutation
Access: Free, Owner, Admin, User
Route Subscriptions
routeAdded
Triggered when a new route is created.
subscription OnRouteAdded($tenantId: String!) { routeAdded(tenantId: $tenantId) { id tenantId name status stops { id name status } track }}Triggers: addRoute mutation
Access: Free, Owner, Admin, User
routeUpdated
Triggered when a route is modified.
subscription OnRouteUpdated($tenantId: String!) { routeUpdated(tenantId: $tenantId) { id tenantId name status stops { id name status } track actionLog { action timestamp userId stopId stopName } }}Triggers: updateRoute, updateRouteName, pauseRoute, resumeRoute, cancelRoute
Access: Free, Owner, Admin, User
routeDeleted
Triggered when a route is deleted.
subscription OnRouteDeleted($tenantId: String!) { routeDeleted(tenantId: $tenantId) { id tenantId }}Triggers: deleteRoute mutation
Access: Free, Owner, Admin, User
Route Template Subscriptions
routeTemplateAdded
Triggered when a new template is created.
subscription OnRouteTemplateAdded($tenantId: String!) { routeTemplateAdded(tenantId: $tenantId) { id tenantId name stops { id name } track }}Triggers: addRouteTemplate mutation
Access: Free, Owner, Admin, User
routeTemplateUpdated
Triggered when a template is modified.
subscription OnRouteTemplateUpdated($tenantId: String!) { routeTemplateUpdated(tenantId: $tenantId) { id tenantId name stops { id name } track }}Triggers: updateRouteTemplate, updateRouteTemplateName
Access: Free, Owner, Admin, User
routeTemplateDeleted
Triggered when a template is deleted.
subscription OnRouteTemplateDeleted($tenantId: String!) { routeTemplateDeleted(tenantId: $tenantId) { id tenantId }}Triggers: deleteRouteTemplate mutation
Access: Free, Owner, Admin, User
User Subscriptions
userAdded
Triggered when a new user is added.
subscription OnUserAdded($tenantId: String!) { userAdded(tenantId: $tenantId) { id email group status enabled }}Triggers: addAdminUser, addStandardUser
Access: Free, Owner, Admin, User
userDeleted
Triggered when a user is deleted.
subscription OnUserDeleted($tenantId: String!) { userDeleted(tenantId: $tenantId) { id email }}Triggers: deleteAdminUser, deleteStandardUser
Access: Free, Owner, Admin, User
Plan & Account Subscriptions
planModified
Triggered when a plan is changed or added.
subscription OnPlanModified($id: String!) { planModified(id: $id) { id planId plan { id title price } }}Triggers: changePlan, confirmAddPlan
Access: Free, Owner, Admin, User
planCanceled
Triggered when a plan is canceled via webhook.
subscription OnPlanCanceled($id: String!) { planCanceled(id: $id) { id planId plan { title } }}Triggers: cancelPlanPeriodEndedWebhook
Access: Free, Owner, Admin, User
accountDeleted
Triggered when the account is deleted.
subscription OnAccountDeleted($id: String!) { accountDeleted(id: $id) { id }}Triggers: deleteAccount mutation
Access: Free, Owner, Admin, User
paymentMethodAdded
Triggered when a payment method is added.
subscription OnPaymentMethodAdded($tenantId: String!) { paymentMethodAdded(tenantId: $tenantId) { id paymentType last4 cardType default }}Triggers: confirmAddPaymentMethod
Access: Free, Owner
Best Practices
Handle Reconnection
WebSocket connections can drop. Implement reconnection logic:
const client = createClient({ url: 'wss://api.stations.build/graphql/realtime', connectionParams: { Authorization: `Bearer ${jwtToken}`, }, retryAttempts: 5, shouldRetry: () => true, on: { connected: () => console.log('Connected'), closed: () => console.log('Closed'), error: (err) => console.error('Error:', err), },});Cleanup Subscriptions
Always unsubscribe when components unmount:
// React exampleuseEffect(() => { const unsubscribe = client.subscribe(/* ... */); return () => unsubscribe();}, []);Filter Updates
Only subscribe to what you need. Use the returned data to filter updates relevant to your view:
client.subscribe( { query: routeUpdatedSubscription, variables: { tenantId } }, { next: ({ data }) => { // Only update if it's the route we're viewing if (data.routeUpdated.id === currentRouteId) { updateRouteState(data.routeUpdated); } }, });