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

# NemHandel supplier registration guide

> Register Danish parties on the NemHandel network so they can send and receive invoices.

export const dkNemhandelUnregisterWorkflow = {
  "name": "Unregister from NemHandel",
  "description": "Release a party's NemHandel registration so it no longer sends or receives",
  "schema": "org/party",
  "steps": [{
    "id": "b0ebea5e-8907-11f1-8000-920007eb4d91",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `processing`{.state .processing}",
    "config": {
      "state": "processing"
    }
  }, {
    "id": "b0ec50f2-8907-11f1-8000-920007eb4d91",
    "name": "Unregister from NemHandel",
    "provider": "gov-dk.unregister"
  }, {
    "id": "b0ecc1fe-8907-11f1-8000-920007eb4d91",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `void`{.state .void}",
    "config": {
      "state": "void"
    }
  }],
  "rescue": [{
    "id": "b0ed13f2-8907-11f1-8000-920007eb4d91",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `error`{.state .error}",
    "config": {
      "state": "error"
    }
  }]
};

export const dkNemhandelRegisterWorkflow = {
  "name": "Register on NemHandel",
  "description": "",
  "schema": "org/party",
  "steps": [{
    "id": "c3e2b400-4f6a-11f1-9c2d-0242ac120012",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `processing`{.state .processing}",
    "config": {
      "state": "processing"
    }
  }, {
    "id": "e3af78f6-88d1-11f1-8000-920007eb4d91",
    "name": "Sign NemHandel Agreement",
    "provider": "gov-dk.sign"
  }, {
    "id": "e3af9d5e-88d1-11f1-8000-920007eb4d91",
    "name": "Wait for NemHandel Agreement",
    "provider": "gov-dk.wait.approval"
  }, {
    "id": "c3e2b401-4f6a-11f1-9c2d-0242ac120012",
    "name": "Register on NemHandel",
    "provider": "gov-dk.register"
  }, {
    "id": "c3e2b402-4f6a-11f1-9c2d-0242ac120012",
    "name": "Set State",
    "provider": "silo.state",
    "summary": "Set state to `registered`{.state .registered}",
    "config": {
      "state": "registered"
    }
  }],
  "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-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

**NemHandel** is Denmark's national e-invoicing network, run by the Danish Business Authority (Erhvervsstyrelsen). The [Denmark app](/apps/denmark) registers each of your Danish parties as a NemHandel participant through Invopop's partner [eCourier](https://ecourier.dk), so the party can send and receive OIOUBL invoices over the network.

Registration includes one step no other party in the flow can do for you: the supplier's representative must **sign an authorisation agreement** before the network participant can be created. The registration workflow publishes a signing link you share with them, and continues automatically once they've signed.

Once a supplier is registered, continue with the companion guide: [NemHandel issuing invoices](/guides/dk-nemhandel).

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

## Prerequisites

* **The party's details**: legal name, **CVR number** (8-digit business registration number, uploaded as the GOBL `tax_id.code`), and a Danish address.
* **A contact person on the party**: the first entry in the party's `people` list, with a name and a role in the company. The signing wizard prefills this person as the agreement's signer, and the API signing flow requires it.
* **The representative's availability**: someone authorized to sign on the supplier's behalf has to complete the signing step before registration can finish.

<Info>
  A registered party starts receiving inbound documents right away, so configure reception first: follow the [receiving guide's setup](/guides/dk-nemhandel-receiving#setup) to create the import workflow and select it in the app's configuration, then come back here.
</Info>

## Setup

All of the following steps must be carried out from the [Invopop Console](https://console.invopop.com).

<Steps>
  <Step title="Connect the Denmark app">
    1. Navigate to **Configuration** → **Apps**
    2. Find **Denmark** in the app discovery list
    3. Click **Connect** to activate
  </Step>

  <Step title="Create the registration workflow">
    <Card iconType="duotone" title="Register on NemHandel workflow" icon="code-branch" href="https://console.invopop.com/redirect/workflows/new?template=dk-register" horizontal>
      Add to my workspace →
    </Card>

    <Tabs>
      <Tab title="Workflow">
        <WorkflowDiagram workflow={dkNemhandelRegisterWorkflow} />
      </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 Register on NemHandel workflow theme={"system"}
        {
            "name": "Register on NemHandel",
            "description": "",
            "schema": "org/party",
            "steps": [
                {
                    "id": "c3e2b400-4f6a-11f1-9c2d-0242ac120012",
                    "name": "Set State",
                    "provider": "silo.state",
                    "summary": "Set state to `processing`{.state .processing}",
                    "config": {
                        "state": "processing"
                    }
                },
                {
                    "id": "e3af78f6-88d1-11f1-8000-920007eb4d91",
                    "name": "Sign NemHandel Agreement",
                    "provider": "gov-dk.sign"
                },
                {
                    "id": "e3af9d5e-88d1-11f1-8000-920007eb4d91",
                    "name": "Wait for NemHandel Agreement",
                    "provider": "gov-dk.wait.approval"
                },
                {
                    "id": "c3e2b401-4f6a-11f1-9c2d-0242ac120012",
                    "name": "Register on NemHandel",
                    "provider": "gov-dk.register"
                },
                {
                    "id": "c3e2b402-4f6a-11f1-9c2d-0242ac120012",
                    "name": "Set State",
                    "provider": "silo.state",
                    "summary": "Set state to `registered`{.state .registered}",
                    "config": {
                        "state": "registered"
                    }
                }
            ],
            "rescue": []
        }
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

## Register a supplier

<Steps>
  <Step title="Upload the party">
    Create a silo entry with the party's details. The example below shows the fields a Danish party carries; the name, the CVR number, and the contact person are what registration uses:

    ```json Denmark supplier example expandable theme={"system"}
    {
        "$schema": "https://gobl.org/draft-0/org/party",
        "name": "Nordlys Software ApS",
        "tax_id": {
            "country": "DK",
            "code": "16356700"
        },
        "people": [
            {
                "name": {
                    "given": "Mette",
                    "surname": "Kristensen"
                },
                "role": "Director"
            }
        ],
        "addresses": [
            {
                "num": "24",
                "street": "Vesterbrogade",
                "locality": "København V",
                "code": "1620",
                "country": "DK"
            }
        ],
        "emails": [
            {
                "addr": "faktura@nordlys.dk"
            }
        ]
    }
    ```
  </Step>

  <Step title="Run the registration workflow">
    Run the registration workflow on the party's silo entry, from the Console or [via the API](/api-ref/transform/jobs/create-a-job-post). The workflow publishes the authorisation agreement and pauses at the **wait for approval** step until it is signed.
  </Step>

  <Step title="Share the signing link">
    The workflow adds a public **agreement signing link** to the party's silo entry. Open the party in the Console to copy it, and send it to the supplier's representative.
  </Step>

  <Step title="Have the representative sign">
    The link opens a short hosted wizard: the representative confirms their name and role (prefilled from the party's contact person), reviews the agreement document, and signs it — drawing a signature that is stamped onto the agreement.
  </Step>

  <Step title="Wait for registration to complete">
    As soon as the agreement is signed, the workflow resumes on its own: it uploads the signed agreement, creates the party's NemHandel participant, and records the routing that delivers the party's inbound documents to your workspace. The party's entry ends in the `registered` state.
  </Step>
</Steps>

<Note>
  The party is registered under its NemHandel participant identifier: the first `endpoints` entry on the party if it has one (a `GLN:` number, for example), otherwise the `DK:CVR` identifier derived from its Danish tax ID.
</Note>

<Warning>
  A participant can only be held by one Invopop workspace. If another workspace has already registered the same identifier, registration fails with `this party is registered on NemHandel by a different workspace`.
</Warning>

## Sign the agreement via the API

Integrators building their own onboarding UI can drive the signing step without the hosted wizard. The Denmark app exposes two endpoints on its service, authenticated per enrollment; both take `?sandbox=true` (or `"sandbox": true` in the body) to address the sandbox environment:

| Endpoint                                 | Purpose                                                                                                                                                                       |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /v1/entry/:silo_entry_id/agreement` | The agreement PDF to render on screen: the signed one once it exists, the unsigned document before that.                                                                      |
| `POST /v1/entry/:silo_entry_id/sign`     | Sign it. Send `document` with a PDF you signed yourself, or `signature` with a drawn PNG/JPEG to have it stamped onto ours; send neither and the signer's typed name is used. |

Both endpoints read the signer from the party entry, so the first person in the party's `people` list must carry a name and a role before either is called.

## Unregister a supplier

To offboard a party, create the unregister workflow and run it on the party's silo entry: it releases the registration, removing the NemHandel participant along with the routing that delivered its inbound documents to your workspace.

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

<Tabs>
  <Tab title="Workflow">
    <WorkflowDiagram workflow={dkNemhandelUnregisterWorkflow} />
  </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 Unregister from NemHandel workflow theme={"system"}
    {
        "name": "Unregister from NemHandel",
        "description": "Release a party's NemHandel registration so it no longer sends or receives",
        "schema": "org/party",
        "steps": [
            {
                "id": "b0ebea5e-8907-11f1-8000-920007eb4d91",
                "name": "Set State",
                "provider": "silo.state",
                "summary": "Set state to `processing`{.state .processing}",
                "config": {
                    "state": "processing"
                }
            },
            {
                "id": "b0ec50f2-8907-11f1-8000-920007eb4d91",
                "name": "Unregister from NemHandel",
                "provider": "gov-dk.unregister"
            },
            {
                "id": "b0ecc1fe-8907-11f1-8000-920007eb4d91",
                "name": "Set State",
                "provider": "silo.state",
                "summary": "Set state to `void`{.state .void}",
                "config": {
                    "state": "void"
                }
            }
        ],
        "rescue": [
            {
                "id": "b0ed13f2-8907-11f1-8000-920007eb4d91",
                "name": "Set State",
                "provider": "silo.state",
                "summary": "Set state to `error`{.state .error}",
                "config": {
                    "state": "error"
                }
            }
        ]
    }
    ```
  </Tab>
</Tabs>

<Warning>
  An unregistered party can no longer send or receive over NemHandel, and documents addressed to it after unregistration will not reach your workspace. To operate on its behalf again, run the registration workflow again.
</Warning>

At this point, you're ready to start sending invoices on behalf of the supplier. Head over to the [NemHandel issuing invoices guide](/guides/dk-nemhandel) to continue.

## FAQ

<AccordionGroup>
  <Accordion title="Why does registration involve signing an agreement?">
    NemHandel registration runs through Invopop's partner **eCourier**, which requires a signed authorisation agreement from the supplier before it can create the supplier's NemHandel participant. That's why the registration workflow has three steps: publish the agreement for signing, wait until the supplier's representative signs it, and only then register the participant.
  </Accordion>

  <Accordion title="Who signs the agreement, and how?">
    A representative of the supplier — typically a director or other authorized signatory. The registration workflow publishes a **public signing link** on the party's silo entry; share it with the representative and they complete a short hosted wizard: confirm their details, review the agreement, and sign. If the party's `people` list carries a person with a name and role, the wizard prefills them as the signer. Integrators building their own onboarding UI can drive the same flow [over the API](/guides/dk-nemhandel-supplier#sign-the-agreement-via-the-api).
  </Accordion>

  <Accordion title="What identifier is the party registered under?">
    Its NemHandel participant identifier: the party's first GOBL `endpoints` entry if it has one (for example a `GLN:` number), otherwise the **`DK:CVR`** identifier derived from the party's Danish tax ID. NemHandel uses symbolic schemes (`DK:CVR`, `DK:SE`, `GLN`) rather than Peppol's numeric ISO 6523 codes.
  </Accordion>

  <Accordion title="Why was my registration refused with “registered on NemHandel by a different workspace”?">
    Each NemHandel participant can only be held by one Invopop workspace. If another workspace has already registered the same identifier, registration is refused — which workspace holds it is not disclosed. Re-running registration for a party your own workspace already registered is fine: it's treated as a retry, not an error.
  </Accordion>

  <Accordion title="Can I unregister a party?">
    Yes. Run the unregister workflow on the party's silo entry: it releases the NemHandel registration, removing the participant and the routing that delivered inbound documents to your workspace. To send or receive on behalf of that party again, you'll need to register it again.
  </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>
