this string has no description
smokesignal_xrpc.md
1# Smokesignal XRPC API Reference
2
3Base URL: `https://smokesignal.events`
4
5All XRPC endpoints are available at `/xrpc/{method-nsid}`. Responses are JSON (`application/json`).
6
7## Table of Contents
8
9- [Public Query Endpoints](#public-query-endpoints)
10 - [community.lexicon.calendar.searchEvents](#communitylexiconcalendarsearchevents)
11 - [community.lexicon.calendar.getEvent](#communitylexiconcalendargetevent)
12 - [community.lexicon.calendar.getRSVP](#communitylexiconcalendargetrsvp)
13 - [community.lexicon.calendar.listRSVPs](#communitylexiconcalendarlistrsvps)
14- [Authenticated Procedure Endpoints](#authenticated-procedure-endpoints)
15 - [events.smokesignal.rsvp.linkAttestation](#eventssmokesignalrsvplinkattestation)
16 - [events.smokesignal.event.configure](#eventssmokesignaleventconfigure)
17- [Authentication](#authentication)
18- [Error Responses](#error-responses)
19
20---
21
22## Public Query Endpoints
23
24### community.lexicon.calendar.searchEvents
25
26Search for events by text query, organizer DID, and/or location. Requires OpenSearch to be configured on the server.
27
28**Method:** `GET`
29
30**Path:** `/xrpc/community.lexicon.calendar.searchEvents`
31
32**Authentication:** None
33
34**Query Parameters:**
35
36| Parameter | Type | Required | Default | Description |
37|-----------|------|----------|---------|-------------|
38| `query` | string | No | — | Free-text search query. Use `"upcoming"` to search for upcoming events. |
39| `repository` | string | No | — | DID of the event organizer to filter by (`did:plc:...` or `did:web:...`). |
40| `location` | string or string[] | No | — | Location CID(s) to filter by. Repeat the parameter for multiple values. |
41| `limit` | integer | No | `10` | Maximum number of results to return. |
42
43At least one of `query`, `repository`, or `location` must be provided. If none are provided, an empty result set is returned.
44
45**Response Body:**
46
47```json
48{
49 "results": [
50 {
51 "$type": "community.lexicon.calendar.eventView",
52 "name": "Rust Meetup",
53 "description": "Monthly Rust meetup",
54 "startsAt": "2026-03-01T18:00:00Z",
55 "endsAt": "2026-03-01T20:00:00Z",
56 "countGoing": 42,
57 "countInterested": 15,
58 "countNotGoing": 3,
59 "url": "https://smokesignal.events/alice.bsky.social/3abc123"
60 }
61 ]
62}
63```
64
65Each result contains the event record fields (flattened), RSVP counts, and a web URL for the event.
66
67**curl Example:**
68
69```bash
70# Search by text
71curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?query=rust+meetup&limit=5'
72
73# Search by organizer DID
74curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?repository=did:plc:1234abcd'
75
76# Search upcoming events
77curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?query=upcoming&limit=10'
78
79# Search by multiple locations
80curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?location=bafyreiabc&location=bafyreixyz'
81```
82
83**Example HTTP Request:**
84
85```http
86GET /xrpc/community.lexicon.calendar.searchEvents?query=rust+meetup&limit=5 HTTP/1.1
87Host: smokesignal.events
88Accept: application/json
89```
90
91**Example HTTP Response:**
92
93```http
94HTTP/1.1 200 OK
95Content-Type: application/json
96
97```
98
99**Error Responses:**
100
101| Status | Error | Description |
102|--------|-------|-------------|
103| 404 | `invalid_repository` | `repository` parameter is not a valid `did:plc` or `did:web` value. |
104| 503 | `search_unavailable` | OpenSearch is not configured on the server. |
105| 500 | `search_error` | Failed to initialize or execute the search. |
106
107---
108
109### community.lexicon.calendar.getEvent
110
111Retrieve a single event by its organizer DID and record key.
112
113**Method:** `GET`
114
115**Path:** `/xrpc/community.lexicon.calendar.getEvent`
116
117**Authentication:** None
118
119**Query Parameters:**
120
121| Parameter | Type | Required | Description |
122|-----------|------|----------|-------------|
123| `repository` | string | Yes | DID of the event organizer (`did:plc:...` or `did:web:...`). |
124| `record_key` | string | Yes | Record key (rkey) of the event. |
125
126**Response Body:**
127
128```json
129{
130 "$type": "community.lexicon.calendar.eventView",
131 "name": "Rust Meetup",
132 "description": "Monthly Rust meetup",
133 "startsAt": "2026-03-01T18:00:00Z",
134 "endsAt": "2026-03-01T20:00:00Z",
135 "countGoing": 42,
136 "countInterested": 15,
137 "countNotGoing": 3,
138 "url": "https://smokesignal.events/alice.bsky.social/3abc123"
139}
140```
141
142The response contains the event record fields (flattened at the top level), RSVP counts, and a web URL.
143
144**curl Example:**
145
146```bash
147curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.getEvent?repository=did:plc:1234abcd&record_key=3abc123'
148```
149
150**Example HTTP Request:**
151
152```http
153GET /xrpc/community.lexicon.calendar.getEvent?repository=did:plc:1234abcd&record_key=3abc123 HTTP/1.1
154Host: smokesignal.events
155Accept: application/json
156```
157
158**Example HTTP Response:**
159
160```http
161HTTP/1.1 200 OK
162Content-Type: application/json
163
164```
165
166**Error Responses:**
167
168| Status | Error | Description |
169|--------|-------|-------------|
170| 404 | `not_found` | Invalid `repository` DID format or event record not found. |
171
172---
173
174### community.lexicon.calendar.getRSVP
175
176Retrieve a specific RSVP record for a given event and identity.
177
178**Method:** `GET`
179
180**Path:** `/xrpc/community.lexicon.calendar.getRSVP`
181
182**Authentication:** None
183
184**Query Parameters:**
185
186| Parameter | Type | Required | Description |
187|-----------|------|----------|-------------|
188| `event` | string | Yes | AT-URI of the event (e.g., `at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123`). |
189| `identity` | string | Yes | DID or handle of the RSVP author. Handles are resolved to DIDs. |
190
191**Response Body:**
192
193```json
194{
195 "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
196 "cid": "bafyreiabc123",
197 "record": {
198 "$type": "community.lexicon.calendar.rsvp",
199 "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
200 "status": "going",
201 "createdAt": "2026-02-10T12:00:00Z"
202 }
203}
204```
205
206**curl Example:**
207
208```bash
209curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.getRSVP?event=at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123&identity=did:plc:5678efgh'
210```
211
212**Example HTTP Request:**
213
214```http
215GET /xrpc/community.lexicon.calendar.getRSVP?event=at%3A%2F%2Fdid%3Aplc%3A1234abcd%2Fcommunity.lexicon.calendar.event%2F3abc123&identity=did%3Aplc%3A5678efgh HTTP/1.1
216Host: smokesignal.events
217Accept: application/json
218```
219
220**Example HTTP Response:**
221
222```http
223HTTP/1.1 200 OK
224Content-Type: application/json
225
226```
227
228**Error Responses:**
229
230| Status | Error | Description |
231|--------|-------|-------------|
232| 400 | `InvalidRequest` | Invalid event AT-URI format or invalid identity DID. |
233| 404 | `NotFound` | RSVP not found for the given event and identity. |
234| 500 | `InternalServerError` | Database error while fetching the RSVP. |
235
236---
237
238### community.lexicon.calendar.listRSVPs
239
240List all RSVPs for a given identity with cursor-based pagination.
241
242**Method:** `GET`
243
244**Path:** `/xrpc/community.lexicon.calendar.listRSVPs`
245
246**Authentication:** None
247
248**Query Parameters:**
249
250| Parameter | Type | Required | Default | Description |
251|-----------|------|----------|---------|-------------|
252| `identity` | string | Yes | — | DID or handle of the user to list RSVPs for. Handles are resolved to DIDs. |
253| `limit` | integer | No | `50` | Maximum number of results. Clamped to range `[1, 100]`. |
254| `cursor` | string | No | — | RFC 3339 datetime string from a previous response for pagination. |
255
256**Response Body:**
257
258```json
259{
260 "rsvps": [
261 {
262 "uri": "at://did:plc:5678efgh/community.lexicon.calendar.rsvp/3xyz789",
263 "cid": "bafyreiabc123",
264 "record": {
265 "$type": "community.lexicon.calendar.rsvp",
266 "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
267 "status": "going",
268 "createdAt": "2026-02-10T12:00:00Z"
269 },
270 "eventUri": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
271 "status": "going"
272 }
273 ],
274 "cursor": "2026-02-10T12:00:00Z"
275}
276```
277
278The `cursor` field is only present when there are more results available. Pass it as the `cursor` query parameter to fetch the next page.
279
280**curl Example:**
281
282```bash
283# First page
284curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25'
285
286# Next page using cursor
287curl 'https://smokesignal.events/xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25&cursor=2026-02-10T12:00:00Z'
288```
289
290**Example HTTP Request:**
291
292```http
293GET /xrpc/community.lexicon.calendar.listRSVPs?identity=did:plc:5678efgh&limit=25 HTTP/1.1
294Host: smokesignal.events
295Accept: application/json
296```
297
298**Example HTTP Response:**
299
300```http
301HTTP/1.1 200 OK
302Content-Type: application/json
303
304```
305
306**Error Responses:**
307
308| Status | Error | Description |
309|--------|-------|-------------|
310| 400 | `InvalidRequest` | Invalid identity DID format or invalid cursor format (must be RFC 3339). |
311| 500 | `InternalServerError` | Database error while fetching RSVPs. |
312
313---
314
315## Authenticated Procedure Endpoints
316
317These endpoints require an AT Protocol JWT Bearer token. See [Authentication](#authentication) for details.
318
319### events.smokesignal.rsvp.linkAttestation
320
321Link 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.
322
323**Method:** `POST`
324
325**Path:** `/xrpc/events.smokesignal.rsvp.linkAttestation`
326
327**Authentication:** Required (AT Protocol JWT Bearer token)
328
329**Authorization:** The authenticated caller must be both the event organizer and the attestation record owner.
330
331**Request Body (`application/json`):**
332
333| Field | Type | Required | Description |
334|-------|------|----------|-------------|
335| `did` | string | Yes | DID of the target user the attestation is for. |
336| `event` | string | Yes | AT-URI of the event. |
337| `aturi` | string | Yes | AT-URI of the remote attestation record. |
338
339**Response Body (success):**
340
341```json
342{}
343```
344
345**curl Example:**
346
347```bash
348curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.rsvp.linkAttestation' \
349 -H 'Authorization: Bearer <at-proto-jwt>' \
350 -H 'Content-Type: application/json' \
351 -d '{
352 "did": "did:plc:5678efgh",
353 "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
354 "aturi": "at://did:plc:1234abcd/com.example.attestation/3att456"
355 }'
356```
357
358**Example HTTP Request:**
359
360```http
361POST /xrpc/events.smokesignal.rsvp.linkAttestation HTTP/1.1
362Host: smokesignal.events
363Authorization: Bearer eyJhbGciOi...
364Content-Type: application/json
365
366```
367
368**Example HTTP Response:**
369
370```http
371HTTP/1.1 200 OK
372Content-Type: application/json
373
374```
375
376**Error Responses:**
377
378| Status | Error | Description |
379|--------|-------|-------------|
380| 401 | `AuthRequired` | Missing, invalid, or expired authentication token, or no issuer in token. |
381| 400 | `InvalidRequest` | Invalid target DID format, invalid event AT-URI, or invalid attestation AT-URI. |
382| 403 | `Forbidden` | Caller is not the event organizer or not the attestation record owner. |
383| 404 | `NotFound` | Event not found. |
384| 500 | `InternalServerError` | Failed to store the attestation link. |
385
386---
387
388### events.smokesignal.event.configure
389
390Configure Smokesignal-specific settings for an event, such as email confirmation requirements and external ticketing redirects.
391
392**Method:** `POST`
393
394**Path:** `/xrpc/events.smokesignal.event.configure`
395
396**Authentication:** Required (AT Protocol JWT Bearer token)
397
398**Authorization:** The authenticated caller must be the event organizer (owner of the event's AT-URI).
399
400**Request Body (`application/json`):**
401
402| Field | Type | Required | Description |
403|-------|------|----------|-------------|
404| `event` | string | Yes | AT-URI of the event to configure. Must belong to the authenticated user. |
405| `requireConfirmedEmail` | boolean | No | When `true`, RSVPs require a confirmed email address. |
406| `disableDirectRsvp` | boolean | No | When `true`, the RSVP button redirects to an external ticketing URL. |
407| `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. |
408
409At least one of `requireConfirmedEmail`, `disableDirectRsvp`, or `rsvpRedirectUrl` must be provided.
410
411**Response Body (success):**
412
413```json
414{}
415```
416
417**curl Example:**
418
419```bash
420# Enable email confirmation requirement
421curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.event.configure' \
422 -H 'Authorization: Bearer <at-proto-jwt>' \
423 -H 'Content-Type: application/json' \
424 -d '{
425 "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
426 "requireConfirmedEmail": true
427 }'
428
429# Set up external ticketing redirect
430curl -X POST 'https://smokesignal.events/xrpc/events.smokesignal.event.configure' \
431 -H 'Authorization: Bearer <at-proto-jwt>' \
432 -H 'Content-Type: application/json' \
433 -d '{
434 "event": "at://did:plc:1234abcd/community.lexicon.calendar.event/3abc123",
435 "disableDirectRsvp": true,
436 "rsvpRedirectUrl": "https://ti.to/myorg/my-event"
437 }'
438```
439
440**Example HTTP Request:**
441
442```http
443POST /xrpc/events.smokesignal.event.configure HTTP/1.1
444Host: smokesignal.events
445Authorization: Bearer eyJhbGciOi...
446Content-Type: application/json
447
448```
449
450**Example HTTP Response:**
451
452```http
453HTTP/1.1 200 OK
454Content-Type: application/json
455
456```
457
458**Error Responses:**
459
460| Status | Error | Description |
461|--------|-------|-------------|
462| 401 | `AuthRequired` | Missing, invalid, or expired authentication token, or no issuer in token. |
463| 400 | `InvalidRequest` | Event AT-URI doesn't belong to the authenticated user, invalid AT-URI format, or no settings provided. |
464| 400 | `InvalidRedirectUrl` | Redirect URL is not valid or does not use HTTPS. |
465| 404 | `EventNotFound` | The specified event does not exist. |
466| 500 | `InternalServerError` | Failed to update event settings. |
467
468---
469
470## Authentication
471
472Authenticated endpoints require an AT Protocol JWT passed as a Bearer token in the `Authorization` header:
473
474```
475Authorization: Bearer <at-proto-jwt>
476```
477
478The JWT must:
479- Be a valid AT Protocol access token
480- Contain an `iss` (issuer) claim with the caller's DID
481- Not be expired
482
483Tokens are validated by the server using AT Protocol's JOSE/JWT verification with P-256 ECDSA keys.
484
485## Error Responses
486
487All error responses follow a consistent JSON structure:
488
489```json
490{
491 "error": "ErrorCode",
492 "message": "Human-readable description of the error"
493}
494```
495
496Some endpoints use `error_description` instead of `message`:
497
498```json
499{
500 "error": "error_code",
501 "error_description": "Human-readable description of the error"
502}
503```
504
505### Common HTTP Status Codes
506
507| Status | Meaning |
508|--------|---------|
509| 200 | Success |
510| 400 | Bad request (invalid parameters or input) |
511| 401 | Authentication required or token invalid |
512| 403 | Forbidden (insufficient permissions) |
513| 404 | Resource not found |
514| 500 | Internal server error |
515| 503 | Service unavailable (e.g., search not configured) |