this string has no description
smokesignal_xrpc.md
595 lines 18 kB view raw view rendered
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) |