---
title: "Plan"
method: POST
path: "/api/plan"
tags: ["plan"]
---

# Plan

`POST /api/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/plan`
- Auth: none declared

## Request body

- PlanRequest: 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

## Response `200`

Successful Response

- PlanResponse: One-shot Setup Plan: the draft + brief + deterministic number cards.
  - `draft` CompanyRequestDraft: Output of the summarise node — what the user previews and signs off on. Fields use Italian-pack literals for v1; a v2 country-pack expansion will widen the unions or move them onto the pack itself (see plan).
    - `id` string, required
    - `summary_md` string, required
    - `sentences` CitedSentence[]
      - `text` string, required
      - `chunk_ids` string[]
    - `ateco_candidates` AtecoCandidate[]
      - `code` string, required
      - `title` string, required
      - `title_en` string, nullable
      - `rationale` string, required
      - `coefficiente` integer, nullable
      - `chunk_id` string, nullable
      - `url` string, nullable
    - `recommended_regime` 'forfettario' | 'ordinario_with_impatriate' | 'ordinario' | 'semplificato', nullable
    - `recommended_social_scheme` 'inps_gestione_separata' | 'inps_artigiani_commercianti' | 'cassa_professionale', nullable
    - `cassa_name` string, nullable
    - `impatriate_eligible` boolean, nullable
    - `forfettario_vs_impatriate_comparison` object, nullable
    - `matched_accountant` AccountantMatch
      - `accountant_id` string, required
      - `name` string, required
      - `firm` string, nullable
      - `matched_specialties` string[]
      - `matched_languages` string[]
      - `city` string, nullable
      - `rationale` string
    - `risk_flags` string[]
  - `text` string
  - `markdown` string
  - `sentences` CitedSentence[]
    - `text` string, required
    - `chunk_ids` string[]
  - `chunks` ChunkManifestEntry[]
    - `chunk_id` string, required
    - `source` string, required
    - `title` string, nullable
    - `url` string, nullable
    - `similarity` number, nullable
    - `text` string, nullable
    - `highlights` string[]
  - `profile` InterviewProfile: All onboarding-interview state for a single conversation. The router/interview/summarise nodes mutate this; QA-mode turns pass it through unchanged so slot chips never disappear if the user takes a detour to ask a freeform question.
    - `slots` object
    - `intent` 'unknown' | 'create_company' | 'qa_only' | 'both'
    - `ready_to_summarise` boolean
    - `country` 'IT'
  - `breakdowns` Breakdown[]
    - `country` string, required
    - `regime` string, required
    - `revenue_local` number, required
    - `revenue_eur` number, required
    - `currency` 'EUR' | 'PLN' | 'RON', required
    - `social_contributions` number
    - `health_contribution` number
    - `income_tax` number
    - `substitute_tax` number
    - `other_deductions` number
    - `net_local` number
    - `net_eur` number
    - `effective_rate` number, nullable
    - `eligible` boolean
    - `contributions_are_stand_in` boolean
    - `assumptions` string[]
    - `notes` string[]

## Other responses

- `422`: Validation Error

---

[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)
