this string has no description
smokesignal_xrpc.md
595 lines 18 kB view raw view code

Smokesignal XRPC API Reference#

Base URL: https://smokesignal.events

All XRPC endpoints are available at /xrpc/{method-nsid}. Responses are JSON (application/json).

Table of Contents#


Public Query Endpoints#

community.lexicon.calendar.searchEvents#

Search for events by text query, organizer DID, and/or location. Requires OpenSearch to be configured on the server.

Method: GET

Path: /xrpc/community.lexicon.calendar.searchEvents

Authentication: None

Query Parameters:

Parameter Type Required Default Description
query string No Free-text search query. Use "upcoming" to search for upcoming events.
repository string No DID of the event organizer to filter by (did:plc:... or did:web:...).
location string or string[] No Location CID(s) to filter by. Repeat the parameter for multiple values.
limit integer No 10 Maximum number of results to return.

At least one of query, repository, or location must be provided. If none are provided, an empty result set is returned.

Response Body:

{
  "results": [
    {
      "$type": "community.lexicon.calendar.eventView",
      "name": "Rust Meetup",
      "description": "Monthly Rust meetup",
      "startsAt": "2026-03-01T18:00:00Z",
      "endsAt": "2026-03-01T20:00:00Z",
      "countGoing": 42,
      "countInterested": 15,
      "countNotGoing": 3,
      "url": "https://smokesignal.events/alice.bsky.social/3abc123"
    }
  ]
}

Each result contains the event record fields (flattened), RSVP counts, and a web URL for the event.

curl Example:

# Search by text
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?query=rust+meetup&limit=5'

# Search by organizer DID
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?repository=did:plc:1234abcd'

# Search upcoming events
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?query=upcoming&limit=10'

# Search by multiple locations
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?location=bafyreiabc&location=bafyreixyz'

Example HTTP Request:

GET /xrpc/community.lexicon.calendar.searchEvents?query=rust+meetup&limit=5 HTTP/1.1
Host: smokesignal.events
Accept: application/json

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "results": [
    {
      "$type": "community.lexicon.calendar.eventView",
      "name": "Rust Meetup",
      "description": "Monthly Rust meetup in Tallinn",
      "startsAt": "2026-03-01T18:00:00Z",
      "endsAt": "2026-03-01T20:00:00Z",
      "mode": "physical",
      "countGoing": 42,
      "countInterested": 15,
      "countNotGoing": 3,
      "url": "https://smokesignal.events/alice.bsky.social/3abc123"
    }
  ]
}

Error Responses:

Status Error Description
404 invalid_repository repository parameter is not a valid did:plc or did:web value.
503 search_unavailable OpenSearch is not configured on the server.
500 search_error Failed to initialize or execute the search.

community.lexicon.calendar.getEvent#

Retrieve a single event by its organizer DID and record key.

Method: GET

Path: /xrpc/community.lexicon.calendar.getEvent

Authentication: None

Query Parameters:

Parameter Type Required Description
repository string Yes DID of the event organizer (did:plc:... or did:web:...).
record_key string Yes Record key (rkey) of the event.

Response Body:

{
  "$type": "community.lexicon.calendar.eventView",
  "name": "Rust Meetup",
  "description": "Monthly Rust meetup",
  "startsAt": "2026-03-01T18:00:00Z",
  "endsAt": "2026-03-01T20:00:00Z",
  "countGoing": 42,
  "countInterested": 15,
  "countNotGoing": 3,
  "url": "https://smokesignal.events/alice.bsky.social/3abc123"
}

The response contains the event record fields (flattened at the top level), RSVP counts, and a web URL.

curl Example:

curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.getEvent?repository=did:plc:1234abcd&record_key=3abc123'

Example HTTP Request:

GET /xrpc/community.lexicon.calendar.getEvent?repository=did:plc:1234abcd&record_key=3abc123 HTTP/1.1
Host: smokesignal.events
Accept: application/json

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "$type": "community.lexicon.calendar.eventView",
  "name": "Rust Meetup",
  "description": "Monthly Rust meetup in Tallinn",
  "startsAt": "2026-03-01T18:00:00Z",
  "endsAt": "2026-03-01T20:00:00Z",
  "mode": "physical",
  "countGoing": 42,
  "countInterested": 15,
  "countNotGoing": 3,
  "url": "https://smokesignal.events/alice.bsky.social/3abc123"
}

