Add-ons: Technical reference
Technical reference for building a Storeganise Add-on, covering webhook structure, authentication, data fetching patterns, and access control conventions.Your endpoint must respond with a Use For guidance on making efficient API requests, see API best practices.
Note: For the full development process and partnership overview, see the Add-on: Partner guide.
Webhook event structure
Anatomy of a webhook POST request
When an event occurs in Storeganise, your Add-on receives a POST request containing four fields:type: the event that triggered the webhook, for exampleuser.createdorjob.unit_moveIn.completeddata: an object containing relevant IDs for the event, for example{ userId }or{ jobId }. IDs vary depending on the event type.apiUrl: the base URL for making API calls back to the operator's Storeganise instanceaddonId: your Add-on's unique ID for that installation. Use this to retrieve the operator's configuration and credentials.
// Get the event data from the request body
const {
type, // The event type, e.g. `user.created`, `job.unit_moveIn.completed`
data = {}, // An object of event data; contains IDs depending on the event type, e.g. userId, jobId
apiUrl, // The base URL of Storeganise API
addonId, // The ID of the addon which called this webhook; the addon contains the business-specific customFields/settings
} = req.body;
200 status within 30 seconds. For a full list of available events, see Webhooks.Authentication
How Add-on authentication works
Each webhook request includes theapiUrl and addonId for the operator's installation. You combine the addonId with your sgApiKey to authenticate API requests back to Storeganise. The sgApiKey is not a global key; it comes from the operator's custom fields, set when they installed and configured your Add-on.Auth header format
Authorization: Addon ${addonId}|${sgApiKey}
Where sgApiKey comes from
When an operator installs your Add-on, they enter their credentials into the custom fields you defined. Fetch the Add-on record usingaddonId to retrieve those fields, including the sgApiKey for that operator.Fetching data from the API
Why webhooks contain IDs, not full objects
Webhook payloads are intentionally lightweight. Storeganise sends only the IDs relevant to the event, and your handler fetches the full object data it needs via the API. This keeps payloads fast and gives you control over what data you retrieve.StoreganiseApi helper pattern
Use this helper to make authenticated requests from your webhook handler:function StoreganiseApi({ apiUrl, addonId }) {
return function fetchSg(path, {
method = 'GET',
body,
} = {}) {
return fetch(`${apiUrl}${path}`, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Addon ${addonId}|${config.sgApiKey}`,
},
body: body && JSON.stringify(body),
})
.then(async response => {
const data = await response.json().catch(() => ({}));
if (!response.ok) {
console.error(`Error calling ${method} ${apiUrl}${path}: ${response.status} ${response.statusText}`);
const err = Object.assign(new Error(), data.error);
err.status = response.status;
throw err;
}
return data;
});
}
}
Fetching Add-on details
Fetch the Add-on record to access the operator's custom fields, including their credentials:const fetchSg = StoreganiseApi(req.body); const addon = await fetchSg(`/v1/admin/addons/${addonId}`);
addon.customFields to retrieve the credentials or configuration the operator entered during installation.Handling a move-in event
Use the IDs from the webhook payload to fetch the full record. For example, on a move-in event:const { unitRentalId } = data; const rental = await fetchSg(`/v1/admin/unit-rentals/${unitRentalId}?include=unit,owner,customFields`); // Now call your remote API using addon.customFields for the credentials, and rental data to sync
Tracking installations across operators
Why /v1/admin/addons won't give you a cross-account view
TheGET /v1/admin/addons endpoint lists Add-ons from the perspective of a single operator account. It is not designed for Add-on developers to discover all installations across different accounts.Instead, track installations by recording the apiUrl and addonId from incoming webhook requests. Together these identify a specific installation.Using addon.dailyEvent.started as a daily ping
Subscribe to theaddon.dailyEvent.started event. This fires at 3:00 AM daily for each enabled instance of your Add-on. By logging these events you can maintain an up-to-date list of active installations and detect when an Add-on has been disabled or removed, as the daily ping will stop arriving.Using addon.installed for new installation events
Subscribe toaddon.installed to be notified immediately when a new operator installs your Add-on.Technical requirements
Your Add-on must meet these requirements before it can be certified for production.Required capabilities:- Webhook endpoint that accepts POST requests with Storeganise event data
- OAuth flow implementation for authenticating with your service
- Comprehensive error handling and retry logic for network failures and API errors
- Multi-site support tested, if your Add-on applies to operators managing multiple facilities
- Webhook responses must complete within 30 seconds
- Handle API rate limits appropriately and minimise the number of requests where possible
- Implement proper error recovery for 4xx and 5xx API responses
Quality standards
Your Add-on should:- Work reliably for all supported use cases
- Handle errors gracefully with clear feedback to operators
- Follow Storeganise UI and UX patterns
- Respond to webhooks within the timeout limit
- Make efficient use of the Storeganise API
- Use clear, jargon-free language
- Include step-by-step instructions with screenshots
- Explain all configuration parameters
- Provide troubleshooting guidance for common issues
- Follow Storeganise helpdoc formatting standards
Common technical pitfalls
- Webhook responses that exceed the 30-second timeout
- Insufficient error handling for API failures and network errors
- Rate limiting not properly implemented, causing excessive API requests
- Not handling all relevant webhook events for your integration type
- Assuming
GET /v1/admin/addonsprovides a cross-account view of installations
Access control conventions
If you're building an access control integration, follow these conventions for consistency across the platform.Note:{prefix} is your Add-on name, for example pti , bearbox , or noke .Unit name override (prefix_id)
Ifunit.customFields.{prefix}_id is set, it overrides unit.name as the unit identifier synced to your remote API.Skipping sync (prefix_id set to NONE)
Ifunit.customFields.{prefix}_id is set to NONE , synchronisation is skipped for that unit.Overlocking status (prefix_overlocked)
Useunit.customFields.{prefix}_overlocked (Boolean) for the overlock status of the unit.Access codes (prefix_accessCode, prefix_pinCode)
Useunit.customFields.{prefix}_accessCode , {prefix}_pinCode , or another relevant name for access codes. Generate codes randomly with at least six digits.Resync trigger (prefix_resync)
Useunit.customFields.{prefix}_resync (Boolean) to trigger a manual resync for a specific unit.Jump to
Related articles
API FAQ
Webhooks
API best practices
Add-on: Partner guide