EverStamp API

Everything the dashboard can do, your own software can do too. One API key acts for one organisation with the rights of an administrator. Photos never travel through this API: the register records that a dossier exists, a kept archive opens through a short-lived link on everstamp.app/d, and anyone checks a dossier on everstamp.app/verify without an account.

Get started

  1. 1In the dashboard, open Settings, Integrations and create an API key. It is shown once; store it as a secret on your server.
  2. 2Call the API with the key as a bearer token. JSON in, JSON out, UTF-8, ISO 8601 times. Every id is a ulid.
  3. 3Prepare an order: it appears in the app of the field worker you assign it to. When the dossier is registered, your webhook hears it.
curl https://api.everstamp.app/v1/orders -H "Authorization: Bearer $EVERSTAMP_KEY"

Authentication

An API key from the dashboard (Settings, Integrations): `esk_` followed by 32 characters. Send it as `Authorization: Bearer esk_...`. It acts for one organisation. A key is made either read-only (GET) or read and write, and either with an expiry date or without; both are chosen when the key is made and neither can be changed afterwards. A key that may only read gets 403 api-key-read-only on anything that changes something; a key past its expiry gets 401 api-key-expired.

Revoke a key the moment it leaks; a revoked key stays revoked. When you make a key you choose whether it may only read or also write, and how long it stays valid (90 days, a year, or no expiry); neither can be changed afterwards, so a key that needs more rights is a new key. A read-only key gets 403 api-key-read-only on anything that changes something, and a key past its date gets 401 api-key-expired. A key still acts for the whole organisation, so keep it server-side, never in an app or a browser. One key per piece of software makes the audit log readable: every order an integration prepares carries the key name.

Concepts

Order. What the office (or your software) prepares for a member: a name, an address, a checklist, optionally a project, labels, a due date and a note. Every phone linked to that member sees it; picking it up creates the dossier on the phone. The status is never a claim by the app: claimed means the register saw the pickup, registered means the dossier row is in the register.

Dossier. A series of captures made on one phone, sealed with a qualified timestamp and registered. The photos stay on the phone unless they are shared or kept at EverStamp (Settings, Share links); the API sees who, when, the root hash and whether the register has stamped the period. Verification of a shared dossier happens on everstamp.app/verify, without this API.

Checklist. Steps with a minimum number of captures each, strict or free. The library ships 22 checklists per industry; your own are versioned and a version never changes, so an old dossier always reads against the checklist it was made with.

Request. Photos from someone who is not a user: the insured, a tenant, a mover. You create a request and send its one-time link; the guest opens it on an iPhone or an Android phone, gives their name and consent, and photographs along a strict checklist. The dossier lands in your organisation with the same seal as the dossiers of your own people; request.completed hands it to you. Business and Enterprise plans, counted in the bundle.

Project and labels. Grouping and filtering. Context, not part of the dossier itself unless the stamp bar shows the project name.

Errors and limits

Errors are JSON with a stable error code and a human message. Codes you will meet: api-key (401), api-not-allowed (403: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so), invalid-body (400), unknown-member, unknown-template, unknown-project (422), template-not-for-request (422: a checklist without a required capture, such as Freeform file (free-dossier), cannot be used for a request), order-claimed (409: the order was picked up, the dossier exists), no-entitlement (403: requests need a paid Business or Enterprise plan), unknown-request (404), request-completed (409: the request is answered, the dossier is in the register), rate-limit (429, with Retry-After).

Lists return at most 500 orders and 100 dossiers per page; page dossiers with before. Calls are idempotent where it matters: withdrawing twice is fine, a phone picking up twice with the same dossier is fine. The API is versioned in the path (/v1); fields are only ever added, never renamed or removed within a version.

Orders

What the office prepares and a field worker picks up in the app. The status comes from the register: prepared, claimed (picked up), registered, cancelled.

GET/v1/ordersList orders
Query parameters
statusquerycomma-separated: prepared, claimed, registered, cancelled
projectqueryonly orders of this project (ulid)
archivedquery1 to include archived orders
tagqueryonly orders with this label
qquerysearch words; every word must occur in title, address, note, member, checklist, project, labels or id; case and accent insensitive
beforequerypaging: the id of the last order of the previous page
limitquery1 to 500, default 100; the response carries more: true when older orders exist
Responses
200 OK
format *"everstamp/3"always "everstamp/3"
orders *array of objectthe orders, newest first
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
title *stringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
template *objectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
member *stringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
memberName *stringthat member's name
duestring (date-time)wanted by (ISO 8601)
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
status *"prepared" | "claimed" | "registered" | "cancelled"prepared, claimed (at least one phone picked it up), registered (every pickup is in the register) or cancelled; always from the register, never from a message by the app
claimedAtstring (date-time)first pickup
claimedBystringdevice of the first pickup (sha-256 of the key id)
dossierstringdossier id of the first pickup
registeredAtstring (date-time)when the first dossier was registered
stampedAtstring (date-time)qualified timestamp of that dossier
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn on
cancelReasonstringwhy it was withdrawn
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
predecessorobject
dossier *stringdossier id of the first pickup
root *stringroot hash of that dossier
titlestringname of the dossier as the app shows it
at *string (date-time)
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
claimsarray of objectevery pickup, oldest first
device *stringthe phone (sha-256 of its key id)
memberstringthe member that phone belonged to at the time
memberNamestringtheir name
dossier *stringthe dossier that phone created for the order
claimedAt *string (date-time)picked up on
registeredAtstring (date-time)registered on
stampedAtstring (date-time)qualified timestamp of the dossier
rootstringroot hash of the dossier
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
more *booleantrue when there is another page
400 bad filter
401 missing or unknown key
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/orders \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/ordersPrepare an order

The order appears in the app of the member you assign it to. `member` is a member id from GET /v1/members; the API fills in `memberName`. `template` is {name, version}: a built-in checklist from the library or one of your own.

