NextSign API
Cases

Retrieve a Case

Fetch one case by id with GET /v3/api/cases/{id}, including its signing links and document downloads.

Returns a single case — who has signed, what state it is in, whether the case emails arrived, and its signing links.

GET https://api.nextsign.dk/v3/api/cases/{id}

Authenticated with an API key — see Authorization.

Quickstart

curl https://api.nextsign.dk/v3/api/cases/65ab12cd34ef56ab78cd90b0 \
  -H "Authorization: Bearer $NEXTSIGN_API_KEY"
const response = await fetch(
  `https://api.nextsign.dk/v3/api/cases/${caseId}`,
  { headers: { Authorization: `Bearer ${process.env.NEXTSIGN_API_KEY}` } },
);

const { case: found } = await response.json();
const signed = found.recipients.filter((r) => r.status === 'signed');
import os, requests

response = requests.get(
    f"https://api.nextsign.dk/v3/api/cases/{case_id}",
    headers={"Authorization": f"Bearer {os.environ['NEXTSIGN_API_KEY']}"},
)

found = response.json()["case"]

The id is the id from the creation response. That response also returns a Location header pointing at this endpoint, so you can follow it directly.


Path Parameter

ParameterTypeDescription
idstringThe case id

Query Parameters

ParameterTypeDefaultDescription
publicUrlsbooleanfalseReturn downloadable document links. See Document URLs
includeDeletedbooleanfalseReturn the case even if it has been moved to the bin

Response

200 OK
{
  "case": {
    "id": "65ab12cd34ef56ab78cd90b0",
    "referenceId": "Jrn. 2342-23",
    "title": "Lejeaftale",
    "state": "open",
    "language": "da",
    "createdAt": "2026-07-27T14:48:36.356Z",
    "expiresAt": "2026-08-10T14:48:36.356Z",
    "folder": { "id": "65ab12cd34ef56ab78cd90a2", "name": "Default" },
    "sender": {
      "id": "65ab12cd34ef56ab78cd90ef",
      "name": "Anna Beck",
      "email": "anna@example.com"
    },
    "activeGroup": 0,
    "recipients": [
      {
        "id": "65ab12cd34ef56ab78cd91a1",
        "uid": "4t5ZQbtB",
        "name": "Andreas Lauridsen",
        "email": "al@example.com",
        "phone": "",
        "position": "",
        "group": 0,
        "type": "email",
        "signing": true,
        "status": "pending",
        "needsCpr": false,
        "signingSchema": "",
        "emailStatus": {
          "status": "delivered",
          "bounceType": null,
          "sentAt": "2026-07-27T14:48:38.000Z",
          "deliveredAt": "2026-07-27T14:48:41.000Z",
          "openedAt": null,
          "bouncedAt": null,
          "updatedAt": "2026-07-27T14:48:41.000Z"
        },
        "signingUrl": "https://www.nextsign.dk/sign/65ab12cd34ef56ab78cd90b0/2/h6gKDYSiPyYTC5Bkq6urKfKKW"
      }
    ],
    "documents": [
      {
        "id": "65ab12cd34ef56ab78cd92c3",
        "name": "contract.pdf",
        "type": "application/pdf",
        "url": "https://nextsign-de.fsn1.your-objectstorage.com/65ab/contract.pdf",
        "signObligated": true,
        "documentMustBeRead": false,
        "signatories": []
      }
    ],
    "notices": []
  }
}

This is the same case object Create a Case returns, with one field missing: delivery, which reports the outcome of sending and therefore only exists on the response that did the sending.

This endpoint also reads back cases started in the dashboard, and those can be less filled in than one created here: a dashboard draft has no expiry until it is sent, so expiresAt can be null — and activeGroup is null whenever no group is currently being asked to sign, as on a draft.

notices is present and almost always empty — it mostly records what we filled in for you while creating a case. The one notice this endpoint can add is signing-urls-unavailable, when an open case's signing links could not be built; the case itself is still returned.

