The Mesh API runs at http://localhost:8080. All endpoints use JSON.

[!NOTE] Phase 2 Status: All ingestion endpoints now trigger an automated background processing pipeline. This includes content scraping, AI-driven tag extraction (or rule-based fallback), vector embedding generation, and automated relationship discovery. No new API endpoints were added in Phase 2; focus was entirely on intelligence and background orchestration.


Health Check

GET /healthz

Returns the health status of the API and its database connection.

Request:

curl http://localhost:8080/healthz

Response (200 OK):

{
  "status": "ok"
}

Response (503 Service Unavailable):

{
  "status": "unhealthy",
  "error": "database unreachable"
}

Save a Page (with content)

POST /api/v1/ingest/raw

Saves a web page to the knowledge base with its content included in the request. If a page with the same URL already exists, it is updated instead.

Request:

curl -X POST http://localhost:8080/api/v1/ingest/raw \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article",
    "title": "Example Article",
    "content": "The full text content of the page...",
    "type": "article"
  }'

Response (new page – 201 Created):

{
  "id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
  "title": "Example Article",
  "created_at": "2026-04-02T12:43:09Z"
}

Response (existing URL updated – 200 OK):

{
  "id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
  "title": "Example Article",
  "created_at": "2026-04-02T12:43:09Z",
  "updated": true
}
Field Required Description
url Yes The page URL (must be http or https)
title Yes The page title
content No The extracted text content (max 500 KB, HTML-sanitized)
type No Node type (default: article). See Node Types

Save a URL (async scraping)

POST /api/v1/ingest/url

Queues a URL for background scraping and processing. The page content is fetched asynchronously by a worker.

Request:

curl -X POST http://localhost:8080/api/v1/ingest/url \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article",
    "type": "article"
  }'

Response (202 Accepted):

{
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "node_id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
  "status": "pending"
}
Field Required Description
url Yes The page URL to scrape (must be http or https)
type No Node type (default: article). See Node Types

The worker will scrape the page in the background and update the node with the extracted content.


Save Text (no URL)

POST /api/v1/ingest/text

Saves a text note or thought that doesn’t have a URL. The content is queued for background processing.

Request:

curl -X POST http://localhost:8080/api/v1/ingest/text \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My thought on distributed systems",
    "content": "Consistency and availability are fundamentally at odds...",
    "type": "thought"
  }'

Response (201 Created):

{
  "node_id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "pending"
}
Field Required Description
title Yes The note title
content Yes The text content (HTML-sanitized)
type No Node type (default: thought). See Node Types

List Recent Saves

GET /api/v1/nodes/recent

Returns the 20 most recently saved pages.

Request:

curl http://localhost:8080/api/v1/nodes/recent

Response (200 OK):

[
  {
    "id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
    "type": "article",
    "title": "Example Article",
    "source_url": "https://example.com/article",
    "status": "active",
    "created_at": "2026-04-02T12:43:09Z"
  }
]

List All Pages (Paginated)

GET /api/v1/nodes

Returns pages with cursor-based pagination.

Parameters:

Parameter Default Description
per_page 20 Number of results per page (1–100)
cursor (none) Cursor string from next_cursor of previous response

Request (first page):

curl "http://localhost:8080/api/v1/nodes?per_page=10"

Response (200 OK):

{
  "nodes": [
    {
      "id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
      "type": "article",
      "title": "Example Article",
      "source_url": "https://example.com/article",
      "status": "active",
      "created_at": "2026-04-02T12:43:09Z"
    }
  ],
  "next_cursor": "eyJ0IjoiMjAyNi0wNC0wMlQxMjo0MzowOVoiLCJpIjoiNmFiZWZhYjYifQ==",
  "has_more": true
}

Request (next page):

curl "http://localhost:8080/api/v1/nodes?per_page=10&cursor=eyJ0IjoiMjAyNi0wNC0wMlQxMjo0MzowOVoiLCJpIjoiNmFiZWZhYjYifQ=="

When has_more is false, there are no more pages to load.


Get a Page

GET /api/v1/nodes/{id}

Retrieves a single saved page by its ID.

Request:

curl http://localhost:8080/api/v1/nodes/6abefab6-e713-4ae7-8fbb-c0704ab33640

Response (200 OK):

{
  "id": "6abefab6-e713-4ae7-8fbb-c0704ab33640",
  "type": "article",
  "title": "Example Article",
  "source_url": "https://example.com/article",
  "status": "active",
  "created_at": "2026-04-02T12:43:09Z"
}

Response (404 Not Found):

{
  "error": "node not found"
}

Delete a Page

DELETE /api/v1/nodes/{id}

Permanently deletes a saved page.

Request:

curl -X DELETE http://localhost:8080/api/v1/nodes/6abefab6-e713-4ae7-8fbb-c0704ab33640

Response: 204 No Content (empty body on success)

Response (404 Not Found):

{
  "error": "node not found"
}

Node Types

All ingest endpoints accept an optional type field. Valid values:

Type Description
article Web article or blog post (default for /ingest/raw and /ingest/url)
book Book or long-form content
hobby Hobby-related content
thought Personal thought or note (default for /ingest/text)
journal Journal entry
image Image content
wildcard Uncategorized or discovery content

Error Responses

All errors return a JSON object with an error field:

{
  "error": "url is required"
}
Status Code Meaning
400 Bad request (missing fields, invalid format)
404 Resource not found
500 Internal server error

This site uses Just the Docs, a documentation theme for Jekyll.