Skip to content

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 is undefaulted_abandonment; more are coming (see The kinds of issue below). Treat kind as an open set and handle unfamiliar values gracefully.
  • It has a status lifecycle: an issue starts open and ends either resolved (someone or something fixed it) or expired (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.

KindMeaningTypical recommended actions
undefaulted_abandonmentAn 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:

EventFired when
employer_issue_createdA new issue has been opened for one of your employers.
employer_issue_resolvedAn 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:

json
{
  "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"
}
FieldTypeDescription
subjectstringAlways employer_issue.
eventstringemployer_issue_created or employer_issue_resolved.
idstringThe primary key of the issue. Use it as an idempotency key for any notification you raise.
remote_idstringMirrors id. Issues have no partner-supplied remote id, so this is the issue id.
urlstringThe fully-qualified API URL to fetch the full issue. Equivalent to GET /api/v1/employer-issue/{id}.
inserted_atstringWhen the webhook was generated (ISO 8601).
versionstringPayload 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:

bash
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:

json
{
  "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."
      }
    ]
  }
}
FieldDescription
idThe issue's primary key.
statusopen, resolved, or expired.
kindWhat's wrong, as a stable machine-readable string. See The kinds of issue.
descriptionA human-readable summary of the problem, suitable to show directly to the employer.
employer_idThe employer this issue belongs to. Always present.
employee_idThe affected employee, or null for employer-level issues.
expires_atWhen the issue auto-expires if no one acts on it.
resolved_at / resolution_reasonPopulated once the issue is resolved. resolution_reason is one of auto_resolved, partner_resolved, system_resolved.
expired_atPopulated once the issue expires.
recommended_actionsAn 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:

bash
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:

bash
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.

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.

The future of super is embedded