Skip to content

Approve or deny, from your phone ​

Your script needs a human decision. Send it as an interactive task with choices. The answer comes back in seconds. No polling, no webhook to host.

Good for: AI agents that need approval before touching production, deploy bots, oncall triage, and any flow that pauses until a human decides.

bash
export SP_API_TOKEN="your-token"

sp task -t deploys --title "Deploy to production?" \
  -c "Commit abc123 is ready;Approve,Deny,Hold" \
  --wait
python
import asyncio
from simplepush import Client, ChoiceInput, TaskCompleted

client = Client(api_token="YOUR_API_TOKEN")

group = client.send_task(
    topic="deploys",
    title="Deploy to production?",
    content="Commit abc123 is ready",
    inputs=[ChoiceInput(options=["Approve", "Deny", "Hold"])],
)

async def main():
    async for g in group.inputs(timeout=600):
        if isinstance(g.item, TaskCompleted):
            print("User chose:", g.item.uploads[0].value)
            break
    await client.aclose()

asyncio.run(main())
ts
import { Client } from '@simplepush/sdk'

const client = new Client({ apiToken: 'YOUR_API_TOKEN' })

const group = await client.sendTask({
  topic: 'deploys',
  title: 'Deploy to production?',
  content: 'Commit abc123 is ready',
  inputs: [{ type: 'choice', options: ['Approve', 'Deny', 'Hold'], required: true }],
})

for await (const { item } of group.inputs({ idleMs: 600_000 })) {
  if (item.kind === 'taskCompleted') {
    const choice = item.uploads.find((u) => u.kind === 'choice')
    console.log('User chose:', choice?.value)
    break
  }
}
client.close()
bash
ANSWER=$(curl -s -X POST https://api.simplepu.sh/v1/tasks \
  -H "API-Token: $SP_API_TOKEN" \
  -H "Topic: deploys" \
  -H "Title: Deploy to production?" \
  -H "Choice-Input: Commit abc123 is ready;Approve,Deny,Hold" \
  -H "Wait: true" | tr -d '\n')

echo "User chose: $ANSWER"

A single-select choice renders as tappable buttons on the push notification. The recipient can answer without opening the app.

The --wait flag and the Wait: true header block until the first answer. That works well for quick approvals. For anything that takes longer, collect over a resumable stream instead. Pipe the send into sp collect (sp task ... --format json | sp collect) or use the SDK streams shown above.