Request body
title *stringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
template *objectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
member *stringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
duestring (date-time)wanted by (ISO 8601)
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
predecessorstring
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
Responses
201 prepared
order *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
title *stringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
template *objectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
member *stringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
memberName *stringthat member's name
duestring (date-time)wanted by (ISO 8601)
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
status *"prepared" | "claimed" | "registered" | "cancelled"prepared, claimed (at least one phone picked it up), registered (every pickup is in the register) or cancelled; always from the register, never from a message by the app
claimedAtstring (date-time)first pickup
claimedBystringdevice of the first pickup (sha-256 of the key id)
dossierstringdossier id of the first pickup
registeredAtstring (date-time)when the first dossier was registered
stampedAtstring (date-time)qualified timestamp of that dossier
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn on
cancelReasonstringwhy it was withdrawn
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
predecessorobject
dossier *stringdossier id of the first pickup
root *stringroot hash of that dossier
titlestringname of the dossier as the app shows it
at *string (date-time)
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
claimsarray of objectevery pickup, oldest first
device *stringthe phone (sha-256 of its key id)
memberstringthe member that phone belonged to at the time
memberNamestringtheir name
dossier *stringthe dossier that phone created for the order
claimedAt *string (date-time)picked up on
registeredAtstring (date-time)registered on
stampedAtstring (date-time)qualified timestamp of the dossier
rootstringroot hash of the dossier
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
400 invalid body
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
422 unknown member, checklist or project
curl -X POST https://api.everstamp.app/v1/orders \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Kloosterweg 14, meter cupboard","template":{"name":"meter-cupboard","version":1},"member":"01K4BQ4A1PZQ6D2E8F0G3H5J7K"}'
GET/v1/orders/{id}One order
Query parameters
id *paththe id (ulid)
Responses
200 OK
order *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
title *stringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
template *objectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
member *stringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
memberName *stringthat member's name
duestring (date-time)wanted by (ISO 8601)
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
status *"prepared" | "claimed" | "registered" | "cancelled"prepared, claimed (at least one phone picked it up), registered (every pickup is in the register) or cancelled; always from the register, never from a message by the app
claimedAtstring (date-time)first pickup
claimedBystringdevice of the first pickup (sha-256 of the key id)
dossierstringdossier id of the first pickup
registeredAtstring (date-time)when the first dossier was registered
stampedAtstring (date-time)qualified timestamp of that dossier
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn on
cancelReasonstringwhy it was withdrawn
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
predecessorobject
dossier *stringdossier id of the first pickup
root *stringroot hash of that dossier
titlestringname of the dossier as the app shows it
at *string (date-time)
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
claimsarray of objectevery pickup, oldest first
device *stringthe phone (sha-256 of its key id)
memberstringthe member that phone belonged to at the time
memberNamestringtheir name
dossier *stringthe dossier that phone created for the order
claimedAt *string (date-time)picked up on
registeredAtstring (date-time)registered on
stampedAtstring (date-time)qualified timestamp of the dossier
rootstringroot hash of the dossier
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 no such order in this organisation
curl -X GET https://api.everstamp.app/v1/orders/01K4C0Z9Y8X7W6V5T4S3R2Q1P0 \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/orders/{id}Change a prepared order

Only while the order is prepared; once a phone picked it up the dossier exists and the order is fixed (409 order-claimed). Send only the fields you change. `clearProject: true` removes the project, `tags: []` removes the labels.

Query parameters
id *paththe id (ulid)
Request body
titlestringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
templateobjectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
memberstringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
duestring (date-time)wanted by (ISO 8601)
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
clearStampBarbooleantrue removes the order's own stamp-bar layout
clearProjectbooleantrue removes the order from its project
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
clearQualifiedPhotoStampboolean
Responses
200 OK
order *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
title *stringname of the dossier as the app shows it
addressstringaddress, on the stamp bar
notestringa note for the field worker
template *objectthe checklist: name and version (built-in from the library, or your own)
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
member *stringthe member the order is for (member id from GET /v1/members); every phone of that member sees it
memberName *stringthat member's name
duestring (date-time)wanted by (ISO 8601)
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
status *"prepared" | "claimed" | "registered" | "cancelled"prepared, claimed (at least one phone picked it up), registered (every pickup is in the register) or cancelled; always from the register, never from a message by the app
claimedAtstring (date-time)first pickup
claimedBystringdevice of the first pickup (sha-256 of the key id)
dossierstringdossier id of the first pickup
registeredAtstring (date-time)when the first dossier was registered
stampedAtstring (date-time)qualified timestamp of that dossier
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn on
cancelReasonstringwhy it was withdrawn
projectstringproject id (ulid)
projectNamestringfilled in from the project when omitted
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only; without it the organisation default applies
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
predecessorobject
dossier *stringdossier id of the first pickup
root *stringroot hash of that dossier
titlestringname of the dossier as the app shows it
at *string (date-time)
prefillarray of object
id *stringulid
value *string
qualifiedPhotoStampboolean
claimsarray of objectevery pickup, oldest first
device *stringthe phone (sha-256 of its key id)
memberstringthe member that phone belonged to at the time
memberNamestringtheir name
dossier *stringthe dossier that phone created for the order
claimedAt *string (date-time)picked up on
registeredAtstring (date-time)registered on
stampedAtstring (date-time)qualified timestamp of the dossier
rootstringroot hash of the dossier
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 no such order
409 order-claimed or order-cancelled
curl -X POST https://api.everstamp.app/v1/orders/01K4C0Z9Y8X7W6V5T4S3R2Q1P0 \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Kloosterweg 14, meter cupboard"}'
POST/v1/orders/{id}/cancelWithdraw a prepared order
Query parameters
id *paththe id (ulid)
Request body
reasonstringwhy (optional)
Responses
200 OK
id *stringulid
cancelledAt *string (date-time)withdrawn on
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
409 already picked up
curl -X POST https://api.everstamp.app/v1/orders/01K4C0Z9Y8X7W6V5T4S3R2Q1P0/cancel \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Requests

