NextSign API
Guides

Send letters via e-Boks without signing

Send a filled-in Word letter to a recipient's e-Boks with API v3, when nobody has to sign anything.

Many letters need no signature: a notice, an information letter, an invitation, a decision. This guide shows how to send one through e-Boks with POST /v3/api/cases, filled in with your own data for each recipient.

How it works

You create one case per recipient. The case's document is your Word letter: NextSign fills in its {tags} with the values you send and converts it to PDF. An e-Boks template decides what goes into the recipient's e-Boks, and for this kind of letter you use the solution Case documents only.

An e-Boks template has three solutions:

SolutionWhat the recipient gets in e-BoksUse it for
Letter with linkA cover letter from the template, plus a page with a link and QR code to the caseCases someone signs
Letter and documentsA cover letter from the template, followed by the case documentsCases someone signs
Case documents onlyThe case documents, merged into one PDFLetters, as in this guide

With Case documents only and your letter as the case's only document, the recipient gets exactly one file in e-Boks: your filled-in letter.

The letter you can upload in an e-Boks template is a cover letter. It is used by the two other solutions, when there is something to sign. Do not put the letter you want to send there: with Case documents only no template letter is sent, and your letter is the case document.

Nobody signs, so the case is completed as soon as e-Boks has the letter.

1. Set up the e-Boks template

In the dashboard, go to Communication → e-Boks (Kommunikation) and create a template.

  1. Content: choose Case documents only (Kun sagens dokumenter).
  2. Title: the subject the recipient sees in their e-Boks inbox, 4-50 characters. It can contain tags: {case_name} (the case title) or any tag you send in the case's tags, such as {eboks_title}. A longer title is cut at 50 characters. If a tag in the title has no value, or the result is shorter than 4 characters, the case title is used instead.
  3. Button: turn off Show a button in e-Boks (Vis en knap i e-Boks). The button leads to the case at NextSign, and there is nothing to do there.
  4. Other recipient types: leave Own letter for recipients who don't sign off. When it is on, recipients with signing: false get that letter with a link instead of your letter.
  5. Physical letter (optional): to post the letter to recipients who cannot receive e-Boks, turn on Put the recipient's address on the document and Send a physical letter if the recipient doesn't have e-Boks. NextSign prints the recipient's name and address in the window field at the top left of page 1, so keep that area of your letter empty. The address comes from the recipient's eboks.address or, for a company, the CVR register. A recipient identified only by CPR has no address to print, so send eboks.address as well when you want the physical letter. The option is only shown when physical letters are enabled on your account; contact NextSign to enable it.
  6. Read receipt (optional): get notified when the recipient opens the letter in e-Boks. It costs extra credits per recipient, applies to the first dispatch only, and needs a one-time setup at e-Boks that NextSign does for you on request.
  7. Save the template and copy its Template ID (Skabelon-ID) from the editor. You send it as messageTemplateId.

2. Write the letter

Write the letter in Word and save it as .docx. Wherever a value goes, write a tag with one curly brace on each side and no spaces:

In Word
Dear {name}

You are invited to the general meeting on {meeting_date}.
  • {{ name }} makes the letter impossible to render: the case is refused with document-conversion-failed and nothing is created.
  • { name } (with spaces) is accepted but printed as empty.
  • Tag names are case-sensitive and must match the tag you send exactly.
  • Tags work everywhere in the document: the body, tables, headers and footers.

The letter is filled with:

  • every tag in the case's top-level tags array, and
  • the global fields, such as {company_name}, {company_cvr}, {sender_name} and {today}.

The letter is rendered once for the case, not by the e-Boks template. The fields of a template letter, such as {recipient_name}, {recipient_address}, {custom_message} and {case_name}, are not filled in it. Send the recipient's name and address as your own tags. The letter is only filled when the case has a tags array; without one it is converted as it is, with every {tag} printed as written.

3. Send the letter

One request creates the case and sends the letter. A letter up to 20 MB can go in content as base64; for a larger file, upload it first and pass its url with a name that ends in .docx (see Files over 20 MB).

