tommy push API v1
Captures the push notifications your app's backend sends instead of handing them to Apple or Google, and shows each one the way a phone would: a lock-screen card with the title, subtitle and body, next to the payload exactly as it was posted. It says plainly whether a push displays anything at all, which is what most silent-push debugging comes down to, and it keeps APNs and FCM apart rather than pretending a device token and a topic are the same thing. The endpoints that feed it arrive with the providers: fcm speaks the Firebase HTTP v1 send API, apns speaks Apple's HTTP/2 provider API.
These routes read back what tommy captured, in the shape this content type
wants: filters that only mean something here, and the parts that are bytes
rather than JSON. They read from the same store as the events API, so a
client that sends and immediately fetches sees its own write, and every
entry carries the id of the event behind it.
The events API - /api/v1/events, described in its own document - is the
generic view of the same captures, and is the one to use when what you are
asserting does not depend on the content type. The fake vendor endpoints are
described nowhere here: they are the vendors' specifications, not tommy's.
This document is generated from the server's route table. It cannot describe
a route that does not exist, and CI fails if the checked-in copy stops
matching the code.
Server
/api/v1/push — This tommy's push API.
Operations
GET
/messages
Every captured push, newest first. Paging is applied after the filters, so a limit never counts what a filter excluded.
Parameters
| Name | In | Type | Description |
provider |
query |
string |
Only entries captured by this provider, such as mailjet. |
type |
query |
string |
Only entries of this event type, such as mail.message. |
search |
query |
string |
Case-insensitive substring over the summary and type. |
since |
query |
string |
RFC3339 timestamp, a duration such as 5m, or unix milliseconds. |
limit |
query |
integer |
Maximum number of entries to return. |
offset |
query |
integer |
How many entries to skip. |
displays |
query |
boolean |
Only pushes that would show something on a lock screen, or only those that would not. |
kind |
query |
string |
alert, silent or background. |
target_kind |
query |
string |
How the push was addressed: token, topic or condition. |
target |
query |
string |
Substring of the target itself. |
app |
query |
string |
The application or Firebase project the push was sent to. |
push_type |
query |
string |
The APNs push type: alert, background, voip and the rest. |
priority |
query |
string |
The priority, by level or by its raw value. |
data_key |
query |
string |
Only pushes whose data payload carries this key. |
Responses
| Status | Body | Description |
200 |
application/json · array of push.MessageEnvelope
|
Success. |
400 |
application/json · api.Error
|
A query parameter could not be parsed - a malformed since, a negative limit. |
DELETE
/messages
Clear every captured push.
Responses
| Status | Body | Description |
204 |
no body |
Done. No body. |
GET
/messages/{id}
One push, with the displays/explain verdict alongside the model.
Parameters
| Name | In | Type | Description |
id required |
path |
string |
The event id, as returned by any listing. |
Responses
| Status | Body | Description |
200 |
application/json · push.MessageEnvelope
|
Success. |
404 |
application/json · api.Error
|
No such resource, or it belongs to another plugin. |
DELETE
/messages/{id}
Delete one captured push.
Parameters
| Name | In | Type | Description |
id required |
path |
string |
The event id, as returned by any listing. |
Responses
| Status | Body | Description |
204 |
no body |
Done. No body. |
404 |
application/json · api.Error
|
No such resource, or it belongs to another plugin. |
GET
/messages/{id}/raw
The request body exactly as it arrived, as text/plain with nosniff.
Parameters
| Name | In | Type | Description |
id required |
path |
string |
The event id, as returned by any listing. |
Responses
| Status | Body | Description |
200 |
text/plain
|
Success. |
404 |
application/json · api.Error
|
No such resource, or it belongs to another plugin. |
Schemas
api.Error
| Property | Type |
error required | string |
push.Alert
| Property | Type |
badge | integer |
body | string |
category | string |
image | string |
localization | push.Localization |
sound | string |
subtitle | string |
title | string |
push.Delivery
| Property | Type |
collapse_key | string |
expiry | push.Expiry |
priority | string |
priority_raw | string |
push.Expiry
| Property | Type |
at | string (date-time) |
immediate | boolean |
raw | string |
ttl_seconds | integer |
push.Localization
| Property | Type |
body_args | array of string |
body_key | string |
title_args | array of string |
title_key | string |
push.MessageEnvelope
| Property | Type |
displays required | boolean |
explain | string |
id required | string |
message required | push.Message |
meta | object of any |
preview | string |
provider required | string |
raw_url required | string |
received_at required | string (date-time) |
title required | string |
type required | string |
url | string |
push.Payload
| Property | Type |
data required | string, base64-encoded |
format required | string |
push.Target
| Property | Type |
kind required | string |
source | string |
value required | string |