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:
| Solution | What the recipient gets in e-Boks | Use it for |
|---|---|---|
| Letter with link | A cover letter from the template, plus a page with a link and QR code to the case | Cases someone signs |
| Letter and documents | A cover letter from the template, followed by the case documents | Cases someone signs |
| Case documents only | The case documents, merged into one PDF | Letters, 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.
- Content: choose Case documents only (Kun sagens dokumenter).
- Title: the subject the recipient sees in their e-Boks inbox, 4-50 characters. It can contain tags:
{case_name}(the casetitle) or any tag you send in the case'stags, 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 casetitleis used instead. - 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.
- Other recipient types: leave Own letter for recipients who don't sign off. When it is on, recipients with
signing: falseget that letter with a link instead of your letter. - 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.addressor, for a company, the CVR register. A recipient identified only by CPR has no address to print, so sendeboks.addressas 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. - 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.
- 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:
Dear {name}
You are invited to the general meeting on {meeting_date}.{{ name }}makes the letter impossible to render: the case is refused withdocument-conversion-failedand nothing is created.{ name }(with spaces) is accepted but printed as empty.- Tag names are case-sensitive and must match the
tagyou 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
tagsarray, 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:
| Field | Value |
|---|---|
messageTemplateId | The id of your Case documents only template. It can also be set per recipient |
tags | The values for the letter and for the inbox title, each { "tag": "...", "value": "..." } |
documents | One document: your .docx letter, as content or url |
recipients | One 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 |
referenceId | Your 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:
{
"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 noticecompleted-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[].mediumiseboks, orletterwhen 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.eboksisok: falsewith the reason inrecipients[].error. The response is still201, the case staysopen, 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:
- Create the case as above with
"state": "draft". The letter is filled in and converted, but nothing is sent and nothing is charged. - 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. - 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 withGET /v3/api/cases?referenceId=.... Retry only on network errors and5xx, never on a4xx. 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 see | Why | What to do |
|---|---|---|
400 validation-failed, documents "is required" | A case that is sent needs a document. Here the letter is the document | Send 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 address | Send cpr, eboks.cvr or eboks.address |
400 message-template-not-found | The template id is wrong or belongs to another company | Copy the Template ID from the template editor |
400 document-conversion-failed | The 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 false | e-Boks could not deliver it: CPR not registered for Digital Post, an unknown address, or a foreign address | Check the recipient data, or enable the physical letter |
| The inbox shows the case title | A tag in the template title had no value, or the title came out shorter than 4 characters | Send the tag, or use a longer title |
| The recipient got a letter with a link | The template is not set to Case documents only, or Own letter for recipients who don't sign is on | Fix the template |
The case stays open | A recipient signs (signing defaults to true), e-Boks refused the letter, or the template is not set to Case documents only | Set 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.