← Help

Import file format

Import lives in Settings → Data → Import data. It takes two kinds of input — a JSON file, or a plain list — and works out which one you gave it on its own. You never pick a format.

Nothing is written to your account until you have seen the preview and confirmed it.

Three situations cover almost everything:

From a list you already have

The quickest route, and it needs no file at all: paste your list into the box on the import page, or drop it in as a .txt or .md file.

## Birthday

- [Sony WH-1000XM5](https://www.amazon.de/dp/B09XS7JWHH)
- Wool blanket — https://shop.com/wool-blanket
- [x] Kettle
- A long walk with a friend

## Kitchen

- https://shop.com/p/9912

One item per line. A ## heading starts a new list; anything above the first heading goes into the list you chose on the import page. Bullets, numbers and checkboxes are understood, and lines that are only a link still get a name. The exact rules are under How a pasted list is read, further down.

From another app

Most wishlist apps can export your data, but no two of them agree on a format. Rather than convert it by hand, hand both halves to a chat assistant — ChatGPT, Claude, Gemini — and let it do the reformatting.

  1. Export your wishlist from the other app, however that app does it.
  2. Copy the prompt below into the assistant, followed by your export. A screenshot, a page of notes or a pile of links works just as well as a real export file.
  3. Save the reply as a file ending in .json.
  4. Drop that file on the import page.
Turn my wishlist into a Things To Have import file. Follow the format documented at https://thingstohave.app/help/import-format exactly: one JSON object with "schemaVersion": 1, a "lists" array and a "things" array, where each list references its items by their ids in "thingIds". Reply with the JSON only.

Agents get things wrong, so read the preview before you confirm — it lists every item that will be created, and nothing is written to your account until you say so.

From a Things To Have export

Settings → Data → Export my data produces a file in exactly the format described below, so an export always imports back cleanly — the same lists, the same items, their original dates. Anything that was in no list lands in the list you chose on the import page. Use it to move things to another account, or to put back something you deleted.

Two things do not survive the round trip: images are never imported, and neither are followers or settings.

The JSON format

The file is one JSON object with three parts:

  • schemaVersion — must be 1. A file without it, or with any other version, is rejected.
  • lists — the lists to create. Each list references the things in it by their ids, through thingIds.
  • things — the items themselves. A thing that no list mentions goes into the list you chose on the import page.

Fields

FieldWhereRequiredNotes
idbothyesAny number, unique within the file. Used to link the two.
namebothyesAn item or list without a name is skipped.
descriptionlistsnoFree text.
isPubliclistsnotrue makes the list publicly visible. Defaults to false.
defaultViewModelistsno"list" or "grid".
thingIdslistsnoThe ids of the things in this list.
urlthingsnoMust be an http(s) link. Stored exactly as written.
notethingsnoFree text.
price + currencythingsnoA number plus a currency, or one string like "120 USD".
identifierthingsnoYour own reference, e.g. a model number.
isOwnedthingsnotrue marks the item as already owned.
createdAtbothnoISO date. Kept as written, so history survives a round trip.

A price always needs a currency. "price": 120 on its own is skipped; "price": 120, "currency": "USD" is fine.

A complete example

{
  "schemaVersion": 1,
  "lists": [
    {
      "id": 1,
      "name": "Birthday",
      "description": "Things I would love",
      "isPublic": true,
      "defaultViewMode": "grid",
      "thingIds": [1, 2]
    },
    {
      "id": 2,
      "name": "Kitchen",
      "isPublic": false,
      "thingIds": [3]
    }
  ],
  "things": [
    {
      "id": 1,
      "name": "Sony WH-1000XM5",
      "url": "https://www.amazon.de/dp/B09XS7JWHH",
      "note": "Black, not silver",
      "price": 379,
      "currency": "EUR"
    },
    {
      "id": 2,
      "name": "Wool blanket",
      "isOwned": true
    },
    {
      "id": 3,
      "name": "Kettle",
      "url": "https://shop.com/p/9912",
      "price": "49.90 USD",
      "identifier": "KT-9912"
    }
  ]
}

How a pasted list is read

Anything that is not JSON is read line by line. Blank lines are ignored, and -, * and 1. prefixes are stripped.

  • A ## heading starts a new list named after the heading. Items above the first heading go into the list you chose on the import page.
  • [Name](link) uses the name and the link.
  • Text before a link becomes the name; trailing dashes, colons and pipes are trimmed off.
  • A bare link is named after the readable part of its address — https://shop.com/wool-blanket becomes "Wool blanket", and https://shop.com/p/9912 falls back to "shop.com".
  • A line with no link becomes an item with just a name.
  • - [x] imports the item as already owned.

Limits

  • Files must be .txt, .json or .md, up to 2 MB and 1,000 items per import.
  • Import never deduplicates. A link you already have is imported again, and the same link twice in one file becomes two items.
  • Rows that cannot be imported — no name, a price that cannot be read, an invalid link, a field that is too long — are listed on the result screen and can be downloaded, corrected and imported again.