A val.town webhook that schedules atproto XRPC requests to be replayed at a future time.
Clients POST a request body to the val (with an app password as a Bearer token); the request is stored, and a cron job fires it within 15 mins after the requested time.
POST /xrpc/me.byjp.atproto.repo.delayedRequest Authorization: Bearer <app-password> Content-Type: application/json
The app password is validated against the PDS for request.repo at submission time (via com.atproto.server.createSession). The cron job re-creates a session at execution time and uses the resulting accessJwt to call the target XRPC procedure.
| field | type | notes |
|---|---|---|
delay.key | string | Stable, client-chosen ID. Re-using the same key replaces the pending request; omitting request deletes it. |
delay.executeAfter | string | When to fire. See formats below. |
request | object | The XRPC request to send. Must carry a $type field naming the procedure. |
Supported request.$type values:
com.atproto.repo.putRecordcom.atproto.repo.deleteRecord
- ISO 8601 timestamp —
"2026-05-21T10:00:00.000Z" - ISO 8601 timestamp + additional delay —
"2026-05-21T10:00:00.000Z/PT30M" - Unix ms —
"1779354000000" - Unix ms + additional delay ms —
"1779354000000+60000"
Delete at://did:plc:ephkzpinhaqcabtkugtbzrwu/fm.teal.alpha.actor.status/self one hour from now:
curl -X POST https://<your-val>.web.val.run/xrpc/me.byjp.atproto.repo.delayedRequest \ -H "Authorization: Bearer $APP_PASSWORD" \ -H "Content-Type: application/json" \ -d '{ "delay": { "key": "clear-teal-status", "executeAfter": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'/PT1H" }, "request": { "$type": "com.atproto.repo.deleteRecord", "collection": "fm.teal.alpha.actor.status", "repo": "did:plc:ephkzpinhaqcabtkugtbzrwu", "rkey": "self" } }'
On success the val responds with { "ok": true, "dkey": "clear-teal-status", "executeAfter": <ms> }.
Send the same delay.key with no request:
curl -X POST https://<your-val>.web.val.run/xrpc/me.byjp.atproto.repo.delayedRequest \ -H "Authorization: Bearer $APP_PASSWORD" \ -H "Content-Type: application/json" \ -d '{ "delay": { "key": "clear-teal-status" } }'
- main.ts — HTTP trigger (the webhook)
- execute.cron.ts — cron trigger that fires due requests (set the schedule to every minute in val.town)
- db.ts — sqlite schema and queries
- auth.ts — DID/PDS resolution and session creation
- validate.ts — lexicon validation for stored requests
- parse-time.ts —
executeAfterparsing