Files
synq/docs/api.md
2026-05-17 15:59:43 -04:00

2.8 KiB

api contract

base url example:

http://jeeves.mother:8765

all write endpoints require:

authorization: bearer <phone_capture_token>
content-type: application/json

get /health

request:

GET /health

response:

{
  "ok": true,
  "service": "synq",
  "version": "0.1.0"
}

post /capture

request:

POST /capture
Authorization: Bearer <token>
Content-Type: application/json

body:

{
  "id": "phone-20260517-143122-a8f2",
  "created_at": "2026-05-17T14:31:22-04:00",
  "kind": "todo",
  "body": "buy printer paper",
  "tags": ["home", "errands"],
  "device": "android"
}

field rules:

  • id: required, stable, unique per capture.
  • created_at: required iso-8601 datetime with timezone.
  • kind: required, either note or todo.
  • body: required, trimmed, non-empty.
  • tags: required array, may be empty.
  • device: required string, e.g. android.

success, newly accepted:

{
  "ok": true,
  "status": "accepted",
  "id": "phone-20260517-143122-a8f2"
}

success, duplicate/idempotent retry:

{
  "ok": true,
  "status": "already_seen",
  "id": "phone-20260517-143122-a8f2"
}

invalid token:

{
  "detail": "unauthorized"
}

invalid payload:

{
  "detail": "body must not be empty"
}

org formatting rules

todo capture:

* TODO buy printer paper :home:errands:
:PROPERTIES:
:CREATED: [2026-05-17 sun 14:31]
:SOURCE: android
:ID: phone-20260517-143122-a8f2
:END:

note capture:

* note :retcon:
:PROPERTIES:
:CREATED: [2026-05-17 sun 14:33]
:SOURCE: android
:ID: phone-20260517-143322-b91c
:END:

mobile capture should stay dumb and append-only.

multiline note capture:

input body:

retcon capture idea

phone should produce records, not edit org files.

output:

* note: retcon capture idea :retcon:
:PROPERTIES:
:CREATED: [2026-05-17 sun 14:33]
:SOURCE: android
:ID: phone-20260517-143322-b91c
:END:

retcon capture idea

phone should produce records, not edit org files.

suggested behavior: use first line as heading suffix for notes when helpful, but preserve full body below the drawer.

idempotency

server must never append the same id twice.

recommended implementation:

  1. begin sqlite transaction.
  2. check whether id already exists.
  3. if exists, return already_seen.
  4. append org entry.
  5. insert id into sqlite.
  6. commit.

if append succeeds but sqlite insert fails, log loudly. safest implementation may insert first inside a transaction and mark appended after write, but keep the code simple and test the duplicate path.

status codes

  • 200: accepted or already seen.
  • 400: malformed request or invalid capture.
  • 401: missing/invalid token.
  • 500: server failed to append or persist state.

android should treat accepted and already_seen as synced.