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:
- Inspect the error messages and identify the root cause
- Update the relevant Employer or Employee data
- Create a new pay event (or use an
update_eventtype) and submit it - 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:
- Create a new pay event (or an
update_eventtype targeting the original) - Add the items
- 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.