Back to home
Entity API docs

A simple entity HTTP API.

Create, read, update, delete, and list JSON or EDN entities.

Auth

Send x-api-key. Read-only keys cannot write or delete.

Formats

Send JSON or EDN. Use .json or .edn for the response.

Limits

Body max: 1 MB. Batch max: 20 entities. Query pagination sizes: 20, 50, or 100.

Quick start

Start in three steps

Set the URL and key. Create, patch, then read an entity.

  1. Set API_BASE_URL and SHIP_DEPLOY_API_KEY.
  2. Create an entity.
  3. Patch its data.
  4. Read it by id.
Example
export API_BASE_URL=https://shipdeploy.work/api/v1
export SHIP_DEPLOY_API_KEY=replace-with-your-api-key
Example
curl -X POST "$API_BASE_URL/entities.json" \
  -H 'content-type: application/json' \
  -H "x-api-key: $SHIP_DEPLOY_API_KEY" \
  -d '{"id":"person-ada","type":"person","labels":{"region":"za"},"data":{"name":"Ada","active":false,"profile":{"city":"London"}}}'
Example
curl -X POST "$API_BASE_URL/entities/patch.json" \
  -H 'content-type: application/json' \
  -H "x-api-key: $SHIP_DEPLOY_API_KEY" \
  -d '{"id":"person-ada","patches":[["assoc","active",true],["assoc-in",["profile","email"],"ada@example.com"],["deep-merge",{"profile":{"city":"Cape Town"}}]]}'
Example
curl -X POST "$API_BASE_URL/queries/find-entity-by-id.json" \
  -H 'content-type: application/json' \
  -H "x-api-key: $SHIP_DEPLOY_API_KEY" \
  -d '{"id":"person-ada"}'
History

Review every change

Every write adds a version. Deleted entities keep their history.

Evict removes the entity and all history.

POST /entities/history

List change metadata. No data or diffs.

POST /entities/history/version

Get one version snapshot.

Tenants

Keys select the tenant

Each tenant has separate data and keys. Clients do not send tenant ids.

Write keys change data. Read-only keys can only read and list.

Private data

Every key is scoped to one tenant.

Write keys

Create, update, and delete entities.

Read-only keys

Read and list without changing data.

No tenant ids

The API key handles isolation for you.

Core endpoints

What the API does

Create, read, update, delete, and list entities. Advanced operations remain available when you need them.

GET /health

Check service health

Return status and deployed version.

POST /entities

Create an entity

Store one entity. The server can create the id.

POST /queries/find-entity-by-id

Find one entity

Return one entity by id.

POST /queries/find-entities-by-type

Find entities by type

Return a page of one entity type.

POST /queries/find-entities-by-attributes

Find entities by attributes

Match fields in entity data.

POST /queries/find-entities-by-labels

Find entities by labels

Match every supplied label.

POST /entities/upsert

Upsert an entity

Create or replace an entity by id.

POST /entities/update

Update an entity

Update an existing entity. Missing ids return 404.

POST /entities/patch

Patch entity data

Apply ordered patches to entity data.

POST /entities/labels

Replace entity labels

Replace labels. An empty map clears them.

POST /entities/batch

Create multiple entities

Store up to 20 entities together or independently.

POST /entities/delete

Delete an entity

Soft delete hides it. Hard delete removes it. Both keep history.

POST /entities/evict

Evict an entity

Permanently remove the entity and history.

POST /entities/history

List entity history

List version and change metadata.

POST /entities/changes

List entity changes

Alias for entity history.

POST /entities/history/version

Get one history version

Return one version snapshot.

POST /queries/recent-entities-by-type

Get recent entities by type

Return the latest 20 entities of one type.

POST /schema

Inspect one object structure

Infer one object's fields and types. No key required.

POST /schema/by-entity-id

Inspect one stored entity

Infer one stored entity's structure.

POST /schema/sample-by-type

Inspect stored data by type

Show common and uncommon fields for one type.

POST /entity-type-configs

Configure an entity type

Set display names and relationship rules.

POST /relationship-definitions

Define a relationship

Define a relationship between entity types.

POST /entity-relationships

Link related entities

Link two existing entities.

POST /entity-relationships/delete

Unlink related entities

Remove a link and record the change.

POST /entity-relationships/by-entity

List entity relationships

List links for one entity.

POST /entity-relationships/graph

Get relationship graph

Return an entity and its neighbours.

POST /entity-relationships/infer

Infer relationships

Create links from configured id fields.

Check health

Confirm the service and deployed version.

Example
curl https://shipdeploy.work/health.json

Create an entity

Store one entity. Omit id to create one.

Example
curl -X POST https://shipdeploy.work/api/v1/entities.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","type":"person","labels":{"region":"za","workflow/status":"active"},"data":{"name":"Ada","active":true,"department":"research"}}'

Find one entity

Read one entity by id.

Example
curl -X POST https://shipdeploy.work/api/v1/queries/find-entity-by-id.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada"}'

Find entities by type

Page sizes: 20, 50, or 100. Sort by id, type, created-at, or updated-at.

Example
curl -X POST https://shipdeploy.work/api/v1/queries/find-entities-by-type.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"type":"person","page":1,"page-size":20,"sort-by":"updated-at","sort-direction":"desc"}'

Find entities by attributes

Match fields in entity data.

Example
curl -X POST https://shipdeploy.work/api/v1/queries/find-entities-by-attributes.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"attributes":{"department":"research","active":true},"page-size":20}'

Find entities by labels

Labels sit outside data. Every supplied label must match.

