Overview

A Submission represents a single attempt to lodge a pay event to the ATO. Every time you POST /pay_events/:id/submit, a Submission row is created and tracked through its lifecycle. Submissions are read-only via the API — you create them implicitly by submitting a pay event.

This is the resource you poll (or receive webhooks about) to know when the ATO has accepted or rejected your lodgement.

The Submission object

Common fields

Field Type Notes
id integer
pay_event_id integer Parent pay event
employer_id integer
employer_name string Computed
status string pending, sent, accepted, rejected, error
environment string evte or production
event_type string pay_event, update_event, full_file_replacement
is_finalisation boolean True if this is an EOFY finalisation
message_id string ATO message ID (nullable until sent)
sent_at string (ISO 8601, nullable) When we sent it to the ATO
response_received_at string (ISO 8601, nullable) When the ATO replied
created_at string (ISO 8601)

Detail fields (on GET /:id)

Field Type Notes
correlation_id string Our internal correlation ID for request tracing
submission_id string ATO's returned submission receipt number
ato_status string Raw status from the ATO (accepted, rejected, etc.)
error_messages array Parsed error messages if the submission was rejected
pay_event object Nested summary: period, payment_date, totals, employee count

Status lifecycle

pending ──────► sent ────────┬─► accepted
                             ├─► rejected
                             └─► error
Status Meaning
pending Created but not yet sent to the ATO
sent Dispatched to the ATO gateway; awaiting acknowledgement
accepted ATO confirmed receipt and passed validation
rejected ATO validation failed — see error_messages
error Something broke in our infrastructure (signing, network, etc.) — typically retryable

Endpoints

List submissions

GET /api/v1/submissions

Scopes: submissions:read

Query parameters:

Param Default Notes
employer_id Filter to one employer
status Filter by status
page / per_page 1 / 25

Response: 200 OK with an array of compact Submission objects.

curl "https://stp.beeswaxapp.com/api/v1/submissions?employer_id=12&status=accepted" \
  -H "Authorization: Bearer stp_test_..."
[
  {
    "id": 501,
    "pay_event_id": 300,
    "employer_id": 12,
    "employer_name": "Acme",
    "status": "accepted",
    "environment": "evte",
    "event_type": "pay_event",
    "is_finalisation": false,
    "message_id": "ATO-MSG-12345",
    "sent_at": "2026-04-09T11:33:41Z",
    "response_received_at": "2026-04-09T11:33:58Z",
    "created_at": "2026-04-09T11:33:40Z"
  }
]

Get a submission

GET /api/v1/submissions/:id

Scopes: submissions:read

Response: 200 OK with full detail including ato_status, error_messages, and nested pay_event summary.

curl https://stp.beeswaxapp.com/api/v1/submissions/501 \
  -H "Authorization: Bearer stp_test_..."
{
  "id": 501,
  "pay_event_id": 300,
  "employer_id": 12,
  "employer_name": "Acme",
  "status": "accepted",
  "environment": "evte",
  "event_type": "pay_event",
  "is_finalisation": false,
  "message_id": "ATO-MSG-12345",
  "sent_at": "2026-04-09T11:33:41Z",
  "response_received_at": "2026-04-09T11:33:58Z",
  "created_at": "2026-04-09T11:33:40Z",
  "correlation_id": "corr-abcdef12",
  "submission_id": "ATO-RECEIPT-999",
  "ato_status": "accepted",
  "error_messages": null,
  "pay_event": {
    "period_label": "1 Apr – 14 Apr 2026",
    "payment_date": "2026-04-14",
    "total_gross": 4820.00,
    "total_tax": 1145.00,
    "employee_count": 1
  }
}

Handling rejected submissions

When a submission is rejected, the error_messages field contains the parsed list of issues from the ATO. Example:

{
  "status": "rejected",
  "ato_status": "rejected",
  "error_messages": [
    "CMN.ATO.GEN.428002: Invalid ABN format",
    "CMN.ATO.PAYEVNT.000045: Employee TFN is missing or invalid"
  ]
}

Each error message starts with the ATO error code (e.g. CMN.ATO.GEN.428002). These codes are documented in the ATO STP business implementation guide.

To fix and re-submit:

  1. Inspect the error messages and identify the root cause
  2. Update the relevant Employer or Employee data
  3. Create a new pay event (or use an update_event type) and submit it
  4. The old rejected submission remains in your audit history for reference

Polling vs webhooks

Prefer webhooks. Polling submissions just to find out when an async job has finished is wasteful. Set up a webhook endpoint subscribed to submission.accepted, submission.rejected, and submission.error events, and you'll be notified the instant the ATO responds.

If you must poll (e.g. for a one-off CLI tool), hit GET /api/v1/submissions?employer_id=X&status=sent every 10–30 seconds and check which have changed state. Don't poll more than once per second — you'll eat your rate limit for nothing.

Resubmitting

There is no "resubmit" endpoint for submissions. To lodge the same data again:

  1. Create a new pay event (or an update_event type targeting the original)
  2. Add the items
  3. Mark ready and submit

The new pay event creates a fresh Submission record with its own ATO message ID.

Environment isolation

Like all resources, submissions are scoped to the token's environment. Test tokens only see EVTE submissions, live tokens only see production submissions.

Retention

We retain submission records for at least 12 months from the sent_at date on paid plans, as required by the ATO Operational Security Framework. Submissions are never deleted automatically — you can always look back through your lodgement history. If you cancel your subscription, data is retained for 90 days before soft-deletion.