Accounts and the graph

Data exports and imports

import-export-service

A person's copy of their own data: asking for one, seeing how it is getting on, fetching it and giving it up (data-export.md); and bringing their lists in from a file (moving.md (opens in a new tab)). Optional: an installation may not run it.

The viewer's exports

GET/exports

And how often they may ask, how long an archive is kept, and when they may next ask.

Who: Somebody signed in

Answers

Request

curl "https://api.example.org/exports" \
  -H "Authorization: Bearer $TOKEN"

Answer · 200

{
  "data": [
    {
      "created_at": "2026-10-27T09:30:00Z",
      "download_url": "https://example.org/",
      "error": "string",
      "expires_at": "2026-10-27T09:30:00Z",
      "id": "string",
      "ready_at": "2026-10-27T09:30:00Z",
      "size_bytes": 1,
      "status": "string"
    }
  ],
  "every_days": 1,
  "keep_days": 1,
  "next_at": "2026-10-27T09:30:00Z"
}

Ask for a copy of the viewer's data

POST/exports

Everything they wrote, as a zip archive made in the background: GET /exports/:id says when it is ready, with where to fetch it. One at a time, and one a week unless the installation says otherwise (EXPORT_EVERY_DAYS).

Who: Somebody signed in, who has just proved who they are again

Answers

  • 201
    Created
    importexport.ExportItem application/json
  • 401
    no token, or one that has expired
  • 403
    step_up_required: the viewer must prove who they are again first (/reauth)
    Refusal application/json
  • 409
    active: one is being made
    Refusal application/json
  • 429
    too_soon: it is not yet time to ask again, and it says when
    importexport.TooSoon application/json

Request

curl -X POST "https://api.example.org/exports" \
  -H "Authorization: Bearer $TOKEN"

Answer · 201

{
  "created_at": "2026-10-27T09:30:00Z",
  "download_url": "https://example.org/",
  "error": "string",
  "expires_at": "2026-10-27T09:30:00Z",
  "id": "string",
  "ready_at": "2026-10-27T09:30:00Z",
  "size_bytes": 1,
  "status": "string"
}

How an export is getting on

GET/exports/{id}

Once it is ready, with an address to fetch it from, good for a few minutes and made afresh each time this is read.

Who: Somebody signed in

Parameters

  • idstringrequiredin path
    The export's id: a UUID.

Answers

Request

curl "https://api.example.org/exports/<id>" \
  -H "Authorization: Bearer $TOKEN"

Answer · 200

{
  "created_at": "2026-10-27T09:30:00Z",
  "download_url": "https://example.org/",
  "error": "string",
  "expires_at": "2026-10-27T09:30:00Z",
  "id": "string",
  "ready_at": "2026-10-27T09:30:00Z",
  "size_bytes": 1,
  "status": "string"
}

Give an export up

DELETE/exports/{id}

Stops it being made, or deletes its archive once it is.

Who: Somebody signed in

Parameters

  • idstringrequiredin path
    The export's id: a UUID.

Answers

  • 204
    given up, or it was over already
  • 401
    no token, or one that has expired
  • 404
    the viewer has no such export

Request

curl -X DELETE "https://api.example.org/exports/<id>" \
  -H "Authorization: Bearer $TOKEN"

The viewer's imports

GET/imports

The latest five, newest first, each with how far it has got.

Who: Somebody signed in

Answers

Request

curl "https://api.example.org/imports" \
  -H "Authorization: Bearer $TOKEN"

Answer · 200

{
  "data": [
    {
      "created_at": "2026-10-27T09:30:00Z",
      "file_name": "string",
      "finished_at": "2026-10-27T09:30:00Z",
      "id": "string",
      "kinds": [
        null
      ],
      "source": "string",
      "started_at": "2026-10-27T09:30:00Z",
      "status": "string"
    }
  ]
}

Read a file to import

POST/imports

Another Anahita's download, as a zip, or a single CSV, Mastodon's or Misskey's: who the viewer follows, blocks and mutes, and what they saved. Read at once and kept, ready, with how many of each kind; nothing is done until it is started. One at a time; at most 20,000 lines and 20 MB.

Who: Somebody signed in, with socialgraph:write

