> ## 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.

# NemHandel receiving invoices guide

> Import the OIOUBL documents Danish trading partners send to your registered parties.

export const dkNemhandelImportWorkflow = {
  "name": "Import NemHandel invoice",
  "description": "Import a received OIOUBL document delivered via NemHandel",
  "schema": "bill/invoice",
  "steps": [{
    "id": "a1c0f2df-4f6a-11f1-9c2d-0242ac120010",
    "name": "Load from NemHandel",
    "provider": "gov-dk.import",
    "summary": "Fetches, parses OIOUBL, and converts to GOBL in one step"
  }, {
    "id": "a1c0f2e2-4f6a-11f1-9c2d-0242ac120010",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `received`{.state .received}",
    "config": {
      "state": "received"
    }
  }],
  "rescue": [{
    "id": "a1c0f2e3-4f6a-11f1-9c2d-0242ac120010",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `error`{.state .error}",
    "config": {
      "state": "error"
    }
  }]
};

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-dk": "https://assets.invopop.com/flags/dk.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

Documents sent to a registered party's NemHandel participant are pushed to Invopop the moment they arrive: eCourier notifies the [Denmark app](/apps/denmark) by webhook, and the app starts your import workflow for each document. There is no polling schedule to wait for — received invoices show up as soon as the network delivers them.

Each received document becomes exactly one silo entry carrying the GOBL invoice, the original OIOUBL XML, and any binary attachments embedded in it, so received invoices show up like any other workflow-processed document.

Registering the parties themselves is covered in the companion guide: [NemHandel supplier registration](/guides/dk-nemhandel-supplier).

| -               | Sandbox                                        | Live                                     |
| --------------- | ---------------------------------------------- | ---------------------------------------- |
| **Party**       | Registered against eCourier's test environment | Registered on the live NemHandel network |
| **Environment** | eCourier sandbox                               | eCourier production                      |

## Prerequisites

* **The Denmark app connected**: navigate to **Configuration** → **Apps**, find **Denmark**, and click **Connect**.
* **A party ready to register**: inbound routing is created when a party is registered, so set up the import workflow below before registering it.

## Setup

