---
name: vakantio
description: >-
  Read, write, and publish travel-blog content on https://vakantio.de via
  the official `@vakantio/cli` command-line tool or `@vakantio/sdk`
  TypeScript library. Use when the user wants to create, update, fetch,
  publish, or delete posts, drafts, blogs, trips, comments, destinations,
  media, or notifications on Vakantio — or asks how to interact with
  Vakantio programmatically. Reading public posts is unauthenticated;
  authoring requires a session via `vakantio login` or the
  `VAKANTIO_SESSION_ID` env var.
---

# Vakantio

> Vakantio is where travelers keep a running journal of a trip — posts,
> photos, an itinerary on a map — and decide who sees it. A blog at
> https://vakantio.de can be open to the whole web, or limited to a
> follower list so friends and family can follow along in real time
> without anything being indexed publicly. Anything a human can do on
> the site, an agent can do programmatically via the official CLI
> (`@vakantio/cli`) or TypeScript SDK (`@vakantio/sdk`).

Reading public posts is open and unauthenticated. Authoring (creating
posts, drafts, trips, comments, follows, bookmarks) and reading
follower-only content requires a session.

The API is served at `https://api.vakantio.de`.

## CLI quickstart

```sh
npm i -g @vakantio/cli
vakantio login                   # opens browser, persists ~/.vakantio/config.json
vakantio whoami                  # confirms the session works
vakantio search "tuscany" --json # every command supports --json
```

## Login from a sandbox / container / agent

If you're running in an environment that can't accept a `127.0.0.1` OAuth
callback (ChatGPT Code Interpreter, Codex sandbox, GitHub Codespace, CI
runner, plain SSH session, Docker container, etc.), use the device flow:

```sh
vakantio login --device
```

The CLI prints a URL and a short code (e.g. `BCDF-9X4P`). Relay both to the
user — they open the URL on whatever device they're already signed into
Vakantio on (laptop, phone, doesn't matter), enter the code, click Approve.
The CLI is polling in the background; once the user approves, the next
poll succeeds and `vakantio login` exits with the session saved. No
callback URL, no copy-paste of secrets back into the chat.

The CLI auto-detects most sandboxed environments (no `DISPLAY`, `$CI`,
`$CODESPACES`, `$CONTAINER`, no TTY on stdout) and falls back to the
device flow without `--device`. Set `VAKANTIO_FORCE_LOOPBACK=1` to
override that auto-detection, or `VAKANTIO_DEVICE_FLOW=1` to force the
device flow even on a normal laptop.

If even printing the URL is awkward (you already have a long-lived
session for this user from elsewhere), pass it via `VAKANTIO_SESSION_ID`
instead and skip `vakantio login` entirely.

Every command accepts `--json` (machine-readable output) and `--profile <name>`
(alternate `~/.vakantio/<name>.json` config, for juggling multiple accounts).
Auth-required commands are marked **(auth)** below.

## Commands

### Auth
- `vakantio login` — browser OAuth (loopback callback); stores `sessionId` at `~/.vakantio/config.json`
- `vakantio login --device` — RFC 8628 device flow; use this in any environment that can't accept a `127.0.0.1` callback (sandboxes, containers, Codespaces, CI, headless SSH). The CLI prints a URL + short code; the user opens the URL on a device they're already signed into Vakantio on, enters the code, clicks Approve. No callback URL or copy-paste of secrets required.
- `vakantio logout` — clear the local session
- `vakantio whoami [--refresh]` **(auth)** — show / re-fetch the current user

### Posts and drafts
- `vakantio posts list [--page N] [--tags ...] [--destination <id>] [--locale de|en]` — public feed
- `vakantio posts get <id|path> [--draft]` — single post (drafts require auth)
- `vakantio posts create --title <t> [--content <html|@file.html>] [--tags ...] [--lat --lng] [--date-traveled <iso>] [--media <file> ...] [--trip <tripId>]` **(auth)** — `--media` accepts images and videos; on `posts update` the new files are appended to the existing media list rather than replacing it
- `vakantio posts update <id> [...same flags]` **(auth)**
- `vakantio posts publish <id>` / `vakantio posts unpublish <id>` **(auth)**
- `vakantio posts delete <id>` **(auth)** — drafts only
- `vakantio posts like|unlike|bookmark|unbookmark <id>` **(auth)**
- `vakantio drafts list` **(auth)** — drafts on the active blog

### Blogs (a "blog" is one user's travel journal)
- `vakantio blogs list` **(auth)**
- `vakantio blogs create --name <n> [--description <d>] [--locale de|en] [--instagram <url>] [--image <file>] [--header-image <file>] [--switch]` **(auth)**
- `vakantio blogs switch <blogId>` **(auth)** — set the active blog for write commands
- `vakantio blogs get [<path>]` — blog metadata (defaults to active blog)
- `vakantio blogs stats [<path>]` **(auth)** — view counts, top posts
- `vakantio blogs update [--name] [--description] [--image <file>] [--header-image <file>] [--instagram <url>] [--locale de|en]` **(auth)**
- `vakantio blogs follow <blogId>` / `vakantio blogs unfollow <blogId>` **(auth)**

### Destinations, search
- `vakantio destinations list [--parent <id>] [--type country|state|city] [--limit N]`
- `vakantio destinations get <id>`
- `vakantio destinations search "<query>" [--limit N]` — find a destination by name
- `vakantio search "<query>" [--limit N]` — full-text across posts, blogs, destinations
- `vakantio search ["<query>"] --lat N --lng N [--radius-km 50]` — geo-scoped post search; `<query>` is optional, so bare geo works too

Media uploads happen via `posts create/update --media <file>` (and the
blog-avatar `blogs create/update --image <file> --header-image <file>`
flags). There is no standalone `vakantio media upload` command.

### Trips, comments, notifications
- `vakantio trips list|get|create|update|delete` (writes **auth**)
- `vakantio comments list <postId>` / `vakantio comments create <postId> --text <t>` **(auth for writes)**
- `vakantio notifications list [--unread]` / `vakantio notifications mark-read [<id>...]` **(auth)**

## SDK direct use

The CLI is a thin wrapper around `@vakantio/sdk`; every command maps 1:1
to an SDK call. To call the API directly from TypeScript:

```ts
import { createVakantio } from "@vakantio/sdk";
const vak = createVakantio(process.env.VAKANTIO_SESSION_ID);
const posts = await vak.posts.list({ tags: "thailand" });
```

## Identify your client

The CLI and SDK already send a structured `User-Agent` plus an
`X-Vakantio-Client` header that name the tool, its version, and the
runtime. If you're calling the API yourself (curl, fetch, your own
wrapper), please send a `User-Agent` that names your tool and gives a
contact path. Good examples:

```
User-Agent: my-blog-importer/0.3 (+https://github.com/me/my-blog-importer)
User-Agent: agentname-research/2026-05 (contact: ops@example.com)
```

Requests without a User-Agent, or with a generic `curl` / `bot` /
`crawler` / `scraper` string, may be rejected with HTTP 403.

## Also available

- [vakantio.de/llms.txt](https://vakantio.de/llms.txt) — this body, served as `text/plain` per the llms.txt spec
- [vakantio.de/skill.md](https://vakantio.de/skill.md) — this body wrapped in Claude Skills / Cursor Agent Skills YAML frontmatter, served as `text/markdown` for direct ingestion as an agent skill
- [vakantio.de/robots.txt](https://vakantio.de/robots.txt) — crawler rules