curl https://api.nextsign.dk/v3/api/cases \
  -H "Authorization: Bearer $NEXTSIGN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "General meeting 2026",
    "referenceId": "member-4711",
    "messageTemplateId": "<your e-Boks template id>",
    "tags": [
      { "tag": "name", "value": "Jane Doe" },
      { "tag": "address", "value": "Østergade 12, 1100 København K" },
      { "tag": "meeting_date", "value": "12 November 2026" },
      { "tag": "eboks_title", "value": "Invitation: General meeting 2026" }
    ],
    "recipients": [
      { "name": "Jane Doe", "type": "eboks", "signing": false, "cpr": "1234567890" }
    ],
    "documents": [
      { "name": "invitation.docx", "content": "UEsDBBQABgAIAAAAIQ...", "signObligated": false }
    ]
  }'
import { readFile } from 'node:fs/promises';

const letter = await readFile('invitation.docx');

const response = await fetch('https://api.nextsign.dk/v3/api/cases', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NEXTSIGN_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'General meeting 2026',
    referenceId: 'member-4711',
    messageTemplateId: process.env.NEXTSIGN_EBOKS_TEMPLATE_ID,
    tags: [
      { tag: 'name', value: 'Jane Doe' },
      { tag: 'address', value: 'Østergade 12, 1100 København K' },
      { tag: 'meeting_date', value: '12 November 2026' },
      { tag: 'eboks_title', value: 'Invitation: General meeting 2026' },
    ],
    recipients: [{ name: 'Jane Doe', type: 'eboks', signing: false, cpr: '1234567890' }],
    documents: [{ name: 'invitation.docx', content: letter.toString('base64'), signObligated: false }],
  }),
});

const { case: created } = await response.json();
console.log(created.state, created.delivery.eboks);
import base64, os, requests

letter = base64.b64encode(open("invitation.docx", "rb").read()).decode()

response = requests.post(
    "https://api.nextsign.dk/v3/api/cases",
    headers={"Authorization": f"Bearer {os.environ['NEXTSIGN_API_KEY']}"},
    json={
        "title": "General meeting 2026",
        "referenceId": "member-4711",
        "messageTemplateId": os.environ["NEXTSIGN_EBOKS_TEMPLATE_ID"],
        "tags": [
            {"tag": "name", "value": "Jane Doe"},
            {"tag": "address", "value": "Østergade 12, 1100 København K"},
            {"tag": "meeting_date", "value": "12 November 2026"},
            {"tag": "eboks_title", "value": "Invitation: General meeting 2026"},
        ],
        "recipients": [
            {"name": "Jane Doe", "type": "eboks", "signing": False, "cpr": "1234567890"}
        ],
        "documents": [
            {"name": "invitation.docx", "content": letter, "signObligated": False}
        ],
    },
)

created = response.json()["case"]
print(created["state"], created["delivery"]["eboks"])

What matters in the request:

FieldValue
messageTemplateIdThe id of your Case documents only template. It can also be set per recipient
tagsThe values for the letter and for the inbox title, each { "tag": "...", "value": "..." }
documentsOne document: your .docx letter, as content or url
recipientsOne recipient with type: "eboks" and signing: false, identified by cpr (10-digit CPR or 8-digit CVR), eboks.cvr or eboks.address. See the e-Boks Object
referenceIdYour own id for the recipient or the letter. Useful for finding the case again

signing defaults to true. Leave it out and the recipient becomes a signer, and the case stays open waiting for a signature.

From your document library. You can also keep the letter in Dashboard → Documents and send it as documentId with its values in documents[].tags instead of content. Those values are checked against the letter's fields, including the ones in its header and footer. The inbox title still takes its values from the top-level tags.

4. Read the response

The response is 201 with the whole case. Trimmed to what matters here:

