Submissions

Submissions turn the phone into a one-tap endpoint for any script, server, or workflow. Nobody has to ask first: open the app, pick a submission type, and send. A listener receives it within seconds. You can submit plain text, a photo straight from the camera, raw voice audio, your GPS location, or an arbitrary file.
Receiving submissions
Receiving requires your API token (app settings, under API Token). Pick whichever consumer fits:
# block until the next submission arrives, print it, exit
sp collect --submissions --until count:1
# or watch them stream by
sp events --type submissionimport asyncio
from simplepush import Client
client = Client(api_token="YOUR_API_TOKEN", passwords="personal-secret")
async def main():
async for s in client.submissions():
if s.body:
print("text:", s.body.text)
if s.photo:
await s.photo.save("./inbox")
asyncio.run(main())import { Client } from "@simplepush/sdk";
const client = new Client({ apiToken: "YOUR_API_TOKEN", passwords: "personal-secret" });
for await (const s of client.submissions()) {
if (s.body) console.log("text:", s.body.text);
if (s.photo) await s.photo.save("./inbox");
}Getting the file
A photo, voice clip, or file is stored, not inlined: what arrives is metadata plus a way to fetch the bytes. In the SDKs that is a bound handle with save() and read(), which fetch and decrypt when you hold the key. On the CLI, --save-files does the same and stamps the saved location onto the JSON line as path. download_url() presigns a URL for your own HTTP stack instead, and serves raw ciphertext for an encrypted file.
# download attachments into ./inbox as they stream in
sp collect --submissions --save-files ./inbox
# or fetch one afterwards: submission id + file id, both off the JSON line
sp download sbm_0193... sbf_0193... --out ./inboxasync for s in client.submissions():
if s.file:
print(s.file.filename, s.file.content_type, s.file.size)
path = await s.file.save("./inbox") # a directory keeps the file's own name
print("saved to", path)
data = await s.file.read() # or keep the bytes in memory
if s.audio:
await s.audio.save("./inbox")for await (const s of client.submissions()) {
if (s.file) {
console.log(s.file.filename, s.file.contentType, s.file.size);
const path = await s.file.save("./inbox");
console.log("saved to", path);
const data = await s.file.read();
}
if (s.audio) await s.audio.save("./inbox");
}A submission carries each kind independently, so check photo, file, audio, and location separately rather than assuming one.
Receiving as an organization
When the sender is an org member, the submission goes to the organization's stream instead of a personal one. Every member's submissions arrive on that one stream, each carrying the member as its actor, so a single consumer covers the whole team.
# once per machine: the CLI session doubles as the org credential
sp auth login
# no --api-token, so collect reads the organization's stream
sp collect --submissionsimport asyncio
from simplepush import OrgClient
org = OrgClient(api_key="YOUR_ORG_API_KEY",
master_key="BASE64_MASTER_KEY", master_key_version=1)
async def main():
async for s in org.submissions():
member = (s.raw.actor or {}).get("name")
print(member, s.body.text if s.body else None)
asyncio.run(main())import { OrgClient } from "@simplepush/sdk";
const org = new OrgClient({
apiKey: "YOUR_ORG_API_KEY",
orgMasterKey: masterKeyBytes, orgMasterKeyVersion: 1,
});
for await (const s of org.submissions()) {
console.log(s.actor?.name, s.body?.text);
}Encryption
In the app settings under Encryption, set your Personal Password and turn on submission encryption. Everything you submit is then sealed on the device before upload. On the receiving side, supply that same password as your personal password (the bare string in passwords, or a bare -p secret on the CLI) and payloads decrypt transparently.
Org members encrypt under the shared org master key instead, so there is no personal password to configure. Pass the key to an OrgClient to decrypt what arrives; sp collect reads it from the local vault and asks for the passphrase the first time it runs on a terminal. See Encryption.