Ask someone who is not a user, such as the insured, a tenant or a mover, for photos. You get a one-time link to send; the guest opens it on an iPhone or an Android phone, takes the photos along a strict checklist, and the dossier lands in your organisation. Business and Enterprise plans; counted in the bundle.

GET/v1/requestsList requests
Query parameters
statusquerycomma-separated: open, started, completed, expired, cancelled
closedAsqueryonly cancelled requests that were closed this way: withdrawn or handled
projectqueryonly requests of this project (ulid)
tagqueryonly requests with this label
qquerysearch words; every word must occur in title, address, note, guest name or contact, checklist, project, labels or id
beforequerypaging: the id of the last request of the previous page
limitquery1 to 500, default 100; the response carries more: true when older requests exist
Responses
200 OK
format *"everstamp/3"always "everstamp/3"
requests *array of objectthe requests, newest first
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
organisationName *stringyour organisation's name as the guest sees it; filled in from your organisation
codestringthe one-time code, eight characters; the link is https://everstamp.app/v/<code>
urlstring (uri)the link to send to the guest
title *stringwhat it is about; the guest sees it and the dossier is named after it
addressstringaddress, for the guest and on the stamp bar
notestringa note for the guest, in plain words
template *objectthe checklist: name and version; strict for a guest
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
guestNamestringthe guest's name as you know it; the guest confirms or corrects it
guestContactstringphone number or e-mail of the guest, for you only; wiped 30 days after completion
guestNameGivenstringthe name the guest gave on their phone
expiresAt *string (date-time)until when the link works; default 14 days, at most 30
status *"open" | "started" | "completed" | "expired" | "cancelled"open, started (accepted on a phone), completed (the dossier is in the register), expired or cancelled
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
startedAtstring (date-time)accepted on
devicestringthe guest's phone (sha-256 of its key id)
completedAtstring (date-time)when the dossier was registered
dossierstringthe dossier id
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn or handled on
cancelReasonstringwhy, or with handled the note on how it was settled
closedAs"withdrawn" | "handled"how a cancelled request was closed: withdrawn (the default when you cancel), or handled (the matter was settled outside the request); a request from before this field reads withdrawn
projectstringproject id (ulid)
projectNamestringname of that project
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
prefillarray of objectfield values you already know (id from the checklist, value); the app fills them in and the guest confirms
id *stringulid
value *string
predecessorobject
dossier *stringthe dossier id
root *stringroot hash of that dossier
titlestringwhat it is about; the guest sees it and the dossier is named after it
at *string (date-time)
deliverystringthe delivery (share id) the app made for your organisation; open it with GET /v1/requests/{id}/archive
consentVersionintegerwhich declaration the guest confirmed when accepting (CONSENT.version in the contract); absent for an app from before that field
deliveredAtstring (date-time)when the archive arrived
countedbooleantrue while it counts in the bundle; false after withdrawal or expiry within the ten percent
more *booleantrue when there is another page
400 bad filter
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/requests \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/requestsCreate a request