Error Responses:

Status Error Description
404 not_found Invalid repository DID format or event record not found.

community.lexicon.calendar.getRSVP#

Retrieve a specific RSVP record for a given event and identity.

Method: GET

Path: /xrpc/community.lexicon.calendar.getRSVP

Authentication: None

Query Parameters:

Parameter Type Required Description
event string Yes AT-URI of the event (e.g., at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123).
identity string Yes DID or handle of the RSVP author. Handles are resolved to DIDs.

Response Body:

{
  "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
  "cid": "bafyreiabc123",
  "record": {
    "$type": "community.lexicon.calendar.rsvp",
    "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
    "status": "going",
    "createdAt": "2026-02-10T12:00:00Z"
  }
}

curl Example:

curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.getRSVP?event=at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123&identity=did:plc:5678efgh'

Example HTTP Request:

GET /xrpc/community.lexicon.calendar.getRSVP?event=at%3A%2F%2Fdid%3Aplc%3A1234abcd%2Fcommunity.lexicon.calendar.event%2F3abc123&identity=did%3Aplc%3A5678efgh HTTP/1.1
Host: smokesignal.events
Accept: application/json

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
  "cid": "bafyreiabc123",
  "record": {
    "$type": "community.lexicon.calendar.rsvp",
    "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
    "status": "going",
    "createdAt": "2026-02-10T12:00:00Z"
  }
}

Error Responses:

Status Error Description
400 InvalidRequest Invalid event AT-URI format or invalid identity DID.
404 NotFound RSVP not found for the given event and identity.
500 InternalServerError Database error while fetching the RSVP.

community.lexicon.calendar.listRSVPs#

List all RSVPs for a given identity with cursor-based pagination.

Method: GET

Path: /xrpc/community.lexicon.calendar.listRSVPs

Authentication: None

Query Parameters:

Parameter Type Required Default Description
identity string Yes DID or handle of the user to list RSVPs for. Handles are resolved to DIDs.
limit integer No 50 Maximum number of results. Clamped to range [1, 100].
cursor string No RFC 3339 datetime string from a previous response for pagination.

Response Body:

{
  "rsvps": [
    {
      "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
      "cid": "bafyreiabc123",
      "record": {
        "$type": "community.lexicon.calendar.rsvp",
        "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
        "status": "going",
        "createdAt": "2026-02-10T12:00:00Z"
      },
      "eventUri": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
      "status": "going"
    }
  ],
  "cursor": "2026-02-10T12:00:00Z"
}

The cursor field is only present when there are more results available. Pass it as the cursor query parameter to fetch the next page.

curl Example:

# First page
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25'

# Next page using cursor
curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25&cursor=2026-02-10T12:00:00Z'

Example HTTP Request:

GET /xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25 HTTP/1.1
Host: smokesignal.events
Accept: application/json

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "rsvps": [
    {
      "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
      "cid": "bafyreiabc123",
      "record": {
        "$type": "community.lexicon.calendar.rsvp",
        "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
        "status": "going",
        "createdAt": "2026-02-10T12:00:00Z"
      },
      "eventUri": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
      "status": "going"
    },
    {
      "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3def456",
      "cid": "bafyreidef456",
      "record": {
        "$type": "community.lexicon.calendar.rsvp",
        "event": "at://did:plc:9999zzzz/community.lexicon.calendar.event/3ghi789",
        "status": "interested",
        "createdAt": "2026-02-08T09:30:00Z"
      },
      "eventUri": "at://did:plc:9999zzzz/community.lexicon.calendar.event/3ghi789",
      "status": "interested"
    }
  ],
  "cursor": "2026-02-08T09:30:00Z"
}

Error Responses:

Status Error Description
400 InvalidRequest Invalid identity DID format or invalid cursor format (must be RFC 3339).
500 InternalServerError Database error while fetching RSVPs.

Authenticated Procedure Endpoints#

These endpoints require an AT Protocol JWT Bearer token. See Authentication for details.

events.smokesignal.rsvp.linkAttestation#

Link an external attestation record (e.g., from a ticket purchase on ti.to or Eventbrite) to an event. This creates an acceptance ticket that the target user can later confirm to complete their RSVP.

Method: POST

Path: /xrpc/events.smokesignal.rsvp.linkAttestation

