Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docs/howto/custom-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Custom Nostr Events

This guide shows how to construct and publish a Nostr event with a non-standard `kind` using **nostr-java**.

## Background

Every Nostr event must include the fields defined in [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md):

- `id`
- `pubkey`
- `created_at`
- `kind`
- `tags`
- `content`
- `sig`

Kinds that are not defined by existing NIPs may still be used. [NIP-16](https://github.com/nostr-protocol/nips/blob/master/16.md) describes how kind numbers are grouped (regular, replaceable, ephemeral and parameterized replaceable). Choose a value that does not collide with other applications.

## Example

```java
import java.util.List;

import nostr.client.springwebsocket.StandardWebSocketClient;
import nostr.event.BaseTag;
import nostr.event.impl.GenericEvent;
import nostr.event.message.EventMessage;
import nostr.id.Identity;

public class CustomEventExample {
public static void main(String[] args) throws Exception {
Identity identity = Identity.generateRandomIdentity();

int CUSTOM_KIND = 9000; // Non-standard kind
GenericEvent event = new GenericEvent(identity.getPublicKey(), CUSTOM_KIND, List.<BaseTag>of(),
"Hello from a custom kind!");

// Required fields `id` and `sig` are populated when signing
identity.sign(event);

try (StandardWebSocketClient client = new StandardWebSocketClient("wss://relay.example.com")) {
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example uses a placeholder relay URL 'wss://relay.example.com' which is not a real relay. Consider using a well-known public relay like 'wss://relay.damus.io' or add a note that users should replace this with an actual relay URL.

Suggested change
try (StandardWebSocketClient client = new StandardWebSocketClient("wss://relay.example.com")) {
try (StandardWebSocketClient client = new StandardWebSocketClient("wss://relay.damus.io")) {

Copilot uses AI. Check for mistakes.
client.send(new EventMessage(event));
}
}
}
```

## Steps Explained

1. **Construct the event** – Provide the public key, custom kind, any tags, and content. The constructor fills in `created_at` automatically and initializes the list of `tags`.
2. **Sign** – `Identity.sign(event)` computes the event `id` and `sig` using the private key. Relays verify these fields against the serialized event bytes as defined in NIP‑01.
3. **Submit to a relay** – Send the event using an `EVENT` message. The example uses `StandardWebSocketClient`, but any Nostr-compatible relay transport will work.

For more information about event structure and relay communication, consult [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) and [NIP-16](https://github.com/nostr-protocol/nips/blob/master/16.md).