{
  "asyncapi": "3.0.0",
  "info": {
    "title": "Atheron events",
    "version": "2026-10-15",
    "description": "The events an app hears: as webhooks (signed POSTs to your server), or as a stream it opens: Server-Sent Events, a WebSocket, or a GraphQL subscription. Every way carries the same events with the same body. Streams need an API key with events:read; events are kept 30 days for resuming."
  },
  "servers": {
    "sse": {
      "host": "developers.aton-network.org",
      "protocol": "https",
      "description": "Server-Sent Events.",
      "security": [
        {
          "$ref": "#/components/securitySchemes/apiKey"
        }
      ]
    },
    "websocket": {
      "host": "developers.aton-network.org",
      "protocol": "wss",
      "description": "Plain WebSocket, JSON frames.",
      "security": [
        {
          "$ref": "#/components/securitySchemes/apiKey"
        }
      ]
    },
    "graphql": {
      "host": "developers.aton-network.org",
      "protocol": "wss",
      "description": "GraphQL over WebSocket (graphql-transport-ws).",
      "security": [
        {
          "$ref": "#/components/securitySchemes/apiKey"
        }
      ]
    }
  },
  "channels": {
    "eventsSse": {
      "address": "/api/v1/events",
      "servers": [
        {
          "$ref": "#/servers/sse"
        }
      ],
      "title": "Events, as Server-Sent Events",
      "description": "GET with Authorization: Bearer. Each event is id: <event id>, event: <type>, data: <body>. First event: ready. A comment every 15 seconds. On an error: event: error with {error, error_description}, then the stream closes.",
      "bindings": {
        "http": {
          "method": "GET",
          "query": {
            "type": "object",
            "properties": {
              "types": {
                "type": "string",
                "description": "Comma separated types; all when left out."
              },
              "after": {
                "type": "string",
                "format": "uuid",
                "description": "Resume after this event id."
              }
            }
          }
        }
      },
      "messages": {
        "user_signed_in": {
          "$ref": "#/components/messages/user_signed_in"
        },
        "consent_revoked": {
          "$ref": "#/components/messages/consent_revoked"
        },
        "membership_changed": {
          "$ref": "#/components/messages/membership_changed"
        },
        "ping": {
          "$ref": "#/components/messages/ping"
        }
      }
    },
    "eventsWebSocket": {
      "address": "/api/v1/events/ws",
      "servers": [
        {
          "$ref": "#/servers/websocket"
        }
      ],
      "title": "Events, over a WebSocket",
      "description": "Authorization: Bearer on the upgrade. Frames: {type: ready}, {type: event, event: <body>}, {type: error, error, error_description} before closing. The same types and after query parameters.",
      "bindings": {
        "ws": {
          "method": "GET",
          "headers": {
            "type": "object",
            "properties": {
              "authorization": {
                "type": "string"
              }
            }
          }
        }
      },
      "messages": {
        "user_signed_in": {
          "$ref": "#/components/messages/user_signed_in"
        },
        "consent_revoked": {
          "$ref": "#/components/messages/consent_revoked"
        },
        "membership_changed": {
          "$ref": "#/components/messages/membership_changed"
        },
        "ping": {
          "$ref": "#/components/messages/ping"
        }
      }
    },
    "graphqlSubscription": {
      "address": "/api/graphql/ws",
      "servers": [
        {
          "$ref": "#/servers/graphql"
        }
      ],
      "title": "Events, as a GraphQL subscription",
      "description": "Subprotocol graphql-transport-ws. connection_init with payload {authorization: \"Bearer ath_...\"}, then subscribe to subscription { events(types, after) { id type created clientId data { sub scopes at } } }.",
      "messages": {
        "user_signed_in": {
          "$ref": "#/components/messages/user_signed_in"
        },
        "consent_revoked": {
          "$ref": "#/components/messages/consent_revoked"
        },
        "membership_changed": {
          "$ref": "#/components/messages/membership_changed"
        },
        "ping": {
          "$ref": "#/components/messages/ping"
        }
      }
    }
  },
  "operations": {
    "receiveEventsSse": {
      "action": "receive",
      "channel": {
        "$ref": "#/channels/eventsSse"
      },
      "summary": "Hear events over Server-Sent Events."
    },
    "receiveEventsWebSocket": {
      "action": "receive",
      "channel": {
        "$ref": "#/channels/eventsWebSocket"
      },
      "summary": "Hear events over a WebSocket."
    },
    "receiveEventsGraphql": {
      "action": "receive",
      "channel": {
        "$ref": "#/channels/graphqlSubscription"
      },
      "summary": "Hear events as a GraphQL subscription."
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A developer API key with the events:read right: ath_test_... or ath_live_..."
      }
    },
    "messages": {
      "user_signed_in": {
        "name": "user.signed_in",
        "title": "user.signed_in",
        "summary": "Somebody signed in to your app: an authorization code was issued to your client.",
        "contentType": "application/json",
        "payload": {
          "type": "object",
          "required": [
            "id",
            "type",
            "created",
            "client_id",
            "data"
          ],
          "properties": {
            "id": {
              "type": "string",
              "format": "uuid",
              "description": "The event's id: resume after it with ?after= or Last-Event-ID."
            },
            "type": {
              "type": "string",
              "const": "user.signed_in"
            },
            "created": {
              "type": "string",
              "format": "date-time"
            },
            "client_id": {
              "type": "string",
              "description": "The client the event concerns (test-... or live-...)."
            },
            "data": {
              "type": "object",
              "required": [
                "sub",
                "scopes",
                "at"
              ],
              "properties": {
                "sub": {
                  "type": "string",
                  "format": "uuid"
                },
                "scopes": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        },
        "examples": [
          {
            "payload": {
              "id": "6d0f5c1e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
              "type": "user.signed_in",
              "created": "2026-10-15T16:04:05.000Z",
              "client_id": "live-8b21de",
              "data": {
                "sub": "9a7e0c52-5d1b-4b8e-9a51-3f0e2d1c4b6a",
                "scopes": [
                  "openid",
                  "profile"
                ],
                "at": "2026-10-15T16:04:05.000Z"
              }
            }
          }
        ]
      },
      "consent_revoked": {
        "name": "consent.revoked",
        "title": "consent.revoked",
        "summary": "Somebody withdrew your app's access, from their account or ours.",
        "contentType": "application/json",
        "payload": {
          "type": "object",
          "required": [
            "id",
            "type",
            "created",
            "client_id",
            "data"
          ],
          "properties": {
            "id": {
              "type": "string",
              "format": "uuid",
              "description": "The event's id: resume after it with ?after= or Last-Event-ID."
            },
            "type": {
              "type": "string",
              "const": "consent.revoked"
            },
            "created": {
              "type": "string",
              "format": "date-time"
            },
            "client_id": {
              "type": "string",
              "description": "The client the event concerns (test-... or live-...)."
            },
            "data": {
              "type": "object",
              "required": [
                "sub",
                "at"
              ],
              "properties": {
                "sub": {
                  "type": "string",
                  "format": "uuid"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        },
        "examples": [
          {
            "payload": {
              "id": "6d0f5c1e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
              "type": "consent.revoked",
              "created": "2026-10-15T16:04:05.000Z",
              "client_id": "live-8b21de",
              "data": {
                "sub": "9a7e0c52-5d1b-4b8e-9a51-3f0e2d1c4b6a",
                "at": "2026-10-15T16:04:05.000Z"
              }
            }
          }
        ]
      },
      "membership_changed": {
        "name": "membership.changed",
        "title": "membership.changed",
        "summary": "A person who let your app see their membership had a plan granted, changed or ended.",
        "contentType": "application/json",
        "payload": {
          "type": "object",
          "required": [
            "id",
            "type",
            "created",
            "client_id",
            "data"
          ],
          "properties": {
            "id": {
              "type": "string",
              "format": "uuid",
              "description": "The event's id: resume after it with ?after= or Last-Event-ID."
            },
            "type": {
              "type": "string",
              "const": "membership.changed"
            },
            "created": {
              "type": "string",
              "format": "date-time"
            },
            "client_id": {
              "type": "string",
              "description": "The client the event concerns (test-... or live-...)."
            },
            "data": {
              "type": "object",
              "required": [
                "sub",
                "at"
              ],
              "properties": {
                "sub": {
                  "type": "string",
                  "format": "uuid"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        },
        "examples": [
          {
            "payload": {
              "id": "6d0f5c1e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
              "type": "membership.changed",
              "created": "2026-10-15T16:04:05.000Z",
              "client_id": "live-8b21de",
              "data": {
                "sub": "9a7e0c52-5d1b-4b8e-9a51-3f0e2d1c4b6a",
                "at": "2026-10-15T16:04:05.000Z"
              }
            }
          }
        ]
      },
      "ping": {
        "name": "ping",
        "title": "ping",
        "summary": "A test event you sent from the portal.",
        "contentType": "application/json",
        "payload": {
          "type": "object",
          "required": [
            "id",
            "type",
            "created",
            "client_id",
            "data"
          ],
          "properties": {
            "id": {
              "type": "string",
              "format": "uuid",
              "description": "The event's id: resume after it with ?after= or Last-Event-ID."
            },
            "type": {
              "type": "string",
              "const": "ping"
            },
            "created": {
              "type": "string",
              "format": "date-time"
            },
            "client_id": {
              "type": "string",
              "description": "The client the event concerns (test-... or live-...)."
            },
            "data": {
              "type": "object",
              "required": [
                "at"
              ],
              "properties": {
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        },
        "examples": [
          {
            "payload": {
              "id": "6d0f5c1e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
              "type": "ping",
              "created": "2026-10-15T16:04:05.000Z",
              "client_id": "live-8b21de",
              "data": {
                "at": "2026-10-15T16:04:05.000Z"
              }
            }
          }
        ]
      }
    }
  }
}