The response carries `code` and `url` (https://everstamp.app/v/<code>): send that link to the guest yourself (e-mail, SMS, a letter with a QR). The guest opens it on an iPhone or an Android phone, gives their name and consent, and photographs along the checklist; when the dossier is registered you receive the `request.completed` webhook with the dossier. `template` is {name, version}; for a guest a checklist is always strict. A built-in checklist that is free on its own (such as Progress) reaches the guest as its strict twin `<name>-request`, with the same steps and titles; the dossier then carries that name. A checklist without any required capture, such as Freeform file (free-dossier), cannot be used for a request (422 template-not-for-request). `expiresAt` defaults to 14 days, at most 30. Needs a Business or Enterprise plan (403 no-entitlement).

Request body
title *stringwhat it is about; the guest sees it and the dossier is named after it
addressstringaddress, for the guest and on the stamp bar
notestringa note for the guest, in plain words
template *objectthe checklist: name and version; strict for a guest
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
guestNamestringthe guest's name as you know it; the guest confirms or corrects it
guestContactstringphone number or e-mail of the guest, for you only; wiped 30 days after completion
expiresAtstring (date-time)until when the link works; default 14 days, at most 30
projectstringproject id (ulid)
projectNamestringname of that project
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
prefillarray of objectfield values you already know (id from the checklist, value); the app fills them in and the guest confirms
id *stringulid
value *string
predecessorstring
Responses
201 created
request *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
organisationName *stringyour organisation's name as the guest sees it; filled in from your organisation
codestringthe one-time code, eight characters; the link is https://everstamp.app/v/<code>
urlstring (uri)the link to send to the guest
title *stringwhat it is about; the guest sees it and the dossier is named after it
addressstringaddress, for the guest and on the stamp bar
notestringa note for the guest, in plain words
template *objectthe checklist: name and version; strict for a guest
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
guestNamestringthe guest's name as you know it; the guest confirms or corrects it
guestContactstringphone number or e-mail of the guest, for you only; wiped 30 days after completion
guestNameGivenstringthe name the guest gave on their phone
expiresAt *string (date-time)until when the link works; default 14 days, at most 30
status *"open" | "started" | "completed" | "expired" | "cancelled"open, started (accepted on a phone), completed (the dossier is in the register), expired or cancelled
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
startedAtstring (date-time)accepted on
devicestringthe guest's phone (sha-256 of its key id)
completedAtstring (date-time)when the dossier was registered
dossierstringthe dossier id
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn or handled on
cancelReasonstringwhy, or with handled the note on how it was settled
closedAs"withdrawn" | "handled"how a cancelled request was closed: withdrawn (the default when you cancel), or handled (the matter was settled outside the request); a request from before this field reads withdrawn
projectstringproject id (ulid)
projectNamestringname of that project
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
prefillarray of objectfield values you already know (id from the checklist, value); the app fills them in and the guest confirms
id *stringulid
value *string
predecessorobject
dossier *stringthe dossier id
root *stringroot hash of that dossier
titlestringwhat it is about; the guest sees it and the dossier is named after it
at *string (date-time)
deliverystringthe delivery (share id) the app made for your organisation; open it with GET /v1/requests/{id}/archive
consentVersionintegerwhich declaration the guest confirmed when accepting (CONSENT.version in the contract); absent for an app from before that field
deliveredAtstring (date-time)when the archive arrived
countedbooleantrue while it counts in the bundle; false after withdrawal or expiry within the ten percent
400 invalid body
403 no-entitlement: needs a Business or Enterprise plan; or api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
422 unknown checklist or project; template-not-for-request: the checklist has no required capture
curl -X POST https://api.everstamp.app/v1/requests \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Kloosterweg 14, meter cupboard","template":{"name":"meter-cupboard","version":1}}'
GET/v1/requests/{id}One request
Query parameters
id *paththe id (ulid)
Responses
200 OK
request *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
organisationName *stringyour organisation's name as the guest sees it; filled in from your organisation
codestringthe one-time code, eight characters; the link is https://everstamp.app/v/<code>
urlstring (uri)the link to send to the guest
title *stringwhat it is about; the guest sees it and the dossier is named after it
addressstringaddress, for the guest and on the stamp bar
notestringa note for the guest, in plain words
template *objectthe checklist: name and version; strict for a guest
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
guestNamestringthe guest's name as you know it; the guest confirms or corrects it
guestContactstringphone number or e-mail of the guest, for you only; wiped 30 days after completion
guestNameGivenstringthe name the guest gave on their phone
expiresAt *string (date-time)until when the link works; default 14 days, at most 30
status *"open" | "started" | "completed" | "expired" | "cancelled"open, started (accepted on a phone), completed (the dossier is in the register), expired or cancelled
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
startedAtstring (date-time)accepted on
devicestringthe guest's phone (sha-256 of its key id)
completedAtstring (date-time)when the dossier was registered
dossierstringthe dossier id
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn or handled on
cancelReasonstringwhy, or with handled the note on how it was settled
closedAs"withdrawn" | "handled"how a cancelled request was closed: withdrawn (the default when you cancel), or handled (the matter was settled outside the request); a request from before this field reads withdrawn
projectstringproject id (ulid)
projectNamestringname of that project
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
prefillarray of objectfield values you already know (id from the checklist, value); the app fills them in and the guest confirms
id *stringulid
value *string
predecessorobject
dossier *stringthe dossier id
root *stringroot hash of that dossier
titlestringwhat it is about; the guest sees it and the dossier is named after it
at *string (date-time)
deliverystringthe delivery (share id) the app made for your organisation; open it with GET /v1/requests/{id}/archive
consentVersionintegerwhich declaration the guest confirmed when accepting (CONSENT.version in the contract); absent for an app from before that field
deliveredAtstring (date-time)when the archive arrived
countedbooleantrue while it counts in the bundle; false after withdrawal or expiry within the ten percent
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 no such request in this organisation
curl -X GET https://api.everstamp.app/v1/requests/01K4C0Z9Y8X7W6V5T4S3R2Q1P0 \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
GET/v1/requests/{id}/archiveThe delivered archive of a request

After the guest answered, the app delivers the archive to EverStamp for your organisation (encrypted; the key is kept for you). This returns a link to everstamp.app/d/<id> with a one-time open token and the key: the verification, the photos and the download of the archive. The link opens for 10 minutes and at most 3 times; call again for a fresh link. expiresAt is when the delivered archive itself ends (Settings, Share links; default 365 days). Every call is logged.

Query parameters
id *paththe id (ulid)
Responses
200 OK
url *stringhttps://everstamp.app/d/<id>?o=<open token>#<key>: treat it as the archive itself; opens for 10 minutes and at most 3 times
expiresAt *string (date-time)
requeststring
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 unknown-request or not-delivered
410 share-gone: withdrawn or expired
503 audit-unavailable: the opening could not be logged, so no link was issued
curl -X GET https://api.everstamp.app/v1/requests/01K4C0Z9Y8X7W6V5T4S3R2Q1P0/archive \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/requests/{id}/cancelWithdraw a request, or mark it as handled

The link stops working and a guest link on a phone ends. Without `closedAs`, or with `withdrawn`, the request is withdrawn: the guest sees that the code is unknown or the request was withdrawn (404). With `closedAs: handled`, the matter was settled outside the request: the guest sees that the request is no longer open (410), and `reason` is an optional note on how it was settled. Either way the status is `cancelled`, with `closedAs` on the request; anything the guest sends after that does not belong to the request. Not after completion (409 request-completed): the dossier is already in the register.

Query parameters
id *paththe id (ulid)
Request body
reasonstringwhy (optional); with closedAs handled, your note on how it was settled (the guest does not see it)
closedAs"withdrawn" | "handled"how a cancelled request was closed: withdrawn (the default when you cancel), or handled (the matter was settled outside the request); a request from before this field reads withdrawn
Responses
200 OK
request *object
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
organisationName *stringyour organisation's name as the guest sees it; filled in from your organisation
codestringthe one-time code, eight characters; the link is https://everstamp.app/v/<code>
urlstring (uri)the link to send to the guest
title *stringwhat it is about; the guest sees it and the dossier is named after it
addressstringaddress, for the guest and on the stamp bar
notestringa note for the guest, in plain words
template *objectthe checklist: name and version; strict for a guest
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
guestNamestringthe guest's name as you know it; the guest confirms or corrects it
guestContactstringphone number or e-mail of the guest, for you only; wiped 30 days after completion
guestNameGivenstringthe name the guest gave on their phone
expiresAt *string (date-time)until when the link works; default 14 days, at most 30
status *"open" | "started" | "completed" | "expired" | "cancelled"open, started (accepted on a phone), completed (the dossier is in the register), expired or cancelled
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
startedAtstring (date-time)accepted on
devicestringthe guest's phone (sha-256 of its key id)
completedAtstring (date-time)when the dossier was registered
dossierstringthe dossier id
rootstringroot hash of that dossier
cancelledAtstring (date-time)withdrawn or handled on
cancelReasonstringwhy, or with handled the note on how it was settled
closedAs"withdrawn" | "handled"how a cancelled request was closed: withdrawn (the default when you cancel), or handled (the matter was settled outside the request); a request from before this field reads withdrawn
projectstringproject id (ulid)
projectNamestringname of that project
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
stampBarobjectstamp-bar layout for this dossier only
fields *array of "time" | "address" | "position" | "dossier" | "project" | "step" | "operator" | "organisation" | "note"lines on the bar, in order: time, address, position, dossier, project, step, operator, organisation, note
position"bottom" | "top"bottom or top
theme"dark" | "light"dark bar with light text, or light
size"small" | "medium" | "large"small, medium or large
namestringa name for this layout
prefillarray of objectfield values you already know (id from the checklist, value); the app fills them in and the guest confirms
id *stringulid
value *string
predecessorobject
dossier *stringthe dossier id
root *stringroot hash of that dossier
titlestringwhat it is about; the guest sees it and the dossier is named after it
at *string (date-time)
deliverystringthe delivery (share id) the app made for your organisation; open it with GET /v1/requests/{id}/archive
consentVersionintegerwhich declaration the guest confirmed when accepting (CONSENT.version in the contract); absent for an app from before that field
deliveredAtstring (date-time)when the archive arrived
countedbooleantrue while it counts in the bundle; false after withdrawal or expiry within the ten percent
400 invalid body: closedAs is withdrawn or handled
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
409 request-completed
curl -X POST https://api.everstamp.app/v1/requests/01K4C0Z9Y8X7W6V5T4S3R2Q1P0/cancel \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Dossiers

Every dossier the phones of the organisation registered: who, when, and whether the register has stamped the period yet.

GET/v1/dossiers/{id}/archiveThe kept archive of a dossier

Storage at EverStamp (Settings, Share links): when it is on, the app places every dossier of your members at EverStamp after registration, encrypted, with the key kept for your organisation. This returns a link to everstamp.app/d/<id> with a one-time open token and the key: the verification, the photos and the download of the archive. The link opens for 10 minutes and at most 3 times, so a forwarded link opens nothing; call again for a fresh link. 404 not-stored when nothing is kept for this dossier (storage off, not delivered yet, expired or withdrawn). expiresAt is when the kept archive itself ends (the retention of your organisation). Every call is logged.

Query parameters
id *paththe id (ulid)
Responses
200 OK
url *stringhttps://everstamp.app/d/<id>?o=<open token>#<key>: opens for 10 minutes and at most 3 times
expiresAt *string (date-time)
dossierstring
purposestring
keyHolderstringeverstamp: the key is kept in the vault of the registry
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 not-stored
410 share-gone
503 audit-unavailable: the opening could not be logged, so no link was issued
curl -X GET https://api.everstamp.app/v1/dossiers/01K4C0Z9Y8X7W6V5T4S3R2Q1P0/archive \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
GET/v1/dossiersList registered dossiers

Newest first, 100 per page (fewer with `limit`); pass the `registeredAt` of the last one as `before` for the next page. Each entry says whether the register has stamped the period (`closed`), the order it came from, its project, labels and predecessor.

Query parameters
limitquerypage size, 1 to 100; 100 when omitted
beforequerypaging: the registeredAt of the last dossier of the previous page (ISO 8601)
beforeDossierquerypaging: the dossier id of that last dossier; together with before an exact cursor
projectqueryonly dossiers of this project (ulid)
tagqueryonly dossiers with this label
statequeryclosed (the register has stamped the period) or pending
qquerysearch words; every word must occur in the title, address, member or guest name, checklist, labels, field values (licence plate), dossier id or root; case and accent insensitive
Responses
200 OK
format *"everstamp/3"always "everstamp/3"
dossiers *array of objectthe dossiers, newest first
dossier *stringdossier id (ulid)
root *stringroot hash over all captures (sha-256, hex)
device *stringthe phone (sha-256 of its key id)
memberstringthe member the phone belonged to at registration
memberNamestringtheir name
stampedAt *string (date-time)qualified timestamp of the dossier
registeredAt *string (date-time)when the register recorded it
period *stringthe register period (hour or day) the row is in
closed *booleantrue when the register has stamped that period: the qualified timestamp exists
orderstringthe order this dossier came from, if any
requeststringthe request this dossier answers, if any; the maker is then a guest, not a member
fieldsarray of objectfield values (id and value) from the checklist steps: licence plate, meter reading, serial number; as entered on the phone and signed with the photo: a statement, not a finding
id *stringfield id: lower case, digits and dashes; unique within the checklist
value *string
guestNamestringthe name the guest gave
projectstringproject id (ulid)
clipsobject
count *integer
seconds *integer
bytes *integer
capturesinteger
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
predecessorstringroot hash of the previous dossier when this is a follow-up
titlestringname of the dossier: from the registration, else the order title
templateobjectthe checklist of the dossier (name and version); a dossier that answers a request with a free built-in checklist carries its strict twin, <name>-request
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
storagestringstorage at EverStamp: the share id of the kept archive; open it with GET /v1/dossiers/{id}/archive. Absent while nothing is kept, and again after it expired or was withdrawn
storedAtstring (date-time)when the kept archive was confirmed
more *booleantrue when there is another page
400 bad filter or limit
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/dossiers \
  -H "Authorization: Bearer $EVERSTAMP_KEY"

Projects

A name or address that orders and dossiers belong to. Context, not part of the dossier itself unless the stamp bar shows the project name.

GET/v1/projectsList projects
Query parameters
archivedquery1 to include archived projects
Responses
200 OK
format *"everstamp/3"always "everstamp/3"
projects *array of objectthe projects, newest first
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
name *stringname or address
addressstringaddress, when the name is not one
notestringnote
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
ordersintegernumber of orders in the project
dossiersintegernumber of registered dossiers in the project
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/projects \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/projectsCreate a project
Request body
name *stringname or address
addressstringaddress, when the name is not one
notestringnote
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
Responses
201 created
project *objectproject id (ulid)
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
name *stringname or address
addressstringaddress, when the name is not one
notestringnote
tagsarray of stringlabels of the organisation; context to filter and count, not part of the dossier itself
createdAt *string (date-time)when it was created (ISO 8601)
createdBystringwho created it, as free text
archivedAtstring (date-time)archived on the dashboard: out of view, not deleted
ordersintegernumber of orders in the project
dossiersintegernumber of registered dossiers in the project
400 invalid body
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X POST https://api.everstamp.app/v1/projects \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Renovation West"}'

Checklists

The steps a dossier follows: built in from the library, or your own. A published version never changes.

GET/v1/templatesList checklists

Your own checklists (every version, retired ones marked) followed by the built-in library.

Responses
200 OK
format *"everstamp/3"always "everstamp/3"
templates *array of objectyour checklists (every version) followed by the built-in library
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
organisationstringorganisation id (ulid); implied by your key
createdAtstring (date-time)when it was created (ISO 8601)
retiredbooleantrue when retired: still readable for old dossiers, not offered for new ones
mode *"strict" | "free"strict (the app only closes a dossier when every step has its minimum) or free (the steps are a guide)
industriesarray of "construction" | "automotive" | "property" | "claims" | "logistics" | "maintenance" | "general"industries this built-in checklist belongs to
title *objecttitle per language, for example {"en": "Handover", "nl": "Oplevering"}
subtitle *objectsubtitle per language
steps *array of objectthe steps, in order
id *stringstep id: lower case, digits and dashes; unique within the checklist
title *objecttitle per language
required *integerminimum number of captures in this step; 0 is optional
shotsarray of objectnamed captures within the step (front, left, rear); the app asks for them one by one
id *stringshot id
title *objecttitle per language
fieldsarray of objectdata the step asks for next to the photos
id *stringfield id: lower case, digits and dashes; unique within the checklist
type *"text" | "number" | "licence-plate" | "meter-reading" | "serial" | "date" | "choice"text, number, licence-plate, meter-reading, serial, date or choice
title *objecttitle per language
required *booleantrue when the app insists on a value
hintobjecthint per language
unitstringunit for number and meter-reading (kWh, m3, km)
optionsarray of objectthe choices for a choice field
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/templates \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/templatesPublish a checklist version

Publishing is always a new version; the API assigns the number. Texts are per language (at least one). `mode` is strict (the app only closes a dossier when every step has its minimum) or free.

Request body
name *stringmachine name: lower case, digits and dashes; fixed after publishing
mode *"strict" | "free"strict (the app only closes a dossier when every step has its minimum) or free (the steps are a guide)
industriesarray of "construction" | "automotive" | "property" | "claims" | "logistics" | "maintenance" | "general"industries this built-in checklist belongs to
title *objecttitle per language, for example {"en": "Handover", "nl": "Oplevering"}
subtitle *objectsubtitle per language
steps *array of objectthe steps, in order
id *stringstep id: lower case, digits and dashes; unique within the checklist
title *objecttitle per language
required *integerminimum number of captures in this step; 0 is optional
shotsarray of objectnamed captures within the step (front, left, rear); the app asks for them one by one
id *stringshot id
title *objecttitle per language
fieldsarray of objectdata the step asks for next to the photos
id *stringfield id: lower case, digits and dashes; unique within the checklist
type *"text" | "number" | "licence-plate" | "meter-reading" | "serial" | "date" | "choice"text, number, licence-plate, meter-reading, serial, date or choice
title *objecttitle per language
required *booleantrue when the app insists on a value
hintobjecthint per language
unitstringunit for number and meter-reading (kWh, m3, km)
optionsarray of objectthe choices for a choice field
id *stringulid
title *objecttitle
Responses
201 published
template *object
name *stringmachine name: lower case, digits and dashes; fixed after publishing
version *integerassigned by the API; a version never changes
organisationstringorganisation id (ulid); implied by your key
createdAtstring (date-time)when it was created (ISO 8601)
retiredbooleantrue when retired: still readable for old dossiers, not offered for new ones
mode *"strict" | "free"strict (the app only closes a dossier when every step has its minimum) or free (the steps are a guide)
industriesarray of "construction" | "automotive" | "property" | "claims" | "logistics" | "maintenance" | "general"industries this built-in checklist belongs to
title *objecttitle per language, for example {"en": "Handover", "nl": "Oplevering"}
subtitle *objectsubtitle per language
steps *array of objectthe steps, in order
id *stringstep id: lower case, digits and dashes; unique within the checklist
title *objecttitle per language
required *integerminimum number of captures in this step; 0 is optional
shotsarray of objectnamed captures within the step (front, left, rear); the app asks for them one by one
id *stringshot id
title *objecttitle per language
fieldsarray of objectdata the step asks for next to the photos
id *stringfield id: lower case, digits and dashes; unique within the checklist
type *"text" | "number" | "licence-plate" | "meter-reading" | "serial" | "date" | "choice"text, number, licence-plate, meter-reading, serial, date or choice
title *objecttitle per language
required *booleantrue when the app insists on a value
hintobjecthint per language
unitstringunit for number and meter-reading (kWh, m3, km)
optionsarray of objectthe choices for a choice field
400 invalid checklist
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
409 name of a built-in checklist
curl -X POST https://api.everstamp.app/v1/templates \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Renovation West","mode":"strict","title":"Kloosterweg 14, meter cupboard","subtitle":{"en":"Example"},"steps":[{"id":"overview","title":{"en":"Overview"},"required":2}]}'

People and devices

Members of the organisation and the phones linked to them.

GET/v1/membersList members
Responses
200 OK
format *"everstamp/3"
members *array of object
id *stringmember id (ulid); use it as `member` when preparing an order
organisation *stringorganisation id
email *stringe-mail address
name *stringname of the person, as it appears on the stamp bar
role *"owner" | "admin" | "worker" | "reader"
invitedAt *string (date-time)invited on
acceptedAtstring (date-time)first sign-in; absent until then
active *booleanfalse when deactivated
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/members \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
GET/v1/devicesLinked phones and open device codes
Responses
200 OK
format *"everstamp/3"always "everstamp/3"
enrolments *array of objectlinked phones, current and revoked
device *stringthe phone (sha-256 of its key id)
organisation *stringorganisation id (ulid); implied by your key
member *stringmember id
invitation *stringthe device code that linked it
enrolledAt *string (date-time)linked on
revokedAtstring (date-time)unlinked on
blockedAtstring (date-time)
platform"ios" | "android"
playIntegrity"strong" | "device" | "basic" | "none" | "unrecognized"
invitations *array of objectdevice codes: open, used or withdrawn
id *stringulid
organisation *stringorganisation id (ulid); implied by your key
organisationName *stringorganisation name
member *stringmember the code is for
memberName *stringtheir name
createdAt *string (date-time)when it was created (ISO 8601)
expiresAt *string (date-time)valid until
usedAtstring (date-time)used on
usedBystringthe phone that used it
cancelledAtstring (date-time)withdrawn on
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/devices \
  -H "Authorization: Bearer $EVERSTAMP_KEY"

Key

Who this key is: the organisation, its rights and, for a webhooks key, its events and expiry. Integration platforms use it to test a connection.

GET/v1/meThis key
Responses
200 OK
organisation *object
id *stringorganisation id (ulid)
name *string
slug *stringthe short name in dashboard links
key *object
name *stringthe name you gave the key
scope *"read" | "write"
webhooks *booleantrue when the key may manage its own webhooks
webhookEvents *array of "order.claimed" | "dossier.registered" | "device.enrolled" | "device.revoked" | "device.blocked" | "request.started" | "request.completed" | "request.delivered" | "dossier.stored"the events it may subscribe to; empty without the webhooks right
expiresAt *string | nullexpiry; null is unlimited (never for a webhooks key)
403 api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/me \
  -H "Authorization: Bearer $EVERSTAMP_KEY"

Webhooks

For integration platforms such as Zapier, Make and n8n: a key with the webhooks right subscribes to events itself. That right is chosen when the key is created (with the events it may use and an expiry of at most two years) and sits beside read or write; it cannot be added later. A key sees and removes only its own webhooks. By default only known platform addresses are allowed (hooks.zapier.com, Make, app.n8n.cloud); an owner or admin can add a self-hosted address under Integrations. Every new webhook is reported to all owners. After the key expires or is revoked, nothing is delivered any more.

GET/v1/webhooksWebhooks of this key

Only the webhooks this key created; those of other keys and of the dashboard do not show.

Responses
200 OK
webhooks *array of object
id *stringwebhook id (ulid)
organisation *stringorganisation id (ulid)
url *stringwhere deliveries go (https)
events *array of "order.claimed" | "dossier.registered" | "device.enrolled" | "device.revoked" | "device.blocked" | "request.started" | "request.completed" | "request.delivered" | "dossier.stored"the events it receives
createdAt *string (date-time)created on
active *booleanfalse after too many failed deliveries, after the key expired, or when its address is no longer allowed
lastDeliveryAtstring (date-time)last attempt
lastStatusintegerhttp status of the last attempt; 0 when there was no answer
apiKeystringthe key that created it (its id)
expiresAtstring (date-time)the expiry of that key; after it nothing is delivered
403 this key does not have the webhooks right (api-key-no-webhooks); or api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
curl -X GET https://api.everstamp.app/v1/webhooks \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
POST/v1/webhooksSubscribe to events

At most 10 per key and 25 per organisation, and at most 30 new ones per key per hour. The webhook ends when the key expires or is revoked. All owners of the organisation get an e-mail.

Request body
url *string (uri)https address on a known platform (hooks.zapier.com, hook.<zone>.make.com, app.n8n.cloud or a subdomain) or on a host your organisation added under Integrations; at most 2000 characters
events *array of "order.claimed" | "dossier.registered" | "device.enrolled" | "device.revoked" | "device.blocked" | "request.started" | "request.completed" | "request.delivered" | "dossier.stored"events to receive; only those your key may use (GET /v1/me)
Responses
201 created; Location is /v1/webhooks/{id}
id *stringwebhook id (ulid)
url *string
events *array of string
secret *stringsigning secret (whsec_...), shown once: verify every delivery with it (Standard Webhooks: webhook-id, webhook-timestamp, webhook-signature)
createdAt *string (date-time)
expiresAt *string (date-time)the expiry of the key; after it nothing is delivered
400 invalid url or events
403 this key does not have the webhooks right (api-key-no-webhooks); or api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
422 event-not-allowed (outside the events of this key) or host-not-allowed (not a known platform or an address of your organisation)
429 too many webhooks for this key or organisation
curl -X POST https://api.everstamp.app/v1/webhooks \
  -H "Authorization: Bearer $EVERSTAMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"example","events":[]}'
DELETE/v1/webhooks/{id}Remove a webhook of this key
Query parameters
id *paththe id (ulid)
Responses
200 OK
id *string
deletedAt *string (date-time)
403 this key does not have the webhooks right (api-key-no-webhooks); or api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 this key has no webhook with that id
curl -X DELETE https://api.everstamp.app/v1/webhooks/01K4C0Z9Y8X7W6V5T4S3R2Q1P0 \
  -H "Authorization: Bearer $EVERSTAMP_KEY"
GET/v1/webhooks/samples/{event}A sample delivery

Exactly the shape a webhook receives, with made-up data and a fixed moment (2026-01-15T09:45:00Z); never real events of your organisation. Integration platforms use it to map fields.

Query parameters
event *pathone of the events
Responses
200 OK
format *"everstamp/3"
event *string
at *string (date-time)
organisation *string
data *object
403 this key does not have the webhooks right (api-key-no-webhooks); or api-not-allowed: API keys work only for an organisation on Business by quote with the API, or on Enterprise, that has paid; the key stays and works again once that is so
404 unknown event
curl -X GET https://api.everstamp.app/v1/webhooks/samples/{event} \
  -H "Authorization: Bearer $EVERSTAMP_KEY"

Webhooks

Add a webhook in the dashboard (Settings, Integrations) with an https URL and the events you want. Every delivery is a POST with the Standard Webhooks headers webhook-id, webhook-timestamp and webhook-signature (v1, plus base64 of HMAC-SHA256 over id.timestamp.body with your secret, shown once). Answer any 2xx within five seconds; otherwise we retry after 1, 5, 30 minutes, 2 and 12 hours, and switch the webhook off after eight failures in a row. The same webhook-id is reused on retries, so you can deduplicate.

0
1
2
3
4
5
6
7
8
Body
{ "format": "everstamp/3", "event": "dossier.registered", "at": "2026-09-05T14:53:10Z", "organisation": "01M1...", "data": { "dossier": { ... }, "order": { ... } } }
Verify the signature
import { createHmac, timingSafeEqual } from 'node:crypto';

const secret = Buffer.from(process.env.WEBHOOK_SECRET.replace('whsec_', ''), 'base64');
const id = req.headers['webhook-id'], ts = req.headers['webhook-timestamp'];
const expected = 'v1,' + createHmac('sha256', secret).update(`${id}.${ts}.${rawBody}`).digest('base64');
const ok = timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['webhook-signature']));
if (!ok || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.status(401).end();

Recipes: Zapier, Make, n8n

No code needed for the two things most companies want: hear it when a dossier is registered, and prepare an order from something that already exists (a form, a planning tool, a CRM). The webhook URL these tools give you is unguessable, which is the shared secret for a no-code receiver; verify the signature only if the tool lets you run code.

Zapier

  1. 1. Registered dossier to a sheet or a chat. Trigger: Webhooks by Zapier, Catch Hook. Copy the URL into the dashboard (Settings, Integrations, add webhook, event dossier.registered). Register a test dossier in the app so Zapier sees a sample. Map data__dossier__title, data__dossier__memberName, data__dossier__stampedAt to a Google Sheets row, a Slack message or a Teams post.
  2. 2. Form to order. Trigger: your form (Typeform, Google Forms, Jotform). Action: Webhooks by Zapier, Custom Request, POST https://api.everstamp.app/v1/orders, header Authorization: Bearer esk_..., data: {"title": ..., "address": ..., "template": {"name": "meter-cupboard", "version": 1}, "member": "<member id>"}. Find member ids once with GET /v1/members.
  3. 3. Claim to photo request. Trigger: a new claim in your system (a form, a CRM row). Action: POST https://api.everstamp.app/v1/requests with {"title": "Damage, plate AB-123-C", "template": {"name": "handover", "version": 1}, "guestName": ..., "guestContact": ...}; the reply carries url, which your next step sends to the customer by e-mail or SMS. A request.completed webhook then hands you the dossier.

Make

  1. 1. Registered dossier. Module Webhooks, Custom webhook; paste its address in the dashboard as a webhook for dossier.registered; run once to let Make learn the structure; then any module (Google Sheets, Gmail, Notion).
  2. 2. Prepare orders from a planning. Module HTTP, Make a request: POST https://api.everstamp.app/v1/orders, header Authorization with your key, body type JSON, the same body as above. Add a router on status from GET /v1/orders?status=claimed,registered to move your own records along.

n8n

  1. 1. Registered dossier. Webhook node (POST, respond immediately) as the trigger; its production URL goes in the dashboard. Optional Code node with the Node snippet above to verify webhook-signature. Then Google Sheets, Slack or Postgres.
  2. 2. Orders from a database. Schedule trigger, Postgres or MySQL node selecting the jobs of tomorrow, HTTP Request node POST https://api.everstamp.app/v1/orders with Header Auth (Authorization, Bearer esk_...) and a JSON body per item. Store the returned order.id next to your job to follow its status.
Importable n8n workflow (JSON)
{
  "name": "EverStamp: dossier registered",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "everstamp",
        "responseMode": "onReceived"
      },
      "name": "EverStamp webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const d = $json.body.data.dossier;\nreturn [{ json: { title: d.title, who: d.memberName, stampedAt: d.stampedAt, root: d.root, project: d.project } }];"
      },
      "name": "Pick fields",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        260,
        0
      ]
    }
  ],
  "connections": {
    "EverStamp webhook": {
      "main": [
        [
          {
            "node": "Pick fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

OpenAPI

The machine-readable description of this API, generated from the same contract the app and the register are built on: openapi.json. Import it in Postman, Bruno, Insomnia or a code generator; it is the file to hand to a code assistant. Contract fingerprint 9741eb534c8cb90a, model 26fed14e40695008.

Changelog

  • 2026-09-17 Archive links: GET /v1/dossiers/{id}/archive and GET /v1/requests/{id}/archive now return a link with a one-time open token; it opens for 10 minutes and at most 3 times, so call again for a fresh link instead of storing it. An opening that cannot be logged returns 503 audit-unavailable.
  • 2026-09-06 Delivery: the archive of an answered request is kept at EverStamp for your organisation; GET /v1/requests/{id}/archive returns the link with the key, webhook request.delivered.
  • 2026-09-06 Fields on checklist steps (text, number, licence-plate, meter-reading, serial, date, choice): values travel in the signed capture, appear as fields on dossiers, and prefill on a request lets you pass what you already know. Built-in v2 of vehicle-intake, meter-reading and certification.
  • 2026-09-06 Requests: photos from your customers via a one-time link (/v1/requests, webhooks request.started and request.completed); project filter on dossiers; order updates accept project, labels and stamp bar.
  • 2026-09-05 Projects, labels, several pickups per order, delete and archive, checklist library with strict and free mode, stamp-bar layout, plan and usage, dossier title and checklist in the dossier list, api.everstamp.app with this reference and openapi.json.
  • 2026-09-04 First release: orders, checklists, dossiers, members, devices, webhooks.

Questions or a missing endpoint: privacy@everstamp.app · EverStamp is built by Digital Sandbox B.V., Netherlands.