Skip to main content

Chat and account events

The event facade authors canonical Softchat rumors and returns a typed view alongside the exact raw rumor. On receive, classifiers validate the raw rumor and derive the same view. Store the authenticated raw event as the identity source; use typed views for UI and projections.

Messages, relations, and attachments

A chat message contains participants, content, an optional reply or forward relation, attachment metadata, emoji tags, and bounded extension tags. Replies emit a marked e tag; forwards emit q. Legacy unmarked Android reply tags remain reader compatibility. NIP-18 kind 16 is receive-only and is not a Softchat forward.

let message = identity.create_chat_message(ChatMessageDraft {
created_at,
participants: vec![recipient],
content: "hello".into(),
relation: ChatRelation::None,
attachments: vec![],
emoji_tags: vec![],
extension_tags: vec![],
})?;
let received = classify_chat_message(message.rumor)?;

Other chat writers and readers

The same author/classify pattern applies to:

FamilyWriterReaderImportant rule
SubjectcreateSubjectsubject classifiercanonical subject; icon temporarily emits matching imeta and image
ReactioncreateReactionreaction classifierparent e, p, and k; optional custom emoji
DeletioncreateDeletiondeletion classifierauthor validation; deletion wins over edits
EditcreateEditedit classifierreplaces text/emoji only; deterministic latest ordering
TypingcreateTypingtyping classifierkind 21234 rumor in an ephemeral wrapper

All writers require caller-supplied timestamps. Participants and references are validated canonical identifiers, not arbitrary strings.

Native functions are create_subject, create_reaction, create_deletion, create_edit, create_typing, and the matching classify_* functions.

Metadata and contacts

User metadata is a private kind-0 rumor. Known profile fields are typed while unknown JSON fields are retained. Follow lists are private author-copy kind-3 events with canonical p tags, relay hints, and optional local names.

Native Rust provides latest_user_metadata and latest_application_data. Foreign hosts apply their documented (createdAt, eventID) ordering inside the platform-owned database projection. An older event must never replace a newer projection merely because it arrived later.

let metadata = identity.create_user_metadata(
created_at,
Some("Alice".to_owned()),
None, None, None, None, None, None,
r#"{"future":true}"#,
)?;
let received_metadata = classify_user_metadata(metadata.rumor.clone())?;

let follows = identity.create_follow_list(
created_at + 1,
vec![Contact {
public_key: recipient.to_hex(),
relay_hint: "wss://relay.example".to_owned(),
local_name: String::new(),
}],
)?;
let received_follows = classify_follow_list(follows.rumor.clone())?;

Native Rust additionally exposes latest_user_metadata for deterministic selection over a bounded candidate set. Foreign applications apply the same documented (createdAt, eventID) ordering in their database projection.

Application data

  • Kind 30078 represents namespaced application data.
  • Kind 30079 is signed, self-encrypted cross-device app-data synchronization.
  • decryptAppDataSync authenticates the self-authored event before exposing its JSON.

The SDK owns event shape, signing, encryption, and deterministic ordering. The application owns schema migration and conflict resolution inside the JSON payload.

let direct = identity.create_application_data(
created_at,
"com.example.settings".to_owned(),
r#"{"enabled":true}"#.to_owned(),
)?;
let received_direct = classify_application_data(direct.event.clone())?;

let sync = identity.create_app_data_sync(
created_at + 1,
AppDataContext::ReadState,
r#"{"lastRead":42}"#,
)?;
let event = SignedNostrEvent::try_from(sync.event.clone())?;
let received_sync = identity.decrypt_app_data_sync(&event)?;

Raw values are permanent evidence

Typed results are views. Preserve the raw rumor and unknown tags/JSON so a future SDK can re-project the same authenticated input without losing information. Never construct a replacement raw event from a typed view.