API reference

Entities

Create or update customers, accounts, wallets, devices, agents and counterparties, and read them and their links back.
POST /v1/entities

Creates an entity, or updates it if one with the same id already exists in your organisation. On an update, the kind you send replaces the stored one and attributes are merged into what's there. Returns the entity as stored.

See Entities and the graph for what each kind represents.

Request body

id
string required
Your ID for the entity. Use the one your own systems already use. Must not be empty.
kind
string required
One of customer, account, wallet, device, agent or counterparty.
attributes
object
Free-form JSON. Send what you have; you can add fields later.

Example

Terminal
curl -X POST "$SENTINEL_URL/v1/entities" \
  -H "Authorization: Bearer $SENTINEL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "cus_10442",
    "kind": "customer",
    "attributes": {
      "name": "Test Customer",
      "date_of_birth": "1990-04-12",
      "kyc_result": "verified",
      "risk_tier": "standard"
    }
  }'
Response · 200
{
  "id": "cus_10442",
  "kind": "customer",
  "attributes": {
    "name": "Test Customer",
    "date_of_birth": "1990-04-12",
    "kyc_result": "verified",
    "risk_tier": "standard"
  },
  "created_at": "2026-10-15T09:14:03.512Z",
  "updated_at": "2026-10-15T09:14:03.512Z"
}

A wallet looks the same with a different kind:

Request
{
  "id": "wal_8812",
  "kind": "wallet",
  "attributes": {
    "operator": "Example Mobile Money",
    "opened_at": "2026-10-12"
  }
}

Response fields

FieldTypeMeaning
idstringYour ID
kindstringThe entity kind
attributesobjectAttributes as stored
created_atstring, date-timeWhen Sentinel first saw this entity
updated_atstring, date-timeWhen it was last changed

Errors

Codeerror
400id is required
400unknown kind
401missing or invalid API key

List entities

GET /v1/entities

Entities in your organisation, most recently changed first. Lists come a page at a time, newest first. Pass limit (1 to 200, default 50); if there are more, the response has a next_cursor. Send it back as cursor for the next page. Cursors are opaque and keep their place even while new rows arrive.

ParameterMeaning
kindOnly this kind. Placeholders are left out, since their kind is unknown
qPart of the id or of the name attribute, in any case
limit, cursorPaging, as above
Response · 200
{
  "entities": [
    {
      "id": "wal_8812",
      "kind": "wallet",
      "attributes": {
        "name": "Ama Mensah"
      },
      "registered": true,
      "open_alerts": 1,
      "last_seen": "2026-10-16T09:12:44Z",
      "created_at": "2026-10-01T08:00:00Z",
      "updated_at": "2026-10-15T11:20:00Z"
    }
  ],
  "next_cursor": "MTc5MjE2MjQ3NTkxMzAwMDAwMHx3YWxfODgxMg"
}

registered is false for a placeholder Sentinel made because an event named the entity before you registered it; a placeholder has no kind. open_alerts counts its alerts that are open or in_review, and last_seen is its latest event in or out.

Timeline

GET /v1/entities/{id}/events

The entity's events, money in and out, newest first, each with its decision. The response is the same as listing events, and it pages the same way. An id with no events returns an empty list.

Get an entity

GET /v1/entities/{id}

Returns the entity with the same fields as above, or 404 with entity not found. An entity Sentinel created as a placeholder, because an event named it before you registered it, comes back too; register it to set its real kind.

GET /v1/entities/{id}/links

Who the entity is connected to, built from events, most recently seen first, up to 50. An entity with no links returns an empty list.

Terminal
curl "$SENTINEL_URL/v1/entities/wal_8812/links"   -H "Authorization: Bearer $SENTINEL_KEY"
Response · 200
{
  "links": [
    {
      "entity_id": "wal_6603",
      "kind": "wallet",
      "relation": "shares_device",
      "via": "dev_a3f1e2d4",
      "first_seen": "2026-10-15T08:10:00Z",
      "last_seen": "2026-10-16T09:12:44Z",
      "open_alert": {
        "id": "c7d4e1a2-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
        "number": 20477,
        "priority": "high"
      }
    },
    {
      "entity_id": "dev_a3f1e2d4",
      "kind": "device",
      "relation": "uses_device",
      "first_seen": "2026-10-15T08:10:00Z",
      "last_seen": "2026-10-16T09:12:44Z"
    }
  ]
}
FieldTypeMeaning
entity_idstringThe linked entity
kindstringIts kind. Absent for placeholders you haven't registered
namestringIts name attribute, if it has one
relationstringpaid (this entity paid it), paid_by (it paid this entity), uses_device (a device this entity used), device_user (for a device: who used it) or shares_device (another entity used one of this entity's devices)
viastringFor shares_device, the device they share
first_seen, last_seenstring, date-timeWhen the connection was first and last seen, by the events' occurred_at
open_alertobjectThe linked entity's open alert, if it has one: id, number and priority
Sentinel is a Somu Labs product. © 2026 Somu Labs Ltd.