201 Created (trimmed)
{
  "case": {
    "id": "65ab12cd34ef56ab78cd90b0",
    "referenceId": "member-4711",
    "state": "completed",
    "recipients": [
      { "uid": "4t5ZQbtB", "name": "Jane Doe", "type": "eboks", "signing": false, "status": "not signing" }
    ],
    "delivery": {
      "attempted": true,
      "email": { "ok": true },
      "eboks": {
        "ok": true,
        "recipients": [
          { "recipientId": "65ab12cd34ef56ab78cd91a1", "name": "Jane Doe", "ok": true, "medium": "eboks" }
        ]
      },
      "sms": { "ok": true },
      "webhook": { "ok": true }
    },
    "notices": [
      {
        "code": "completed-on-send",
        "message": "No recipient signs this case, so it was completed once the e-Boks letter was sent."
      }
    ]
  }
}
  • state: "completed" with the notice completed-on-send: e-Boks accepted the letter and the case is done. There is nothing to sign, no reminders are sent, and no signing link is returned.
  • delivery.eboks.recipients[].medium is eboks, or letter when the letter was posted instead (see the physical letter in step 1).
  • When e-Boks refuses the letter, for example because the CPR is not registered for Digital Post or the address cannot be found, delivery.eboks is ok: false with the reason in recipients[].error. The response is still 201, the case stays open, and the dashboard shows the reason on the case. See Delivery.

A refused letter also fires the case.delivery.failed webhook, so an integration that listens for webhooks hears about it too.

5. Test before you send

The test environment (test.nextsign.dk) does not send e-Boks letters, so you cannot see the result there.

Test in production instead, without sending anything:

  1. Create the case as above with "state": "draft". The letter is filled in and converted, but nothing is sent and nothing is charged.
  2. Look at the PDF: open the draft in the dashboard, or download it with Get a Case and ?publicUrls=true. Delete the draft when you are done.
  3. Send one real case to yourself, with your own CPR, to see the letter and its title in e-Boks.

6. Many recipients

Send one case per recipient, one request after another.

  • Retries can send twice. Case creation has no idempotency key, so retrying a request that timed out can create a second case and a second letter. Give each case a referenceId, and before you retry, look it up with GET /v3/api/cases?referenceId=.... Retry only on network errors and 5xx, never on a 4xx. See Errors.
  • Pace the requests. v3 does not enforce a rate limit yet, but one is coming. Stay below the documented 100 requests per minute.
for (const member of members) {
  const referenceId = `general-meeting-2026-${member.id}`;

  // Already sent in an earlier run: skip it.
  const existing = await fetch(
    `https://api.nextsign.dk/v3/api/cases?referenceId=${encodeURIComponent(referenceId)}`,
    { headers: { Authorization: `Bearer ${process.env.NEXTSIGN_API_KEY}` } },
  ).then((res) => res.json());
  if (existing.cases.length) continue;

  await sendLetter(member, referenceId); // the request from step 3
}

Common problems

What you seeWhyWhat to do
400 validation-failed, documents "is required"A case that is sent needs a document. Here the letter is the documentSend the letter in documents, not only in the template
400 validation-failed, recipients[0].cpr "is required for an e-Boks recipient..."An e-Boks recipient needs a CPR, a CVR or an addressSend cpr, eboks.cvr or eboks.address
400 message-template-not-foundThe template id is wrong or belongs to another companyCopy the Template ID from the template editor
400 document-conversion-failedThe letter could not be filled or converted, most often because of {{ tag }}Write tags as {tag}
A field in the letter is empty{ tag } with spaces, a tag name that does not match exactly, or a template-letter field such as {recipient_name}Fix the tag, or send the value as your own tag
delivery.eboks.ok is falsee-Boks could not deliver it: CPR not registered for Digital Post, an unknown address, or a foreign addressCheck the recipient data, or enable the physical letter
The inbox shows the case titleA tag in the template title had no value, or the title came out shorter than 4 charactersSend the tag, or use a longer title
The recipient got a letter with a linkThe template is not set to Case documents only, or Own letter for recipients who don't sign is onFix the template
The case stays openA recipient signs (signing defaults to true), e-Boks refused the letter, or the template is not set to Case documents onlySet signing: false and check delivery.eboks

Price

Nobody signs, so no signature credits are used. The e-Boks dispatch costs credits based on the size of the PDF, so a short letter is the cheapest. A physical letter costs more and depends on its weight, and a read receipt adds credits per recipient.