Skip to content

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 updates
const 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: cleanup
unsubscribe();

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 example
useEffect(() => {
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);
}
},
}
);