Skip to content

Submissions

Submission composer in the Simplepush app with a file and a location attached

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:

bash
# block until the next submission arrives, print it, exit
sp collect --submissions --until count:1

# or watch them stream by
sp events --type submission
python
import 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())
typescript
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.

bash
# 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 ./inbox
python
async 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")
typescript
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.

bash
# 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 --submissions
python
import 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())
typescript
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.