Authentication: Required (AT Protocol JWT Bearer token)

Authorization: The authenticated caller must be both the event organizer and the attestation record owner.

Request Body (application/json):

Field Type Required Description
did string Yes DID of the target user the attestation is for.
event string Yes AT-URI of the event.
aturi string Yes AT-URI of the remote attestation record.

Response Body (success):

{}

curl Example:

curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.rsvp.linkAttestation' \
  -H 'Authorization: Bearer <at-proto-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "did": "did:plc:5678efgh",
    "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
    "aturi": "at://did:plc:1234abcd/com.example.attestation/3att456"
  }'

Example HTTP Request:

POST /xrpc/events.smokesignal.rsvp.linkAttestation HTTP/1.1
Host: smokesignal.events
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json

{
  "did": "did:plc:5678efgh",
  "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
  "aturi": "at://did:plc:1234abcd/com.example.attestation/3att456"
}

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{}

Error Responses:

Status Error Description
401 AuthRequired Missing, invalid, or expired authentication token, or no issuer in token.
400 InvalidRequest Invalid target DID format, invalid event AT-URI, or invalid attestation AT-URI.
403 Forbidden Caller is not the event organizer or not the attestation record owner.
404 NotFound Event not found.
500 InternalServerError Failed to store the attestation link.

events.smokesignal.event.configure#

Configure Smokesignal-specific settings for an event, such as email confirmation requirements and external ticketing redirects.

Method: POST

Path: /xrpc/events.smokesignal.event.configure

Authentication: Required (AT Protocol JWT Bearer token)

Authorization: The authenticated caller must be the event organizer (owner of the event's AT-URI).

Request Body (application/json):

Field Type Required Description
event string Yes AT-URI of the event to configure. Must belong to the authenticated user.
requireConfirmedEmail boolean No When true, RSVPs require a confirmed email address.
disableDirectRsvp boolean No When true, the RSVP button redirects to an external ticketing URL.
rsvpRedirectUrl string No HTTPS URL to redirect users to for external ticketing (max 2048 characters). Must use the https scheme. Pass an empty string to clear.

At least one of requireConfirmedEmail, disableDirectRsvp, or rsvpRedirectUrl must be provided.

Response Body (success):

{}

curl Example:

# Enable email confirmation requirement
curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.event.configure' \
  -H 'Authorization: Bearer <at-proto-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
    "requireConfirmedEmail": true
  }'

# Set up external ticketing redirect
curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.event.configure' \
  -H 'Authorization: Bearer <at-proto-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{
    "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
    "disableDirectRsvp": true,
    "rsvpRedirectUrl": "https://ti.to/myorg/my-event"
  }'

Example HTTP Request:

POST /xrpc/events.smokesignal.event.configure HTTP/1.1
Host: smokesignal.events
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json

{
  "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
  "requireConfirmedEmail": true,
  "disableDirectRsvp": true,
  "rsvpRedirectUrl": "https://ti.to/myorg/my-event"
}

Example HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{}

Error Responses:

Status Error Description
401 AuthRequired Missing, invalid, or expired authentication token, or no issuer in token.
400 InvalidRequest Event AT-URI doesn't belong to the authenticated user, invalid AT-URI format, or no settings provided.
400 InvalidRedirectUrl Redirect URL is not valid or does not use HTTPS.
404 EventNotFound The specified event does not exist.
500 InternalServerError Failed to update event settings.

Authentication#

Authenticated endpoints require an AT Protocol JWT passed as a Bearer token in the Authorization header:

Authorization: Bearer <at-proto-jwt>

The JWT must:

  • Be a valid AT Protocol access token
  • Contain an iss (issuer) claim with the caller's DID
  • Not be expired

Tokens are validated by the server using AT Protocol's JOSE/JWT verification with P-256 ECDSA keys.

Error Responses#

All error responses follow a consistent JSON structure:

{
  "error": "ErrorCode",
  "message": "Human-readable description of the error"
}

Some endpoints use error_description instead of message:

{
  "error": "error_code",
  "error_description": "Human-readable description of the error"
}

Common HTTP Status Codes#

Status Meaning
200 Success
400 Bad request (invalid parameters or input)
401 Authentication required or token invalid
403 Forbidden (insufficient permissions)
404 Resource not found
500 Internal server error
503 Service unavailable (e.g., search not configured)