<Steps>
  <Step title="Create the import workflow">
    The import step fetches one received document, parses the OIOUBL, and files it as a GOBL silo entry with the original XML and its embedded attachments; everything after it is yours to shape: routing to a folder, setting a state, or any other processing your operation needs.

    <Card iconType="duotone" title="Import NemHandel invoice workflow" icon="code-branch" href="https://console.invopop.com/redirect/workflows/new?template=dk-import" horizontal>
      Add to my workspace →
    </Card>

    <Tabs>
      <Tab title="Workflow">
        <WorkflowDiagram workflow={dkNemhandelImportWorkflow} />
      </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 Import NemHandel invoice workflow theme={"system"}
        {
            "name": "Import NemHandel invoice",
            "description": "Import a received OIOUBL document delivered via NemHandel",
            "schema": "bill/invoice",
            "steps": [
                {
                    "id": "a1c0f2df-4f6a-11f1-9c2d-0242ac120010",
                    "name": "Load from NemHandel",
                    "provider": "gov-dk.import",
                    "summary": "Fetches, parses OIOUBL, and converts to GOBL in one step"
                },
                {
                    "id": "a1c0f2e2-4f6a-11f1-9c2d-0242ac120010",
                    "name": "Set State",
                    "provider": "silo.state",
                    "summary": "Set state to `received`{.state .received}",
                    "config": {
                        "state": "received"
                    }
                }
            ],
            "rescue": [
                {
                    "id": "a1c0f2e3-4f6a-11f1-9c2d-0242ac120010",
                    "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 the import workflow">
    Navigate to **Configuration** → **Apps**, find the **Denmark** app, tap **Configure**, and select the import workflow you just created. Every inbound document is handed to this workflow, so save the configuration 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/dk-nemhandel-supplier#register-a-supplier). Registration records the participant → workspace routing that inbound delivery depends on.
  </Step>
</Steps>

## Receiving invoices

From then on, reception is automatic: each document sent to a registered party becomes one silo entry processed by your import workflow.

A few behaviours worth knowing:

* **Delivery is push, not polling.** The network's webhook triggers the import within moments of a document arriving.
* **Documents are acknowledged only after import succeeds.** A failure partway through leaves the document ready on the network to retry, so nothing is lost to a transient error; the network redelivers on its own schedule.
* **Unsupported document types are surfaced, not looped.** The current release imports invoices and credit notes. An OIOUBL ApplicationResponse or Reminder is acknowledged once and the import job fails with a message naming the document type and the participant it was addressed to, so it's visible instead of being retried forever.
* **Embedded attachments are preserved.** Binary attachments carried inside the OIOUBL document are extracted and stored on the silo entry alongside the XML.

## FAQ

<AccordionGroup>
  <Accordion title="How do received invoices arrive?">
    By push, not polling. When a document addressed to one of your registered parties lands on the network, eCourier notifies Invopop by webhook, and the Denmark app starts your configured import workflow for it. The import step fetches the document, parses the OIOUBL, converts it to a GOBL invoice, and creates a silo entry carrying the GOBL document, the original XML, and any binary attachments embedded in it.
  </Accordion>

  <Accordion title="Which workflow processes inbound documents?">
    The one you select in the Denmark app's configuration (**Configuration** → **Apps** → **Denmark** → **Configure**). Every inbound document is handed to that workflow, so create it before registering any party — its first step must be the app's import action, and everything after it is yours to shape: setting a state, filing into a folder, or any other processing.
  </Accordion>

  <Accordion title="What happens to document types Invopop cannot process?">
    The current release imports invoices and credit notes. If something else arrives — an OIOUBL ApplicationResponse or a Reminder — the app acknowledges it on the network once and fails the import job with a message naming the document type that arrived and the participant it was addressed to, so it's visible rather than silently retried forever. Support for these document types is planned for a follow-up release.
  </Accordion>

  <Accordion title="Can a document be delivered twice?">
    The network redelivers its webhook until it is acknowledged, but the import step only acknowledges a document after it has been fully processed — and a document that was already imported isn't imported again. A failure partway through leaves the document ready to retry rather than lost.
  </Accordion>
</AccordionGroup>

More available in our [Denmark FAQ](/faq/denmark) section

***

<AccordionGroup>
  <Accordion title="🇩🇰 Invopop resources for Denmark">
    |            |                                                                                                                                                                                                                                                                                                                                                                                          |
    | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Compliance | <Icon icon="https://assets.invopop.com/flags/dk.svg" /> [Invoicing compliance in Denmark](/compliance/denmark)<br /> <Icon icon="timeline" /> [Compliance timeline](/timelines/denmark)                                                                                                                                                                                                  |
    | Apps       | <Icon icon="https://assets.invopop.com/flags/dk.svg" /> [Denmark](/apps/denmark)<br /> <Icon icon="https://assets.invopop.com/apps/peppol/icon.svg" /> [Peppol](/apps/peppol)                                                                                                                                                                                                            |
    | Guides     | <Icon icon="book" /> [Supplier registration guide](/guides/dk-nemhandel-supplier)<br /> <Icon icon="book" /> [Issuing invoices guide](/guides/dk-nemhandel)<br /> <Icon icon="book" /> [Receiving invoices guide](/guides/dk-nemhandel-receiving)<br /> <Icon icon="book" /> [Peppol guide](/guides/peppol)<br /> <Icon icon="book" /> [Chargebee guide](/guides/cb-denmark)             |
    | FAQ        | <Icon icon="square-question" /> [Denmark FAQ](/faq/denmark)                                                                                                                                                                                                                                                                                                                              |
    | GOBL       | <Icon icon="https://assets.invopop.com/icons/gobl.svg" /> [Danish OIOUBL 2.1 Addon](https://docs.gobl.org/addons/dk-oioubl-v2)<br /> <Icon icon="https://assets.invopop.com/icons/gobl.svg" /> [Denmark Tax Regime](https://docs.gobl.org/regimes/dk)<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.dk.oioubl](https://github.com/invopop/gobl.dk.oioubl)<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 Denmark →
</Card>
