# the hi api ## The basics The `hi` API is exposed as HTTP endpoints that accept JSON and return JSON on success, with a few exceptions noted below. On errors, the response body is freeform text and is meant to be shown to the user, logged, or otherwise handled. Programmatic action should rely on the status code, as documented. Requests that require a JSON body must include a `content-type: application/json` header. For requests that take a JSON body, if the body does not match the required schema, the endpoint will return a 422 Unprocessable Entity response, instead of the responses documented for that endpoint. ## Client initialization Clients will generally need some information about the session in order to present a coherent view to the user, including the session's login identity. ### `GET /api/boot` Returns information needed to boot the client. Also the recommended way to check whether the current `identity` cookie is valid, and what login it authenticates. #### On success ```json { "login": { "name": "example username", "id": "L1234abcd", } } ``` ## Authentication Other than where noted below, all endpoints require authentication. To authenticate a request, send a `cookie: identity=YOUR TOKEN HERE` header in the request. Tokens can be obtained via the `/api/auth/login` endpoint. This authentication protocol is intended to integrate with browsers and browser-like environments, where the browser handles cookie headers automatically. If the token is not valid or has expired, then `hi` will send back a 401 Unauthorized response, instead of the responses documented for the endpoint the request was intended for. ### `POST /api/auth/login` Authenticates the user by login name and password, creating a login if none exists. **This endpoint does not require an `identity` cookie.** #### Request ```json { "name": "example username", "password": "the plaintext password", } ``` #### On success This endpoint returns a 204 No Content response on success, with a `Set-Cookie` header setting the `identity` cookie to a newly created token for this login. This cookie must be presented in future requests, and will authenticate the associated login. The cookie will expire if it is not used regularly. (As of this writing, identity cookies expire seven days after their last use, but this time period may change.) #### Authentication failures If the login already exists, and the provided password is different from the one used to create the login, then this will return a 401 Unauthorized response. ### `POST /api/auth/logout` Invalidates the identity token, logging the user out. #### Request ```json {} ``` #### On success This endpoint returns a 204 No Content response on success, with a `Set-Cookie` header that clears the `identity` cookie. The cookie provided in the request is also invalidated, and will not authenticate future requests even if the client fails to process the `Set-Cookie` response header. ## Working with channels Channels are the containers for conversations. The API supports listing channels, creating new channels, and send messages to an existing channel. ### `GET /api/channels` Lists channels. #### On success Responds with a list of channel objects, one per channel: ```json [ { "name": "nonsense and such", "id": "C1234abcd", } ] ``` ### `POST /api/channels` Creates a channel. #### Request ```json { "name": "a unique channel name" } ``` #### On succeess ```json { "name": "a unique channel name", "id": "C9876cyyz" } ``` #### On duplicate channel name Channel names must be unique. If a channel with the same name already exists, this will return a 400 Bad Request error. ## Events The API delivers events to clients to update them on other clients' actions and messages. While there is no specific delivery deadline, messages are delivered as soon as possible on a best-effort basis, and the event system allows clients to replay events or resume interrupted streams, to allow recovery if a message is lost. ### `POST /api/channels/:channel` Sends a chat message to a channel. It will be relayed to clients subscribed to the channel's events, and recorded for replay. The `:channel` placeholder must be a channel ID, as returned by `GET /api/channels` or `POST /api/channels`. Chat messages expire after 90 days and can no longer be retrieved at that time. #### Request ```json { "message": "my amazing thoughts, by bob" } ``` #### On success Once the message is accepted, this will return a 202 Accepted response. The message will be delivered to subscribers asynchronously, as soon as is feasible. #### Invalid channel ID If the channel ID is not valid, this will return a 404 Not Found response. ### `GET /api/events` Subscribes to events. This endpoint returns an `application/event-stream` response, and is intended for use with the `EventSource` browser API. Events will be delivered on this stream as they occur, and the request will remain open to deliver events. The returned stream may terminate, to limit the number of outstanding messages held by the server. Clients can and should repeat the request, using the `Last-Event-Id` header to resume from where they left off. Events will be replayed from that point, and the stream will resume. #### Query parameters This endpoint accepts the following query parameters: * `channel`: a channel ID to subscribe to. Events for this channel will be included in the response. This parameter may be provided multiple times. Clients should not subscribe to the same channel more than once in a single request. Browsers generally limit the number of open connections, often to embarrassingly low limits. Clients should subscribe to multiple streams in a single request, and should not subscribe to each stream individually. Requests without a subscription return an empty stream. (If you're wondering: it has to be query parameters or something equivalent to it, since `EventSource` can only issue `GET` requests.) #### Request headers This endpoint accepts an optional `Last-Event-Id` header for resuming an interrupted stream. If this header is provided, it must be set to the `id` field sent with the last event the client has processed. When `Last-Event-Id` is sent, the response will resume immediately after the corresponding event. If this header is omitted, then the stream will start from the beginning. If you're using a browser's `EventSource` API, this is handled for you automatically. The event IDs `hi` sends in `application/event-stream` encoding are ephemeral, and can only be reused within the brief intervals required to reconnect to the event stream. Do not store them, and do not parse them. The message data's `"id"` field is the durable identifier for each message. #### On success The returned event stream is a sequence of events: ```json id: 1234 data: { data: "channel": "C9876cyyz", data: "id": "Mabcd1234", data: "sender": { data: "id": "L1234abcd", data: "name": "example username" data: }, data: "body": "my amazing thoughts, by bob", data: "sent_at": "2024-09-19T02:30:50.915462Z" data: } ```