> ## Documentation Index
> Fetch the complete documentation index at: https://docs.invopop.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Finvoice receiving invoices guide

> Import the invoices Finnish trading partners send to your registered parties.

export const fiFinvoiceImportWorkflow = {
  "name": "Finvoice import invoice",
  "description": "Import a received invoice",
  "schema": "bill/invoice",
  "steps": [{
    "id": "bc178046-9172-11f1-ac3d-92000767c8b7",
    "name": "Import received invoice",
    "provider": "gov-fi.import"
  }, {
    "id": "bc178096-9172-11f1-90ae-92000767c8b7",
    "name": "Set folder",
    "provider": "silo.folder",
    "summary": "Set folder to `Invoices · Expenses`{.font-medium}",
    "config": {
      "folder": "expenses"
    }
  }, {
    "id": "bc1780dc-9172-11f1-b338-92000767c8b7",
    "name": "Set state",
    "provider": "silo.state",
    "summary": "Set state to `registered`{.state .registered}",
    "config": {
      "state": "registered"
    }
  }],
  "rescue": [{
    "id": "bc17811a-9172-11f1-ae07-92000767c8b7",
    "name": "Set state",
    "provider": "silo.state",
    "summary": "Set state to `error`{.state .error}",
    "config": {
      "state": "error"
    }
  }]
};

export const fiFinvoiceSyncWorkflow = {
  "name": "Finvoice sync received invoices",
  "description": "Sweep a registered party's inbox at the operator and dispatch import jobs",
  "schema": "org/party",
  "steps": [{
    "id": "bc178004-9172-11f1-b2b4-92000767c8b7",
    "name": "Sync received invoices",
    "provider": "gov-fi.sync"
  }],
  "rescue": []
};