recipients[].signingUrl is returned for cases in the open state. A draft has nothing to sign yet, so the field is absent rather than null.

Signing links are rebuilt, not remembered. You do not need to store the URLs from the creation response — ask for the case again and they are regenerated. Build them by hand and they break, because the signing domain, language prefix and template number are all resolved per case and change over time.

A signing link is a credential. Anyone holding one can open that recipient's signing session, and for recipients who sign without an eID that is enough to sign as them. Treat these URLs like passwords: do not log them, and do not forward them anywhere the recipient would not expect. This is also why List Cases does not return them.


Email status

recipients[].emailStatus tells you whether the case emails, meaning the invitation and any reminders, reached the recipient. It is null until our email provider has reported something, and it stays null for recipients we do not email (type sms or eboks).

"emailStatus": {
  "status": "bounced",
  "bounceType": "hard",
  "sentAt": "2026-07-27T14:48:38.000Z",
  "deliveredAt": null,
  "openedAt": null,
  "bouncedAt": "2026-07-27T14:48:40.000Z",
  "updatedAt": "2026-07-27T14:48:40.000Z"
}
FieldDescription
statussent, delivered, opened or bounced. See below
bounceTypehard or soft when status is bounced, otherwise null
sentAtWhen an email last left our servers
deliveredAtWhen the recipient's mail server last accepted one
openedAtWhen the recipient last opened one, or clicked a link in it
bouncedAtWhen one last bounced. Can be set while status is not bounced, see below
updatedAtThe most recent event of any kind

Every reminder is a new email with its own events, so each timestamp is the most recent event of its kind, and null if there has not been one.

status is the first of these that applies:

  1. bounced: the newest delivery outcome is a bounce. If a later reminder is delivered, the status moves on to delivered or opened, while bouncedAt keeps the time of the bounce. A reminder that bounces after an earlier delivery makes it bounced again: the address stopped working.
  2. opened: an email was opened, or a link in it clicked.
  3. delivered: an email was accepted by the recipient's mail server.
  4. sent: an email was sent and nothing more has been reported yet.

A hard bounce means the address does not exist, or the receiving server refused it permanently. A soft bounce is a temporary problem, such as a full mailbox or an unavailable server, that did not clear while our provider kept retrying. In both cases that email is not going to arrive, and the recipient needs a corrected address or another channel.

If you change a recipient's email address after sending, events reported for the old address no longer count.

How fresh it is. Events are written to the case as soon as our email provider reports them, usually within seconds for sent and delivered. You do not need to poll for bounces: subscribe to the case.delivery.failed webhook, which fires for every bounced case email.

opened is a hint, not proof. Opens are detected through a tracking image. Some mail clients load it automatically (Apple Mail with Mail Privacy Protection does), so an email can count as opened without being read. Others block images, so an email can be read without ever counting as opened. For whether the recipient actually acted, rely on status, the signing status.


Document URLs

By default documents[].url is the document's stored address. It identifies the file and is stable, but it is protected — fetching it without credentials returns 403.

Pass ?publicUrls=true for a downloadable link, valid for one hour:

curl "https://api.nextsign.dk/v3/api/cases/65ab12cd34ef56ab78cd90b0?publicUrls=true" \
  -H "Authorization: Bearer $NEXTSIGN_API_KEY"

Ask for it on the request where you intend to download, rather than storing the result — an hour-old link has already expired, while the case id never does.

Documents you supplied as a url are returned exactly as you gave them, with or without this parameter. We store those by reference and never re-host them — which is also why their type is null, since we never fetched the bytes to inspect.


Errors

errorStatusMeaning
validation-failed400The id is malformed, or a query parameter is invalid. See details
case-not-found404No such case in your company
404 Not Found
{ "error": "case-not-found" }

404 does not mean the case does not exist — only that it is not yours to read. A case belonging to another company, a deleted case, and an id that was never issued all answer identically, on purpose: a response that told them apart would let anyone test whether a given case id exists in NextSign at all.

Reading never changes anything, so every request here is safe to retry. Full detail in Errors.