30817:scheduler-dvm

Scheduler DVM

Russell

published
2026-06-08

NIP Scheduler DVM

draft optional

This NIP defines a privacy-preserving protocol for scheduling Nostr events to be published at a future time, using a Data Vending Machine (NIP-90) as the scheduling backend.

Motivation

Publishing a Nostr event at a future time requires an always-online server. This NIP standardizes the interaction between a client and a Scheduler DVM so that:

  • Any client can schedule any signed event without implementing its own server
  • Multiple Scheduler DVMs can exist and compete (self-hostable, open market)
  • No observer or relay can link a scheduled job to its future published event
  • No observer or relay can read the content or the target publication time of a scheduled job
  • The DVM operator can read the scheduled event content and publication time after decryption

Roles

  • Client: the Nostr user who wants to schedule an event
  • Scheduler DVM: an always-online service that publishes the signed event at the requested time

Kinds

Kind Description
5905 Schedule job request (client -> DVM)
7000 Job feedback (DVM -> client)
5 Delete / cancel a job (standard Nostr delete)

1. Creating a Schedule

The client publishes a kind:5905 job request:

{
  "kind": 5905,
  "pubkey": "<client_pubkey>",
  "content": "<nip44_encrypt(dvm_pubkey, client_privkey, payload)>",
  "tags": [
    ["p", "<dvm_pubkey>"],
    ["encrypted"]
  ]
}

Encrypted Payload

{
  "job_id": "<64 random hex chars>",
  "schedule_at": 1748000000,
  "signed_event": { "<full signed Nostr event>" },
  "relays": ["wss://relay.damus.io", "wss://nos.lol"]
}
Field Type Required Description
job_id string yes 64-char random hex, generated by the client. Stable identifier for this job.
schedule_at unix timestamp yes UTC time at which the DVM should publish the event
signed_event object yes The complete, already-signed Nostr event to publish.
relays array of strings yes Relay URLs where the DVM should publish the event

2. Cancelling a Schedule

The client publishes a standard NIP-09 delete event tagging the kind:5905 to cancel:

{
  "kind": 5,
  "tags": [
    ["e", "<id of the kind:5905 event to cancel>"]
  ]
}

The DVM MUST send a kind:7000 feedback with status:cancelled after processing the deletion.

3. Listing Schedules

The client fetches its own job requests directly from relays:

{
  "authors": ["<client_pubkey>"],
  "kinds": [5905]
}

The client decrypts each event's content locally to reconstruct the list of scheduled jobs and their job_ids.

4. Job Feedback (DVM -> Client)

The DVM sends status updates using kind:7000 with no p tag to avoid linking the feedback to the client's pubkey. The content is encrypted using a one-time ephemeral keypair that the DVM destroys immediately after use.

{
  "kind": 7000,
  "pubkey": "<dvm_pubkey>",
  "content": "<nip44_encrypt(ephemeral_privkey, client_pubkey, feedback_payload)>",
  "tags": [
    ["r", "<job_id>"],
    ["ephemeral-pubkey", "<ephemeral_pubkey>"]
  ]
}

Feedback Payload (decrypted content)

{
  "status": "scheduled",
  "message": "<optional human-readable string>"
}
Status Description
scheduled DVM has accepted and queued the job
published The event has been broadcast to the requested relays
failed All relays rejected or were unreachable
cancelled The job was cancelled via kind:5
error The job request was invalid

5. DVM Discoverability (NIP-89)

Scheduler DVMs SHOULD announce themselves using NIP-89:

{
  "kind": 31990,
  "pubkey": "<dvm_pubkey>",
  "content": "{\"name\": \"My Scheduler DVM\", \"about\": \"Schedule any Nostr event.\"}",
  "tags": [
    ["k", "5905"],
    ["t", "scheduler"]
  ]
}

Discussion

Connect a key to comment.