Example
curl -X POST https://shipdeploy.work/api/v1/queries/find-entities-by-labels.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"labels":{"region":"za","workflow/status":"active"},"page-size":20}'

Upsert by id

Create or replace an entity by id.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/upsert.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","type":"person","data":{"name":"Ada Lovelace","active":true}}'

Update by id

Update an existing id. Missing or deleted entities return 404.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/update.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","type":"person","data":{"name":"Ada Lovelace","active":true}}'

Patch entity data

Apply data patches in order. Type and labels stay unchanged.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/patch.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","patches":[["assoc","active",true],["assoc-in",["profile","email"],"ada@example.com"],["deep-merge",{"profile":{"address":{"city":"Cape Town"}}}],["dissoc","legacy"]]}'

Replace labels

Type and data stay unchanged. An empty map clears all labels.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/labels.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","labels":{"region":"za","workflow/status":"active"},"reason":"assigned to active workflow"}'

Create multiple entities

Send 1 to 20 entities within 1 MB. By default, all succeed or none are saved. Set transaction to false for independent results.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/batch.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"entities":[{"id":"person-ada","type":"person","data":{"name":"Ada"}},{"type":"person","data":{"name":"Grace"}}]}'
Example
curl -X POST https://shipdeploy.work/api/v1/entities/batch.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"transaction":false,"entities":[{"id":"person-ada","type":"person","data":{"name":"Ada"}},{"id":"person-grace","type":"person","data":{"name":"Grace"}}]}'

Soft delete

Hide the entity. Keep its history and versions.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/delete.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","mode":"soft"}'

Hard delete

Remove the entity. Keep its history and versions.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/delete.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","mode":"hard"}'

Evict

Permanently remove the entity and all history.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/evict.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada"}'

List history

List change metadata. Deleted entities remain until evicted. No data or diffs.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/history.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","page":1,"page-size":20}'

List changes

Same response as history.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/changes.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","page":1,"page-size":20}'

Get a version

Get one version snapshot.

Example
curl -X POST https://shipdeploy.work/api/v1/entities/history/version.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","version":2}'

Get recent entities by type

Get the latest 20 entities of one type.

Example
curl -X POST https://shipdeploy.work/api/v1/queries/recent-entities-by-type.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"type":"person"}'

Inspect one object

Infer fields and types. No key required.

Example
curl -X POST https://shipdeploy.work/api/v1/schema.json \
  -H 'content-type: application/json' \
  -d '{"object":{"name":"Ada","age":37,"active":true,"tags":["research"]}}'

Inspect one stored entity

Infer one stored entity's structure.

Example
curl -X POST https://shipdeploy.work/api/v1/schema/by-entity-id.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada"}'

Sample stored entities

See common and uncommon fields in a sample.

Example
curl -X POST https://shipdeploy.work/api/v1/schema/sample-by-type.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"type":"person","sample-size":20}'

Configure an entity type

Set display names and infer links from stored ids.

Example
curl -X POST https://shipdeploy.work/api/v1/entity-type-configs.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"type":"person","display-name":"{{name}}","relationships":[{"id":"person-manager","name":"Manager","to-type":"person","cardinality":"many-to-one","source-field":"manager-id"}]}'

Link entities

Define a relationship, then link two ids.

Example
curl -X POST https://shipdeploy.work/api/v1/relationship-definitions.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-team","name":"Team member","from-type":"person","to-type":"team","cardinality":"many-to-one"}'
Example
curl -X POST https://shipdeploy.work/api/v1/entity-relationships.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"relationship-id":"person-team","from-id":"person-ada","to-id":"team-research","reason":"assigned to research team"}'

List or infer links

Read links or create them from configured id fields.

Example
curl -X POST https://shipdeploy.work/api/v1/entity-relationships/by-entity.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada"}'
Example
curl -X POST https://shipdeploy.work/api/v1/entity-relationships/infer.json \
  -H 'content-type: application/json' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{"id":"person-ada","reason":"inferred from manager-id"}'
For Clojure developers

Use EDN from Clojure

Send and receive native EDN data.

Send content-type: application/edn. Request EDN with accept: application/edn or .edn.

Parse responses with clojure.edn/read-string.

Example
curl -X POST https://shipdeploy.work/api/v1/entities.edn \
  -H 'content-type: application/edn' \
  -H 'accept: application/edn' \
  -H 'x-api-key: replace-with-your-api-key' \
  -d '{:id "person-ada" :type "person" :data {:name "Ada" :active true :tags ["research"]}}'
Example
(import '[java.net URI]
        '[java.net.http HttpClient HttpRequest HttpRequest$BodyPublishers HttpResponse$BodyHandlers])
(require '[clojure.edn :as edn])

(def payload
  {:id "person-ada"
   :type "person"
   :data {:name "Ada" :active true}})

(def response
  (.send (HttpClient/newHttpClient)
         (-> (HttpRequest/newBuilder (URI/create "https://shipdeploy.work/api/v1/entities.edn"))
             (.header "content-type" "application/edn")
             (.header "accept" "application/edn")
             (.header "x-api-key" "replace-with-your-api-key")
             (.POST (HttpRequest$BodyPublishers/ofString (pr-str payload)))
             (.build))
         (HttpResponse$BodyHandlers/ofString)))

(edn/read-string (.body response))

Common responses

Standard HTTP status codes.

401Unauthorized

Missing or invalid API key.

403Forbidden

Read-only API key attempted a write operation.

404Not Found

Route or entity was not found.

409Conflict

Entity id already exists.

413Content Too Large

Request body exceeded 1 MB.