Respond to employer issues
Some problems in the onboarding pipeline can't be fixed by SuperAPI alone - they need a human on the employer or partner side to act. An employee abandons onboarding before a default fund could be picked, a fund rejects a membership we thought was valid, an employer's stapling connection lapses.
An employer issue is a persistent, partner-actionable record describing one of these problems. Each issue gives you a stable id to use as an idempotency key, a status lifecycle so you know when to clear a notification, a kind describing what's wrong, and a list of recommended_actions you can surface to the employer. This guide covers how to listen for issues, fetch their detail, and drive them to resolution - including a couple of patterns for notifying employers (email, support tickets, or both).
How an employer issue behaves
Before wiring anything up, it helps to understand the shape of an issue:
- It belongs to an employer, and may optionally also reference a single employee. Employer-only issues (no
employee_id) describe a problem with the employer's configuration; employee-scoped issues describe a problem with one person's onboarding. - It has a
kind- a stable string identifying what's wrong. Today the only kind isundefaulted_abandonment; more are coming (see The kinds of issue below). Treatkindas an open set and handle unfamiliar values gracefully. - It has a status lifecycle: an issue starts
openand ends eitherresolved(someone or something fixed it) orexpired(no one acted on it before its TTL elapsed, 90 days by default). Both terminal states are final - an issue is never re-opened, and a new occurrence of the same problem opens a fresh issue with a new id. - Opening is idempotent. SuperAPI keeps at most one open issue per problem, so you will not receive a flood of duplicates for the same underlying cause.
The kinds of issue
Each kind describes a distinct problem and carries its own recommended actions.
| Kind | Meaning | Typical recommended actions |
|---|---|---|
undefaulted_abandonment | An employee abandoned onboarding without a default super fund being picked, because stapling wasn't enabled for the employer. | Re-onboard the employee to capture a real fund choice; enable stapling so future abandonments can be auto-defaulted. |
We will roll out new kinds over time (the next is likely a fund rejecting a membership we sent it). Once employer issue webhooks are enabled, you automatically start receiving every kind we open for your employers - you can't subscribe to a subset, and you can't influence which kinds we open or when. That side of things is driven entirely by SuperAPI.
What you do control is your response. Whether a given issue triggers an email, a support ticket, both, or nothing at all is entirely your decision - opening an issue on our side carries no expectation that you act on it.
WARNING
A new issue kind we ship should never break your integration. Branch on the specific kinds you've built handling for, and let everything else fall through untouched until you've explicitly decided how to treat it. A new kind we ship should never break your integration or fire an unintended notification - receiving an unfamiliar kind is expected, and silently ignoring it is the correct behaviour until you choose to support it.
When you are ready to handle a kind, the issue's description and recommended_actions are always populated regardless of kind, so you can surface useful guidance to the employer without hard-coding per-kind copy.
Step 1 - Enable employer issue webhooks
Employer issue webhooks are off by default. Ask your SuperAPI contact to enable them for your partner account. Once enabled, issues are delivered to the same webhook_url you already use for the rest of your webhooks, signed with the same webhook_signing_token - there is no separate endpoint to configure.
INFO
If you aren't sure what your webhook_url is set to, you can retrieve your product settings using your product API key. See Webhook security for verifying the signature, and Work with webhooks locally for testing against your machine.
Two events are emitted under the employer_issue subject:
| Event | Fired when |
|---|---|
employer_issue_created | A new issue has been opened for one of your employers. |
employer_issue_resolved | An open issue was automatically resolved (e.g. the employee onboarded successfully and now has a valid fund membership). Not fired when you resolve an issue yourself - see Resolving an issue. |
The payload follows the standard webhook shape:
{
"subject": "employer_issue",
"event": "employer_issue_created",
"id": "c2bc0c04-6b98-4333-91a6-919f5ebc9000",
"remote_id": "c2bc0c04-6b98-4333-91a6-919f5ebc9000",
"url": "https://api.superapi.com.au/api/v1/employer-issue/c2bc0c04-6b98-4333-91a6-919f5ebc9000",
"inserted_at": "2025-06-09T03:21:00Z",
"version": "1"
}| Field | Type | Description |
|---|---|---|
subject | string | Always employer_issue. |
event | string | employer_issue_created or employer_issue_resolved. |
id | string | The primary key of the issue. Use it as an idempotency key for any notification you raise. |
remote_id | string | Mirrors id. Issues have no partner-supplied remote id, so this is the issue id. |
url | string | The fully-qualified API URL to fetch the full issue. Equivalent to GET /api/v1/employer-issue/{id}. |
inserted_at | string | When the webhook was generated (ISO 8601). |
version | string | Payload version. |
As with all SuperAPI webhooks, the payload is deliberately minimal - it tells you which issue changed and where to fetch it, and you call url to read the detail.
Step 2 - Fetch the issue
When you receive an employer_issue_created webhook, call the url from the payload to fetch the issue, authenticating with your product API key as you would any other request:
curl -X GET "https://api.superapi.com.au/api/v1/employer-issue/c2bc0c04-6b98-4333-91a6-919f5ebc9000" \
-H "Content-Type: application/json" \
-H "x-api-key: superapi_yourapikeysDZFUnrDIyNp7YTAPDcJXge"A response looks like:
{
"version": "v1",
"data": {
"id": "c2bc0c04-6b98-4333-91a6-919f5ebc9000",
"status": "open",
"kind": "undefaulted_abandonment",
"description": "Onboarding session abandoned without a default super fund (stapling not enabled).",
"employer_id": "9f1d8e2a-0b3c-4d5e-8f6a-7b8c9d0e1f2a",
"employee_id": "2b3c4d5e-6f70-4a1b-9c2d-3e4f5a6b7c8d",
"expires_at": "2025-09-07T03:21:00.000000Z",
"resolved_at": null,
"resolution_reason": null,
"expired_at": null,
"inserted_at": "2025-06-09T03:21:00.000000Z",
"updated_at": "2025-06-09T03:21:00.000000Z",
"recommended_actions": [
{
"code": "reonboard_employee",
"description": "Re-onboard this employee through SuperAPI to capture a valid super fund choice."
},
{
"code": "enable_stapling",
"description": "Enable super stapling for this employer so future abandoned sessions can be auto-defaulted."
}
]
}
}| Field | Description |
|---|---|
id | The issue's primary key. |
status | open, resolved, or expired. |
kind | What's wrong, as a stable machine-readable string. See The kinds of issue. |
description | A human-readable summary of the problem, suitable to show directly to the employer. |
employer_id | The employer this issue belongs to. Always present. |
employee_id | The affected employee, or null for employer-level issues. |
expires_at | When the issue auto-expires if no one acts on it. |
resolved_at / resolution_reason | Populated once the issue is resolved. resolution_reason is one of auto_resolved, partner_resolved, system_resolved. |
expired_at | Populated once the issue expires. |
recommended_actions | An ordered list of {code, description} actions you can surface to the employer. The code is stable and machine-readable; the description is human-readable copy you can show as-is. |
TIP
recommended_actions is computed per kind at read time, not stored. That means the guidance always reflects our current best advice for that kind of problem - you don't need to maintain your own copy of it, and you can render description directly in your UI or notification.
Listing open issues for an employer
Webhooks are the trigger to act in real time, but you can also reconcile state at any point - for example, to render an "issues" panel on an employer dashboard, or to catch up after downtime. List issues for a specific employer, most-recent first:
curl -X GET "https://api.superapi.com.au/api/v1/employer/9f1d8e2a-0b3c-4d5e-8f6a-7b8c9d0e1f2a/employer-issues?status=open" \
-H "Content-Type: application/json" \
-H "x-api-key: superapi_yourapikeysDZFUnrDIyNp7YTAPDcJXge"Pass ?status=open to restrict to currently-open issues, or omit status to return every status. Results are paginated 50 per page via ?page=N.
Step 3 - Notify the employer
This is where you turn an issue into action on the employer's side. The right channel depends on your product, but two patterns cover most cases, and they compose well.
In both cases, use the issue id as an idempotency key. Issues open idempotently on our side - you will not get duplicate employer_issue_created webhooks for the same underlying problem - but keying your own side-effects on the issue id protects you against your own retries and redeliveries.
Pattern A - Email the employer
Send the employer an email describing the problem and what to do about it. The recommended_actions descriptions are written to be shown directly, so you can render them as a checklist or a set of buttons that deep-link into the relevant part of your product (for example, a "Re-onboard this employee" button next to the reonboard_employee action).
Keep a record linking the issue id to the email you sent, so that when the matching employer_issue_resolved webhook arrives you can mark the notification as cleared (and optionally send an "all clear" follow-up).
Pattern B - Raise a ticket in the employer's support system
If your product integrates with a customer-service ticketing system (Zendesk, Freshdesk, an internal queue), an open issue maps naturally onto a ticket: create one when employer_issue_created fires, store the ticket reference against the issue id, and close the ticket when employer_issue_resolved fires.
The lifecycle alignment is the key benefit here - because each issue has exactly one open record on our side and a terminal resolved/expired state, you get a clean one-issue-to-one-ticket mapping without having to invent your own deduplication.
TIP
The two patterns combine well. A common shape is: raise a ticket so your support team has a tracked work item, and email the employer so they know to act. Both are keyed on the same issue id, and both are cleared by the same employer_issue_resolved webhook.
WARNING
Don't drop a notification just because an issue is also auto-resolvable. Many issues resolve themselves (see below), but only after the employer takes the very action you'd be notifying them about - re-onboarding the employee, enabling stapling. The notification is what prompts that action.
Step 4 - Resolve an issue
There are two ways an issue leaves the open state, and they behave differently with respect to webhooks.
Auto-resolution. Most issues resolve themselves once the underlying problem is genuinely fixed. SuperAPI re-checks open issues whenever relevant state changes - for example, when an employee completes a fresh onboarding session or gains a valid fund membership. If the world-state check for that kind now passes, the issue is closed with resolution_reason: auto_resolved and an employer_issue_resolved webhook fires. This is the path you should design for: notify on created, clear on resolved.
Manual resolution. If you've confirmed out-of-band that a problem is handled and want to clear it yourself, resolve it via the API:
curl -X PUT "https://api.superapi.com.au/api/v1/employer-issue/c2bc0c04-6b98-4333-91a6-919f5ebc9000/resolve" \
-H "Content-Type: application/json" \
-H "x-api-key: superapi_yourapikeysDZFUnrDIyNp7YTAPDcJXge"This stamps resolution_reason: partner_resolved and returns the updated issue. It is idempotent - calling it against an already-resolved issue returns the current state - and it returns 422 if the issue has already expired, since that lifecycle is final.
WARNING
A manual resolve does not fire the employer_issue_resolved webhook. The reasoning: you just resolved it, so echoing a notification back to you would be redundant. If you resolve issues manually, clear your own notification in the same code path rather than waiting for a webhook that won't arrive.
Expiry. An issue that no one acts on moves to expired after its TTL (90 days by default). Expiry does not fire a webhook. If you keep long-lived notifications open, reconcile them periodically against the list endpoint so expired issues don't linger in your UI.
Related reading
- List of webhooks for the full webhook reference, including the
employer_issuesubject. - Webhook security for verifying webhook signatures.
- Work with webhooks locally for testing webhooks against your machine.
- Activate stapling for the ATO setup steps that prevent most
undefaulted_abandonmentissues in the first place. - Lifecycle of an onboarding session for the abandonment decision flow that produces these issues.
Getting help
Stuck with something and need help? Please contact us at support@superapi.com.au or by phone on 0405 472 748 (Sam). Have you setup a shared Slack or Teams channel with us? If not, please reach out so we can provide realtime support.