Body multipart/form-data

  • filefilerequired
    The file: another Anahita's download (zip), or a CSV.
  • kindstring
    What a CSV with no header is: "follow", "block", "mute" or "save". Asked of the person when the file says nothing (kind_unknown).

Answers

  • 201
    Created
    importexport.ImportItem application/json
  • 400
    the file could not be read: empty, unreadable, too_large, too_many_lines, not_supported (lists, blocked servers), or kind_unknown: a CSV with no header, whose kind the viewer is to say
    Refusal application/json
  • 401
    no token, or one that has expired
  • 403
    insufficient_scope
    Refusal application/json
  • 409
    active: one is waiting or running
    Refusal application/json

Request

curl -X POST "https://api.example.org/imports" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@photo.jpg" \
  -F "kind=string"

Answer · 201

{
  "created_at": "2026-10-27T09:30:00Z",
  "file_name": "string",
  "finished_at": "2026-10-27T09:30:00Z",
  "id": "string",
  "kinds": [
    {
      "already": 1,
      "done": 1,
      "failed": 1,
      "kind": "string",
      "left": 1,
      "skipped": 1,
      "total": 1
    }
  ],
  "source": "string",
  "started_at": "2026-10-27T09:30:00Z",
  "status": "string"
}

How an import is getting on

GET/imports/{id}

Who: Somebody signed in

Parameters

  • idstringrequiredin path
    The import's id.

Answers

Request

curl "https://api.example.org/imports/<id>" \
  -H "Authorization: Bearer $TOKEN"

Answer · 200

{
  "created_at": "2026-10-27T09:30:00Z",
  "file_name": "string",
  "finished_at": "2026-10-27T09:30:00Z",
  "id": "string",
  "kinds": [
    {
      "already": 1,
      "done": 1,
      "failed": 1,
      "kind": "string",
      "left": 1,
      "skipped": 1,
      "total": 1
    }
  ],
  "source": "string",
  "started_at": "2026-10-27T09:30:00Z",
  "status": "string"
}

Give an import up

DELETE/imports/{id}

What it has not done is not done; what it did stays.

Who: Somebody signed in

Parameters

  • idstringrequiredin path
    The import's id.

Answers

  • 204
    given up, or it was over already
  • 401
    no token, or one that has expired
  • 404
    the viewer has no such import

Request

curl -X DELETE "https://api.example.org/imports/<id>" \
  -H "Authorization: Bearer $TOKEN"

What an import could not do

GET/imports/{id}/failed

A CSV: the kind, who or what, the name, and why in a word.

Who: Somebody signed in

Parameters

  • idstringrequiredin path
    The import's id.

Answers

  • 200
    the file
    file text/csv
  • 401
    no token, or one that has expired
  • 404
    the viewer has no such import

Request

curl "https://api.example.org/imports/<id>/failed" \
  -H "Authorization: Bearer $TOKEN"

Start an import

POST/imports/{id}/start

With the kinds the viewer chose; the lines of the others are skipped. Each line is then done as the viewer would by hand, a line a second, in the background.

Who: Somebody signed in

Parameters

  • idstringrequiredin path

Body application/json

  • kindslist of string
    The kinds to bring in, of those the file has: "follow", "block", "mute", "save".

Answers

  • 200
    OK
    importexport.ImportItem application/json
  • 400
    the request is not well formed, or a value in it is not one it may be
  • 401
    no token, or one that has expired
  • 404
    the viewer has no such import
  • 409
    not_ready: started or given up already
    Refusal application/json

Request

curl -X POST "https://api.example.org/imports/<id>/start" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kinds": [
      "string"
    ]
  }'

Answer · 200

{
  "created_at": "2026-10-27T09:30:00Z",
  "file_name": "string",
  "finished_at": "2026-10-27T09:30:00Z",
  "id": "string",
  "kinds": [
    {
      "already": 1,
      "done": 1,
      "failed": 1,
      "kind": "string",
      "left": 1,
      "skipped": 1,
      "total": 1
    }
  ],
  "source": "string",
  "started_at": "2026-10-27T09:30:00Z",
  "status": "string"
}

Written by Claude, reviewed by Rastin Mehr · About this