---
title: "Read Setup Plan"
method: GET
path: "/api/autopilot/setup-plan"
tags: ["autopilot"]
---

# Read Setup Plan

`GET /api/autopilot/setup-plan`

## Request

- Base URL: `https://api.taxcompass.it` (the document declares no server; this is the origin it was published from)
- URL: `https://api.taxcompass.it/api/autopilot/setup-plan`
- Auth: HTTP bearer

The caller's saved Setup Plan intake, or 204 when they have not made one.

The same 204 contract as ``GET /profile``, and for the same reason: the route
exists and the caller is entitled to it, there is simply nothing stored yet —
and 404 is already this router's "the feature is off" signal, so reusing it
here would be ambiguous.

What comes back is the *inputs*, not a plan. ``POST /api/plan`` turns them
into one deterministically, and that is where the rendering belongs: a plan
stored here would go on disagreeing with a recomputed one after any change to
the tax engine, with nothing to say which of the two the user had read.

## Response `200`

Successful Response

- SetupPlanRead: ``GET/PUT /api/autopilot/setup-plan`` — the Setup Plan's saved *inputs*. The inputs, not the rendered plan, and the distinction is the whole design: :func:`app.api.plan.build_plan` is a pure function of a :class:`PlanRequest` (no LLM, no DB, no HTTP), so the plan can always be recomputed from what is stored here — whereas a stored *output* would go on disagreeing with a recomputed one after the first tax-engine change, and there would be no way to tell which of the two the user had actually read. ``updated_at`` is the DB clock, and it is here for the same reason ``RedditiSessionRead`` carries one: this row is written from whichever device the user happens to be on, and "whose copy is newer" is a question the client has to be able to answer without guessing.
  - `inputs` PlanRequest, required: Structured intake answers → one-shot Setup Plan. Five of the Italy pack's six ``critical`` slots are required here; the rest are optional but improve the cross-border risk flags + accountant match. ``regulated_profession`` is the exception — it is **derived** from the activity, not asked (see the field comment), so the intake never poses a question a foreign founder can't answer.
    - `locale` 'en' | 'pl' | 'it' | 'de' | 'fr' | 'es'
    - `current_residency` string, required
    - `target_setup` 'moving_to_italy' | 'staying_abroad' | 'already_in_italy', required
    - `expected_annual_revenue_eur` number, required
    - `activity_description` string, required
    - `impatriate_eligibility` boolean, required
    - `regulated_profession` boolean, nullable
    - `expected_annual_costs_eur` number, nullable
    - `business_type` 'professionista' | 'artigiano' | 'commerciante', nullable
    - `passport_country` string, nullable
    - `permit_status` 'eu_no_permit_needed' | 'has_self_employment' | 'has_other_permit' | 'needs_permit' | 'unsure', nullable
    - `ateco_chosen` string, nullable
    - `single_client_is_employer` boolean, nullable
    - `existing_business` string, nullable
    - `client_situation` string, nullable
    - `family_situation` string, nullable
    - `pension_situation` string, nullable
    - `prior_employment_income_eur` number, nullable
    - `social_security_coverage` 'none' | 'eu_a1' | 'non_eu_totalization' | 'unsure', nullable
    - `days_in_italy_this_year` integer, nullable
    - `urgency` string, nullable
  - `updated_at` string, date-time, nullable

## Other responses

- `204`: No Setup Plan saved yet

---

[API](https://skmtc.dev/taxcompass/apis/taxcompass-api.md) · [All operations](https://skmtc.dev/taxcompass/apis/taxcompass-api/llms.txt) · [OpenAPI document](https://skmtc.dev/taxcompass/apis/taxcompass-api/revisions/fef5fc6a9b91?raw)