export const WorkflowDiagram = ({workflow}) => {
  const stateColors = {
    processing: "yellow",
    sent: "blue",
    received: "blue",
    registered: "green",
    completed: "green",
    error: "red"
  };
  const StateChip = ({state, label}) => <Badge size="sm" color={stateColors[state] || "gray"} icon="square-small" iconType="solid">
      {label.charAt(0).toUpperCase() + label.slice(1)}
    </Badge>;
  const providerIcons = {
    "silo.state": "https://silo.invopop.com/images/status.svg",
    "silo.close": "https://silo.invopop.com/images/check-badge.svg",
    "silo.if": "https://assets.invopop.com/apps/silo/if.svg",
    "silo.folder": "https://silo.invopop.com/images/folder.svg",
    "silo.modify": "https://silo.invopop.com/images/modify.svg",
    "silo.correct": "https://silo.invopop.com/images/replace.svg",
    "silo.sleep": "https://assets.invopop.com/icons/sleep.svg",
    silo: "https://assets.invopop.com/apps/silo/icon.svg",
    "sequence.enumerate": "https://sequence.invopop.com/images/enumerate.svg",
    "transform.job.create": "https://transform.invopop.com/images/jobs.svg",
    webhook: "https://webhook.invopop.com/icon.svg",
    lookup: "https://lookup.invopop.com/icon.png",
    dropbox: "https://dropbox.invopop.com/icon.png",
    pdf: "https://pdf.invopop.com/file-pdf.svg",
    peppol: "https://assets.invopop.com/apps/peppol/icon.svg",
    ubl: "https://assets.invopop.com/apps/ubl/logo.svg",
    cii: "https://assets.invopop.com/apps/cii/logo.svg",
    "gov-fi": "https://assets.invopop.com/flags/fi.svg",
    "gov-fr": "https://assets.invopop.com/flags/fr.svg",
    "chorus-pro": "https://assets.invopop.com/apps/chroruspro/icon.svg",
    "gov-es": "https://assets.invopop.com/apps/gov-es/icon.svg",
    "gov-es.sii": "https://assets.invopop.com/apps/sii/icon.svg",
    "gov-es.ticketbai": "https://assets.invopop.com/apps/ticketbai/icon.svg",
    "gov-es.facturae": "https://assets.invopop.com/apps/facturae/icon.svg",
    verifactu: "https://assets.invopop.com/apps/verifactu/icon.svg",
    "gov-pl": "https://assets.invopop.com/apps/ksef/icon.svg",
    "gov-sa": "https://assets.invopop.com/apps/zatca/icon.svg",
    "gov-ar": "https://assets.invopop.com/apps/arca/icon.svg",
    "at-pt": "https://assets.invopop.com/apps/at-pt/icon.svg",
    "sat-mx": "https://assets.invopop.com/apps/sat-mexico/icon.svg",
    "sw-sapien": "https://assets.invopop.com/apps/sw-sapien/icon.svg",
    "sdi-it": "https://assets.invopop.com/apps/sdi-italy/icon.svg",
    "ticket-it": "https://assets.invopop.com/apps/agenzia-entrate/icon.svg",
    "nfe-br": "https://assets.invopop.com/apps/notas-fiscais-eletronicas-brazil/icon.svg",
    chargebee: "https://assets.invopop.com/apps/chargebee/icon.svg",
    stripe: "https://assets.invopop.com/apps/stripe/icon.svg",
    email: "https://assets.invopop.com/apps/email/icon.svg",
    cron: "https://assets.invopop.com/apps/cron/icon.svg",
    ilyda: "https://assets.invopop.com/apps/ilyda/icon.svg",
    invoicexpress: "https://assets.invopop.com/apps/invoicexpress/icon.svg",
    plemsi: "https://assets.invopop.com/flags/co.svg"
  };
  const iconFor = provider => {
    const parts = (provider || "").split(".");
    for (let i = parts.length; i > 0; i--) {
      const url = providerIcons[parts.slice(0, i).join(".")];
      if (url) return url;
    }
    return null;
  };
  const StepIcon = ({provider}) => {
    const url = iconFor(provider);
    return <span title={provider} className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-gray-950/10 bg-white dark:border-white/10 dark:bg-white/5">
        {url ? <img src={url} alt="" className="h-4 w-4" /> : null}
      </span>;
  };
  const renderSummary = summary => {
    const nodes = [];
    const re = /`([^`]+)`(\{[^}]*\})?/g;
    let last = 0;
    let m;
    let k = 0;
    while ((m = re.exec(summary)) !== null) {
      if (m.index > last) nodes.push(summary.slice(last, m.index));
      const attrs = m[2] || "";
      if (attrs.indexOf(".state") >= 0) {
        const state = (attrs.match(/\.state\s+\.([\w-]+)/) || [])[1] || m[1];
        nodes.push(<StateChip key={k++} state={state} label={m[1]} />);
      } else if (attrs) {
        nodes.push(<span key={k++} className="text-sm font-medium text-gray-700 dark:text-gray-300">
            {m[1]}
          </span>);
      } else {
        nodes.push(<code key={k++} className="text-sm rounded bg-gray-100 px-1 font-mono text-sm dark:bg-white/10">
            {m[1]}
          </code>);
      }
      last = m.index + m[0].length;
    }
    if (last < summary.length) nodes.push(summary.slice(last));
    return nodes;
  };
  const NoteRow = ({text}) => <div className="mt-4 mb-1 font-mono text-sm leading-5 text-gray-400 dark:text-gray-500">{"// " + text}</div>;
  const renderSteps = (steps, counter) => (steps || []).map(step => {
    counter.n += 1;
    const n = counter.n;
    const branches = (step.next || []).filter(b => b.steps && b.steps.length > 0);
    return <div key={step.id || "step-" + n}>
          {step.notes ? <NoteRow text={step.notes} /> : null}
          <div className="mt-2.5 flex items-center">
            <span className="absolute left-0 w-10 text-center font-mono text-sm text-gray-400 select-none dark:text-gray-500">
              {n}
            </span>
            <div className="flex min-w-0 flex-1 items-center gap-2 rounded-xl border border-gray-950/5 bg-white px-2 py-2 dark:border-white/10 dark:bg-gray-900">
              <StepIcon provider={step.provider} />
              <span className="text-sm shrink-0 font-medium text-gray-900 dark:text-gray-100">{step.name}</span>
              {step.summary ? <span className="text-sm min-w-0 truncate text-gray-500 dark:text-gray-400">{renderSummary(step.summary)}</span> : null}
            </div>
          </div>
          {branches.length > 0 ? <div className="ml-5 border-l border-gray-200 -my-1 py-1 pl-6 dark:border-white/10">
              {branches.map((branch, bi) => <div key={branch.code || branch.status || bi}>
                  <div className="mt-4">
                    <span className="rounded-md bg-gray-200/70 px-2 py-1 font-mono text-sm text-gray-600 dark:bg-white/10 dark:text-gray-300">
                      {branch.code || branch.status}
                    </span>
                  </div>
                  {renderSteps(branch.steps, counter)}
                </div>)}
            </div> : null}
        </div>;
  });
  const counter = {
    n: 0
  };
  const wf = workflow || ({});
  return <div className="not-prose relative my-5 rounded-2xl border border-gray-950/5 bg-gray-50 py-3 pr-4 pb-5 pl-12 dark:border-white/10 dark:bg-white/[0.03]">
      {renderSteps(wf.steps, counter)}
      {wf.rescue && wf.rescue.length > 0 ? <div className="mt-6 border-t border-dashed border-gray-300 dark:border-white/10">
          <NoteRow text="If any step fails" />
          {renderSteps(wf.rescue, counter)}
        </div> : null}
    </div>;
};

## Introduction

Invoices sent to a registered party's e-invoice address land in that party's own inbox at the operator the [Finland app](/apps/finland) works through. The operator has no push channel, so the app **polls** each registered party's inbox on a schedule, every five minutes by default. Received invoices appear within minutes, not instantly; when testing, allow up to a quarter of an hour before suspecting a problem.

Each received document becomes exactly one silo entry carrying the GOBL invoice, the original XML, and a PDF rendering, and your import workflow runs on it, so received invoices show up like any other workflow-processed document.

Registering the parties themselves is covered in the companion guide: [Finvoice supplier registration](/guides/fi-finvoice-supplier).

| -               | Sandbox                                            | Live                                                                       |
| --------------- | -------------------------------------------------- | -------------------------------------------------------------------------- |
| **Party**       | Registered against the operator's test environment | Not yet available (production access is being finalised with the operator) |
| **Environment** | Operator sandbox                                   | Not yet available                                                          |

## Prerequisites

* **The Finland app connected**: navigate to **Configuration** → **Apps**, find **Finland**, and click **Connect**.
* **A party ready to register**: reception is per party, so the setup below has to be in place before you register it. Registration checks the reception configuration and starts polling as soon as it completes.

## Setup

<Steps>
  <Step title="Create the sync workflow">
    This workflow is pure plumbing: the polling schedule fires it for each registered party, and its one step checks the party's inbox and queues one import job per new document.

    <Tabs>
      <Tab title="Workflow">
        <WorkflowDiagram workflow={fiFinvoiceSyncWorkflow} />
      </Tab>

      <Tab title="Code">
        Copy and paste into a new [Empty Party workflow](https://console.invopop.com/redirect/workflows/new?template=empty-party) code view.

        ```json Example Finvoice sync received invoices workflow theme={"system"}
        {
            "name": "Finvoice sync received invoices",
            "description": "Sweep a registered party's inbox at the operator and dispatch import jobs",
            "schema": "org/party",
            "steps": [
                {
                    "id": "bc178004-9172-11f1-b2b4-92000767c8b7",
                    "name": "Sync received invoices",
                    "provider": "gov-fi.sync"
                }
            ],
            "rescue": []
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create the import workflow">
    The import step downloads one received document and files it as a silo entry; everything after it is yours to shape: routing to a folder, setting a state, or any other processing your operation needs.

    <Tabs>
      <Tab title="Workflow">
        <WorkflowDiagram workflow={fiFinvoiceImportWorkflow} />
      </Tab>

      <Tab title="Code">
        Copy and paste into a new [Empty Invoice workflow](https://console.invopop.com/redirect/workflows/new?template=empty-invoice) code view.

        ```json Example Finvoice import invoice workflow theme={"system"}
        {
            "name": "Finvoice import invoice",
            "description": "Import a received invoice",
            "schema": "bill/invoice",
            "steps": [
                {
                    "id": "bc178046-9172-11f1-ac3d-92000767c8b7",
                    "name": "Import received invoice",
                    "provider": "gov-fi.import"
                },
                {
                    "id": "bc178096-9172-11f1-90ae-92000767c8b7",
                    "name": "Set folder",
                    "provider": "silo.folder",
                    "summary": "Set folder to `Invoices · Expenses`{.font-medium}",
                    "config": {
                        "folder": "expenses"
                    }
                },
                {
                    "id": "bc1780dc-9172-11f1-b338-92000767c8b7",
                    "name": "Set state",
                    "provider": "silo.state",
                    "summary": "Set state to `registered`{.state .registered}",
                    "config": {
                        "state": "registered"
                    }
                }
            ],
            "rescue": [
                {
                    "id": "bc17811a-9172-11f1-ae07-92000767c8b7",
                    "name": "Set state",
                    "provider": "silo.state",
                    "summary": "Set state to `error`{.state .error}",
                    "config": {
                        "state": "error"
                    }
                }
            ]
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure the app with both workflows">
    Navigate to **Configuration** → **Apps**, find the **Finland** app, tap **Configure**, and select the sync workflow and the import workflow you just created. Registration checks this configuration, so save it before registering any party.
  </Step>

  <Step title="Register the party">
    Run the registration workflow on the party as described in the [supplier registration guide](/guides/fi-finvoice-supplier#register-a-supplier). Registration checks the reception configuration first and fails with "reception not configured" if the workflows aren't set; polling starts automatically once it completes.
  </Step>
</Steps>

## Receiving invoices

From then on, reception is automatic. Every few minutes the app checks each registered party's inbox, and each new document becomes one silo entry processed by your import workflow, filed under **Expenses** in the example above.

A few behaviours worth knowing:

* **The registry catches up overnight.** A registered party can receive immediately, but the [national registry](https://verkkolaskuosoite.fi) senders look addresses up in is refreshed once a night. A counterparty who can't find the address on the day you registered will normally find it the next day.
* **Duplicates collapse.** The operator can occasionally deliver the same document twice; the app keys every entry by the document's own identity, so a repeated delivery updates the existing entry instead of creating a second one.
* **Errors stay visible.** A document that fails to import leaves a failed job behind, and the rescue steps of your import workflow run so you can see what went wrong and act on it.
* **Retention at the operator is limited.** Received documents stay downloadable at the operator for three calendar months; the silo entry and its attachments are yours permanently.

## FAQ

<AccordionGroup>
  <Accordion title="How quickly do received invoices appear?">
    Reception is polled, not pushed: each registered party's inbox at the operator is swept on a schedule, every five minutes by default. Add the time the sender's own operator takes to deliver, and an invoice normally appears within minutes, but not instantly. If you're testing, allow up to a quarter of an hour before suspecting a problem.
  </Accordion>

  <Accordion title="What format do received invoices arrive in?">
    Each received document becomes one entry in your workspace carrying the GOBL invoice, the original XML as received from the network, and a PDF rendering, whatever format the sender issued.
  </Accordion>

  <Accordion title="What setup does receiving need?">
    Two things: the Finland app must be configured with a sync workflow and an import workflow, and the party must be registered. Registration checks the workflow configuration first, so set the workflows up before running it. Once registered, polling starts automatically; received invoices simply appear as new entries processed by your import workflow.
  </Accordion>
</AccordionGroup>

More available in our [Finland FAQ](/faq/finland) section

***

<AccordionGroup>
  <Accordion title="🇫🇮 Invopop resources for Finland">
    |            |                                                                                                                                                                                                                                                                                        |
    | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Compliance | <Icon icon="https://assets.invopop.com/flags/fi.svg" /> [Invoicing compliance in Finland](/compliance/finland)<br /> <Icon icon="timeline" /> [Compliance timeline](/timelines/finland)                                                                                                |
    | Apps       | <Icon icon="https://assets.invopop.com/flags/fi.svg" /> [Finland](/apps/finland)<br /> <Icon icon="https://assets.invopop.com/apps/peppol/icon.svg" /> [Peppol](/apps/peppol)                                                                                                          |
    | Guides     | <Icon icon="book" /> [Supplier registration](/guides/fi-finvoice-supplier)<br /> <Icon icon="book" /> [Issuing invoices](/guides/fi-finvoice)<br /> <Icon icon="book" /> [Receiving invoices](/guides/fi-finvoice-receiving)<br /> <Icon icon="book" /> [Peppol guide](/guides/peppol) |
    | FAQ        | <Icon icon="square-question" /> [Finland FAQ](/faq/finland)                                                                                                                                                                                                                            |
    | GOBL       | <Icon icon="https://assets.invopop.com/icons/gobl.svg" /> [Finland Tax Regime](https://docs.gobl.org/regimes/fi)<br /> <Icon icon="https://assets.invopop.com/icons/gobl.svg" /> [EU EN 16931 Addon](https://docs.gobl.org/addons/eu-en16931-v2017)                                    |
    | GitHub     | <Icon icon="github" /> [gobl.fi.finvoice](https://github.com/invopop/gobl.fi.finvoice)<br /> <Icon icon="github" /> [gobl.ubl](https://github.com/invopop/gobl.ubl)                                                                                                                    |
  </Accordion>
</AccordionGroup>

<Card title="Participate in our community" icon="forumbee" href="https://community.invopop.com" arrow="true" horizontal>
  Ask and answer questions about invoicing in Finland →
</Card>
