Skip to content

Together Server Export

This document describes the server data export feature — a single endpoint that lets a server owner download a complete archive of their server's data.

Overview

The export endpoint builds a ZIP archive in memory from live database queries and streams it back as a download. Nothing is written to disk on the server.


Endpoint

GET /servers/:id/export

Download a ZIP archive containing all server data.

Authentication: Requires a valid access token (Authorization: Bearer <jwt>).

Authorization: The authenticated user must be the server owner (servers.owner_id). Non-owners (including admins and moderators) receive 404 Not Found — the response intentionally does not reveal whether the server exists, to avoid leaking information to non-members.

Response (200 OK):

  • Content-Type: application/zip
  • Content-Disposition: attachment; filename="{server-slug}-export-{YYYYMMDD}.zip"
  • Content-Length: <byte count>

The filename is derived from the server name (slugified to lowercase alphanumeric and hyphens) and the current date.


ZIP File Structure

{server-slug}-export/
├── server.json
├── channels.json
├── members.json
├── roles.json
├── messages/
│   ├── {channel-slug}-{channel-id}.jsonl
│   └── ...
└── dm_messages/
    ├── {partner-slug}-{dm-channel-id}.jsonl
    └── ...

server.json

Server metadata (pretty-printed JSON):

FieldTypeDescription
idUUIDServer ID
namestringServer name
owner_idUUIDOwner's user ID
icon_urlstring | nullServer icon URL
is_publicbooleanWhether the server is public
created_atdatetimeCreation timestamp

channels.json

All channels in the server, ordered by position (pretty-printed JSON array):

FieldTypeDescription
idUUIDChannel ID
namestringChannel name
channel_typestring"text" or "voice"
positionintegerDisplay order
categorystring | nullCategory name
topicstring | nullChannel topic
created_atdatetimeCreation timestamp

members.json

All server members, ordered by join date (pretty-printed JSON array). No credentials or password hashes are included.

FieldTypeDescription
user_idUUIDUser ID
usernamestringUsername
nicknamestring | nullServer-specific nickname
joined_atdatetimeWhen they joined

roles.json

All roles defined in the server, ordered by position (pretty-printed JSON array):

FieldTypeDescription
idUUIDRole ID
namestringRole name
permissionsintegerPermission bitflags (i64)
colorstring | nullRole color
hoistbooleanWhether the role is displayed separately
positionintegerRole hierarchy position

messages/{channel-slug}-{channel-id}.jsonl

One file per text channel that has messages. Voice channels are skipped. Each file uses newline-delimited JSON (one JSON object per line). Only non-deleted messages are included, ordered by creation time ascending.

FieldTypeDescription
idUUIDMessage ID
author_idUUID | nullAuthor's user ID
author_usernamestring | nullAuthor's username at export time
contentstringMessage content
reply_toUUID | nullID of the message being replied to
edited_atdatetime | nullLast edit timestamp
created_atdatetimeCreation timestamp

dm_messages/{partner-slug}-{dm-channel-id}.jsonl

The requesting user's direct messages, one file per DM conversation. Only included if the DM channel has messages. Each file uses newline-delimited JSON, ordered by creation time ascending.

FieldTypeDescription
idUUIDMessage ID
author_idUUID | nullAuthor's user ID
author_usernamestring | nullAuthor's username at export time
contentstringMessage content
created_atdatetimeCreation timestamp

Permissions

Only the server owner can export. The ownership check queries servers.owner_id directly. If the caller is not the owner, the endpoint returns 404 Not Found (not 403 Forbidden) to avoid confirming server existence to unauthorized users.


Error Cases

StatusCondition
401Missing or invalid access token
404Server not found or caller is not the owner
429Rate limit exceeded
500Internal error during ZIP construction

Performance Considerations

  • The entire ZIP archive is built in memory before being sent. For servers with large message histories, this means the server process will temporarily allocate memory proportional to the total size of all exported messages.
  • All message queries fetch the full result set per channel (fetch_all), so a single channel with a very large number of messages will result in a correspondingly large allocation.
  • ZIP compression uses the Deflate method, which reduces the final download size but adds CPU overhead during construction.
  • There is no streaming or pagination — the response is sent only after the complete archive is built. Clients should expect longer response times for servers with extensive histories.
  • File attachments and uploaded media are not included in the export. Only message text and metadata are exported.