Skip to main content

Walkthrough: CRUD and files

This page walks through the everyday calls against the data API end to end: create an object, read it, list it, change it, upload and download a document, and delete the object. Each step links to the reference page with the full details.

Setup​

The examples use a model with a class my-project.company that has these fields and relations:

NameKind
nameTEXT, required (inherited from commons.item)
registrationNumberTEXT
foundedOnDATE
legalFormLIST with keys bv, nv, vof
countrysingle-valued relation to countries

company becomes companies in URLs — see Qualified names and URLs.

The calls run against the develop environment with an API key. Set these once:

API=https://api.develop.mosterd.com
TENANT=2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d
AUTH="X-API-Key: $MOSTERD_API_KEY"

1. Create​

curl -i -X POST "$API/data/$TENANT/companies" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{
"name": "Acme B.V.",
"registrationNumber": "12345678",
"foundedOn": "2019-03-01",
"legalForm": "bv",
"country": "/data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/countries/5b1d0c9e-2a47-4f3b-8e61-7c9d2a0f4e18"
}'
HTTP/1.1 201 Created
Location: /data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/companies/8d3e2b71-4c0a-4e9f-a1d6-5f2b9c7e0a34

The response has no body. The Location header is the new object's URI; its last segment is the id:

COMPANY=8d3e2b71-4c0a-4e9f-a1d6-5f2b9c7e0a34

A relation is set by passing the related object's URI — here the country. Fields you leave out stay empty; required fields you leave out produce 400 Bad Request. See Create.

2. Read​

curl "$API/data/$TENANT/companies/$COMPANY" -H "$AUTH"
{
"_class": "companies",
"_creationDate": "2026-09-24T09:12:31.482Z",
"_modificationDate": "2026-09-24T09:12:31.482Z",
"name": "Acme B.V.",
"registrationNumber": "12345678",
"foundedOn": "2019-03-01",
"legalForm": "bv",
"_classes": ["companies"],
"_links": {
"_self": { "href": "/data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/companies/8d3e2b71-4c0a-4e9f-a1d6-5f2b9c7e0a34" },
"country": {
"href": "/data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/countries/5b1d0c9e-2a47-4f3b-8e61-7c9d2a0f4e18",
"name": "Netherlands"
}
}
}

Fields are top-level properties; relations are under _links. Some links are left out here for brevity — see Get one for the full shape.

3. List​

curl "$API/data/$TENANT/companies?legalForm=bv&sort=name,asc&size=20" -H "$AUTH"

Returns a page of companies whose legal form is bv, sorted by name. Filters, sorting and paging are described in Querying objects.

4. Update​

Send only what changes:

curl -i -X PATCH "$API/data/$TENANT/companies/$COMPANY" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{ "registrationNumber": "87654321", "foundedOn": null }'
HTTP/1.1 204 No Content
Location: /data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/companies/8d3e2b71-4c0a-4e9f-a1d6-5f2b9c7e0a34

registrationNumber is replaced, foundedOn is cleared, and everything else is left as it was. A multi-valued relation is the exception: sending it replaces the whole list. See Patch.

5. Upload a document​

A file is not an object of its own; it is the value of a field. A document is an object of class commons.document whose file field holds the file. Uploading one takes three calls. The bytes do not go through the data API, but to a short-lived signed URL.

Request an upload URL:

curl "$API/data/$TENANT/upload" -H "$AUTH"
"https://api.develop.mosterd.com/binaries/eyJhbGciOiJFUzI1NiJ9…"

Upload the file to that URL within two minutes, as a multipart part named file:

curl -X POST "https://api.develop.mosterd.com/binaries/eyJhbGciOiJFUzI1NiJ9…" \
-F "file=@signed-contract.pdf"

Note that there is no -H "$AUTH" here. Requests to /binaries/ must not carry an API key or bearer token — the signed URL is the credential.

[
{
"href": "/binaries/3fa85f64-5717-4562-b3fc-2c963f66afa6",
"fileName": "signed-contract.pdf",
"contentType": "application/pdf",
"size": 48213
}
]

Create the document with the returned object, unchanged, as the value of its file field. A document belongs to a dossier, which is a required relation:

curl -i -X POST "$API/data/$TENANT/documents" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{
"dossier": "/data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/dossiers/7c2e5a91-3d4b-4f86-a0e1-9b8d6c3f2e17",
"file": {
"href": "/binaries/3fa85f64-5717-4562-b3fc-2c963f66afa6",
"fileName": "signed-contract.pdf",
"contentType": "application/pdf",
"size": 48213
}
}'
HTTP/1.1 201 Created
Location: /data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/documents/c4a9e2f7-1b6d-4e38-9f05-8a3d7b2c6e91
DOCUMENT=c4a9e2f7-1b6d-4e38-9f05-8a3d7b2c6e91

Until this step, the uploaded file does not belong to any object. Any object with a FILE or IMAGE field works the same way: put the upload result in that field, on create or on patch. See Files.

6. Download a document​

Reading the document shows the file with a download link:

curl "$API/data/$TENANT/documents/$DOCUMENT" -H "$AUTH"
"file": {
"contentType": "application/pdf",
"fileName": "signed-contract.pdf",
"size": 48213,
"href": "/data/2f9c6e1a-7b34-4d58-9c21-0a5e8f1b2c3d/download/c4a9e2f7-1b6d-4e38-9f05-8a3d7b2c6e91/3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

That href returns a signed URL, not the file itself:

curl "$API/data/$TENANT/download/$DOCUMENT/3fa85f64-5717-4562-b3fc-2c963f66afa6" -H "$AUTH"
"https://api.develop.mosterd.com/binaries/eyJhbGciOiJFUzI1NiJ9…"

Fetch the signed URL within two minutes — again without credentials:

curl -o signed-contract.pdf "https://api.develop.mosterd.com/binaries/eyJhbGciOiJFUzI1NiJ9…"

In a browser, the signed URL can be used directly as a link, or as the source of an <iframe> (PDF) or <img> (images). See Downloading a file.

7. Delete​

curl -i -X DELETE "$API/data/$TENANT/companies/$COMPANY" -H "$AUTH"
HTTP/1.1 200 OK

The delete is permanent. Objects that link to the company are updated, deleted too, or block the delete with 409 Conflict, depending on their relation — see Delete.