Quickstart
Push your first version in 5 minutes. All you need is curl and a running Underlay instance.
1. Create an account
curl -X POST https://underlay.org/api/accounts/signup \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-password",
"username": "yourname",
"displayName": "Your Name"
}' 2. Create an API key
Log in and create a write-scoped key:
# Login (saves session cookie)
curl -X POST https://underlay.org/api/accounts/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email": "[email protected]", "password": "your-password"}'
# Create API key
curl -X POST https://underlay.org/api/accounts/keys \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{"label": "my-app", "scope": "write"}'
# → {"id":"...","key":"ul_abc123...","label":"my-app","scope":"write"} Save the key value — it's shown only once.
3. Create a collection
export KEY="ul_abc123..."
curl -X POST https://underlay.org/api/accounts/yourname/collections \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KEY" \
-d '{
"slug": "my-dataset",
"name": "My Dataset",
"description": "A test collection",
"public": true
}' 4. Push a version
curl -X POST https://underlay.org/api/collections/yourname/my-dataset/versions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KEY" \
-d '{
"base_version": null,
"message": "Initial import",
"app_id": "my-app",
"schema": {
"type": "object",
"properties": {
"Book": {
"type": "object",
"properties": {
"title": {"type": "string"},
"author": {"type": "string"},
"year": {"type": "integer"}
}
}
}
},
"changes": {
"added": [
{"id": "book-1", "type": "Book", "data": {"title": "Gödel, Escher, Bach", "author": "Douglas Hofstadter", "year": 1979}},
{"id": "book-2", "type": "Book", "data": {"title": "The Structure of Scientific Revolutions", "author": "Thomas Kuhn", "year": 1962}}
]
}
}'
# → {"version":1,"semver":"v1.0.0","hash":"...","recordCount":2,"fileCount":0} 5. Read it back
# Get collection info
curl https://underlay.org/api/collections/yourname/my-dataset
# Get version 1 records
curl https://underlay.org/api/collections/yourname/my-dataset/versions/1/records
# Get the manifest
curl https://underlay.org/api/collections/yourname/my-dataset/versions/1/manifest 6. Push an update
curl -X POST https://underlay.org/api/collections/yourname/my-dataset/versions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KEY" \
-d '{
"base_version": 1,
"message": "Add third book, fix year",
"changes": {
"added": [
{"id": "book-3", "type": "Book", "data": {"title": "Philosophical Investigations", "author": "Ludwig Wittgenstein", "year": 1953}}
],
"updated": [
{"id": "book-1", "type": "Book", "data": {"title": "Gödel, Escher, Bach", "author": "Douglas Hofstadter", "year": 1979}}
]
}
}'
# → {"version":2,"semver":"v1.1.0","hash":"...","recordCount":3,"fileCount":0} 7. Diff versions
curl https://underlay.org/api/collections/yourname/my-dataset/versions/2/diff?from=1
# → {"from":1,"to":2,"added":[...],"updated":[...],"removed":[]} Working with files
To attach files (PDFs, images, etc.) to records, upload them first by hash:
# Compute hash
HASH=$(shasum -a 256 paper.pdf | cut -d' ' -f1)
# Upload
curl -X PUT "https://underlay.org/api/collections/yourname/my-dataset/files/sha256:$HASH" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/pdf" \
--data-binary @paper.pdf
# Reference in a record
# {"id": "book-1", "type": "Book", "data": {"title": "...", "pdf": {"$file": "sha256:..."}}} Next steps
- Core concepts — understand the data model
- Versions API — full reference for push/pull
- Files API — content-addressed file storage