REST API

Neatbase provides a REST API that lets you read, write, and manage notes and fields in your notebooks programmatically. Use it to build integrations, automate workflows, sync with external services, or power dashboards from your Neatbase data.

The API uses a simple JSON format with field names as keys — no internal IDs to deal with. Changes made via the API sync to the Neatbase app automatically, and changes made in the app are available via the API.

Getting Started

Prerequisites

  • A Neatbase Pro subscription

Enable API Access

  1. Open your notebook in Neatbase
  2. Tap the three-dot menu (⋯) in the toolbar
  3. Select API...
  4. Tap Enable API

Neatbase will generate an API key and a documentation URL for your notebook.

  • API Key — A 64-character token used to authenticate all API requests. Keep it secret.
  • Docs URL — A personalized documentation page showing your notebook's actual field names, types, and curl examples.

Note: Enabling API access on a shared notebook works whether the share is encrypted or not. If the notebook uses end-to-end encryption, the encryption key is securely transmitted to the server so it can read and write data on behalf of the API. Disabling API access removes the key from the server, restoring full end-to-end encryption.

Disable API Access

To revoke API access, open the API... sheet from the three-dot menu and tap Disable API. The API key is immediately invalidated — all subsequent requests will fail with a 401 error.


Authentication

All API requests require a Bearer token in the Authorization header:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/notes

Replace YOUR_API_KEY with the key shown in your notebook's API panel.

Scenario Response
Missing or invalid API key 401 Unauthorized
API was disabled by the notebook owner 410 Gone

Base URL

All endpoints are relative to:

https://cloud.neatbase.app/api/v1

Endpoints

Get Schema

Retrieve your notebook's field definitions — useful for understanding the structure before reading or writing notes.

GET /v1/schema

Example:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/schema

Response:

{
  "notebook_name": "Contacts",
  "fields": [
    {
      "id": "550E8400-E29B-41D4-A716-446655440000",
      "name": "Name",
      "type": "shortText",
      "order": 0
    },
    {
      "id": "6BA7B810-9DAD-11D1-80B4-00C04FD430C8",
      "name": "Email",
      "type": "email",
      "order": 1
    },
    {
      "id": "7C9E6679-7425-40DE-944B-E07FC1F90AE7",
      "name": "Amount",
      "type": "currency",
      "order": 2,
      "config": {
        "currencyCode": "USD"
      }
    },
    {
      "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "name": "Priority",
      "type": "tags",
      "order": 3,
      "config": {
        "availableTags": "Low,Medium,High"
      }
    },
    {
      "id": "B2C3D4E5-F6A7-8901-BCDE-F12345678901",
      "name": "Total",
      "type": "formula",
      "order": 4,
      "config": {
        "formula": "{Amount} * {Quantity}"
      },
      "read_only": true
    }
  ]
}

Fields marked read_only: true (formula, image) can be read but not written via the API.


List Fields

Retrieve all field definitions for the notebook.

GET /v1/fields

Example:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/fields

Response:

{
  "fields": [
    {
      "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "name": "Name",
      "type": "shortText",
      "order": 0
    },
    {
      "id": "B2C3D4E5-F6A7-8901-BCDE-F12345678901",
      "name": "Amount",
      "type": "currency",
      "order": 1,
      "config": {
        "currencyCode": "USD"
      }
    }
  ]
}

Get Field

Retrieve a single field definition by ID.

GET /v1/fields/{id}

Example:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/fields/A1B2C3D4-E5F6-7890-ABCD-EF1234567890

Returns 404 if the field doesn't exist.


List Notes

Retrieve notes with pagination, sorting, and filtering.

GET /v1/notes

Query Parameters:

Parameter Type Default Description
page integer 1 Page number (minimum 1)
per_page integer 100 Items per page (1–100)
sort string created_at Sort by created_at, updated_at, or a field name
order string desc Sort direction: asc or desc
filter string Filter in the format FieldName:operator:value
filter[] string[] Multiple filters (ANDed together)

Basic Example:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?page=1&per_page=50"

Response:

{
  "notes": [
    {
      "id": "550E8400-E29B-41D4-A716-446655440000",
      "fields": {
        "Name": "Jane Doe",
        "Email": "jane@example.com",
        "Amount": 42.50,
        "Priority": ["High"],
        "Total": null
      },
      "created_at": "2026-04-05 12:00:00",
      "updated_at": "2026-04-05 14:30:00"
    }
  ],
  "total": 42,
  "page": 1,
  "per_page": 50,
  "total_pages": 1
}

The updated_at field reflects when the note was last edited (not the sync timestamp). Deleted notes are excluded.

Sorting

Sort by any field name, created_at, or updated_at:

# Oldest notes first
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?sort=created_at&order=asc"

# Sort by a field value
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?sort=Amount&order=desc"

Notes with null values for the sort field appear last regardless of sort direction.

Filtering

Filter notes by field values using the filter parameter. The format is FieldName:operator:value.

# Single filter
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter=Name:contains:Jane"

# Multiple filters (ANDed)
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter[]=Amount:gte:100&filter[]=Priority:contains:High"

# Combined with sorting
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter=Amount:gt:0&sort=Amount&order=desc"

Filter Operators:

Operator Applies To Needs Value Description
eq text, number, date, toggle Yes Equals (case-insensitive for text)
neq text, number, date Yes Not equals
contains text, tags Yes Substring match (text) or has tag (tags)
gt number, date Yes Greater than
lt number, date Yes Less than
gte number, date Yes Greater than or equal
lte number, date Yes Less than or equal
is_empty all No Field is null or empty
is_not_empty all No Field has a value

Type compatibility: "text" = shortText, longText, email, phone, url, reference, barcode, qrCode, color. "number" = number, currency, rating, duration, percent. "date" = date. "toggle" = toggle. "tags" = tags.

Toggle filtering: Use eq:true or eq:false (the value is a string in the URL).

Tags filtering: contains checks if the tag array includes the specified tag (case-insensitive). For example, Priority:contains:High matches notes where the Priority tags include "High".

Invalid filter params return a 400 error with a helpful message explaining what went wrong.


Get Note

Retrieve a single note by its ID.

GET /v1/notes/{id}

Example:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/notes/550E8400-E29B-41D4-A716-446655440000

Response:

{
  "id": "550E8400-E29B-41D4-A716-446655440000",
  "fields": {
    "Name": "Jane Doe",
    "Email": "jane@example.com",
    "Amount": 42.50,
    "Priority": ["High"]
  },
  "created_at": "2026-04-05 12:00:00",
  "updated_at": "2026-04-05 14:30:00"
}

Returns 404 if the note doesn't exist or has been deleted.


Create Note

Create a new note with field values.

POST /v1/notes

Request Body:

{
  "fields": {
    "Name": "John Smith",
    "Email": "john@example.com",
    "Amount": 99.00,
    "Priority": ["Medium", "High"]
  }
}

Example:

curl -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"Name": "John Smith", "Email": "john@example.com", "Amount": 99.00}}' \
  https://cloud.neatbase.app/api/v1/notes

Response (201 Created):

{
  "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
  "fields": {
    "Name": "John Smith",
    "Email": "john@example.com",
    "Amount": 99.00,
    "Priority": ["Medium", "High"]
  },
  "created_at": "2026-04-05 15:30:00",
  "updated_at": "2026-04-05 15:30:00"
}

Behavior:

  • All fields are optional. Omitted fields are stored as null.
  • Unknown field names return 400 Bad Request.
  • Read-only fields (formula, image) are silently ignored.
  • The note ID is generated server-side.
  • All field values are validated before writing. If any validation fails, nothing is saved.

Update Note

Update specific fields on an existing note. This is a partial update — only the fields you include are changed; all other fields are preserved.

PUT /v1/notes/{id}

Request Body:

{
  "fields": {
    "Amount": 149.00,
    "Priority": ["High"]
  }
}

Example:

curl -X PUT \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"Amount": 149.00}}' \
  https://cloud.neatbase.app/api/v1/notes/550E8400-E29B-41D4-A716-446655440000

Response (200 OK):

The complete updated note is returned (same format as Get Note).

Returns 404 if the note doesn't exist.


Delete Note

Soft-delete a note. The note is marked as deleted and will no longer appear in list or get endpoints.

DELETE /v1/notes/{id}

Example:

curl -X DELETE \
  -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/notes/550E8400-E29B-41D4-A716-446655440000

Response (200 OK):

{
  "id": "550E8400-E29B-41D4-A716-446655440000",
  "deleted": true
}

Returns 404 if the note doesn't exist or has already been deleted.


Field Management

Manage your notebook's field schema programmatically — add, rename, reorder, or remove fields without opening the app.

Important: A field's type cannot be changed after creation. To change the type, delete the field and create a new one.

Create Field

POST /v1/fields

Request Body:

{
  "name": "Amount",
  "type": "currency",
  "order": 3,
  "config": {
    "currencyCode": "USD"
  }
}
Parameter Required Description
name Yes Field name (must be unique within the notebook)
type Yes One of the valid field types (see table below)
order No Position in the field list (defaults to end)
config Depends Required for types that need configuration

Types that require config:

Type Config Key Example
currency currencyCode {"currencyCode": "USD"}
tags availableTags {"availableTags": "Low,Medium,High"}
formula formula {"formula": "{Price} * {Qty}"}
reference notebookId {"notebookId": "NOTEBOOK-UUID"} (optional)

Example:

curl -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Amount", "type": "currency", "config": {"currencyCode": "USD"}}' \
  https://cloud.neatbase.app/api/v1/fields

Response (201 Created):

{
  "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
  "name": "Amount",
  "type": "currency",
  "order": 3,
  "config": {
    "currencyCode": "USD"
  }
}

Valid types for creation: shortText, longText, email, phone, url, number, currency, rating, formula, date, toggle, tags, reference, checklist, image, duration, percent, color, barcode, qrCode

Layout types (sectionDivider, sectionDescription) and secretText cannot be created via the API.


Update Field

Update a field's name, order, or config. This is a partial update — only the properties you include are changed.

PUT /v1/fields/{id}

Request Body (all optional, at least one required):

{
  "name": "New Name",
  "order": 5,
  "config": {
    "currencyCode": "EUR"
  }
}

Example:

curl -X PUT \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Price", "order": 2}' \
  https://cloud.neatbase.app/api/v1/fields/FIELD-UUID

Response (200 OK):

The complete updated field is returned (same format as Create Field).

Notes:

  • Including type in the request body returns 400 Bad Request — type is immutable.
  • Field names must be unique across all fields in the notebook.
  • Returns 404 if the field doesn't exist.

Delete Field

Soft-delete a field and all its values across every note in the notebook.

DELETE /v1/fields/{id}

Example:

curl -X DELETE \
  -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/fields/FIELD-UUID

Response (200 OK):

{
  "id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
  "deleted": true
}

Returns 404 if the field doesn't exist or has already been deleted.

Warning: Deleting a field permanently removes all data stored in that field across all notes. This cannot be undone via the API.


Field Types

The API uses the same field types as the Neatbase app. Each type has a specific JSON representation:

Type JSON Type Read Write Notes
shortText string Yes Yes Single-line text
longText string Yes Yes Multi-line text
email string Yes Yes Email address
phone string Yes Yes Phone number
url string Yes Yes Web URL
number number Yes Yes Numeric value
currency number Yes Yes Monetary amount (see schema for currency code)
rating integer Yes Yes Integer from 1 to 5
date string Yes Yes Format: YYYY-MM-DD
toggle boolean Yes Yes true or false
tags array Yes Yes Array of strings, e.g. ["Tag1", "Tag2"]
checklist array Yes Yes Array of objects: [{"text": "...", "checked": true}]
reference string Yes Yes UUID of a note in another notebook
duration number Yes Yes Total seconds (e.g., 5400 = 1h 30m)
percent number Yes Yes Number from 0 to 100
color string Yes Yes Hex color (e.g., #FF5733)
barcode string Yes Yes Barcode string
qrCode string Yes Yes QR code string
image string Yes No Returns an image URL (read-only)
formula null Yes No Always null — computed on device (read-only)
secretText No No Excluded from API entirely
sectionDivider No No Layout element, excluded from API
sectionDescription No No Layout element, excluded from API

Validation Rules

When creating or updating notes, field values are validated based on their type. Invalid values return a 400 Bad Request error.

Text Fields

Types: shortText, longText, email, phone, url, reference, barcode, qrCode, color

"Name": "Jane Doe"
"Name": null

Must be a string or null. Any other type (number, boolean, array) is rejected.

Number Fields

Types: number, currency, duration, percent

"Amount": 42.50
"Amount": -10
"Amount": null

Must be a numeric value (integer or float) or null.

Rating

"Stars": 4
"Stars": null

Must be an integer from 1 to 5, or null. Floats like 3.5 are rejected — use whole numbers only.

Date

"Due Date": "2026-04-05"
"Due Date": null

Must be a string in YYYY-MM-DD format, or null. The format is strictly validated.

Toggle

"Active": true
"Active": false
"Active": null

Must be a JSON boolean (true or false) or null. String values like "true" are rejected.

Tags

"Categories": ["Design", "Marketing"]
"Categories": []
"Categories": null

Must be an array of strings, an empty array, or null. Each element must be a string. Objects and non-string elements are rejected.

Checklist

"Tasks": [
  {"text": "Design mockup", "checked": true},
  {"text": "Review copy", "checked": false}
]
"Tasks": null

Must be an array of checklist items or null. Each item should have text (string) and checked (boolean) keys.

Duration

"Prep Time": 5400
"Prep Time": null

Must be a numeric value representing total seconds, or null. For example, 5400 = 1 hour 30 minutes.

Percent

"Progress": 75
"Progress": null

Must be a numeric value from 0 to 100, or null.

Color

"Brand Color": "#FF5733"
"Brand Color": null

Must be a hex color string (e.g., #FF5733), or null.

Barcode / QR Code

"Barcode": "012345678905"
"QR Code": "https://example.com"

Must be a string or null. Any text value is accepted.


Pagination

List endpoints return paginated results:

GET /v1/notes?page=2&per_page=25
Parameter Default Range Description
page 1 1+ Page number
per_page 100 1–100 Results per page

Response metadata:

{
  "notes": [...],
  "total": 150,
  "page": 2,
  "per_page": 25,
  "total_pages": 6
}

Rate Limits

API requests are rate-limited per API key:

Operation Limit
Read (GET requests) 600 per hour
Write (POST, PUT, DELETE) 120 per hour

When a limit is exceeded, the API returns:

{
  "error": "Rate limit exceeded. Try again later.",
  "code": "rate_limit"
}

HTTP Status: 429 Too Many Requests

Rate limits reset on an hourly window.


Error Handling

All errors follow a consistent format:

{
  "error": "Human-readable error message",
  "code": "machine_readable_code"
}

Error Reference

HTTP Status Code Description
400 invalid_request Malformed request body or missing fields object
400 invalid_request Field validation failed (message includes field name and reason)
400 invalid_field Unknown field name (not in the notebook's schema)
401 unauthorized Missing or invalid API key
404 not_found Note or resource not found
410 gone API access has been disabled for this notebook
429 rate_limit Rate limit exceeded
500 server_error Internal error (e.g., database transaction failed)

Images

Image fields are read-only in the API. When a note has an image field with data, the API returns a URL:

{
  "fields": {
    "Photo": "https://cloud.neatbase.app/api/v1/images/share_abc123_def456.jpg"
  }
}

To download the image, make a GET request to the URL with your API key:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/images/share_abc123_def456.jpg" \
  -o photo.jpg

Images that haven't been set return null.

Image fields cannot be written via the API. Use the Neatbase app to add or update images.


Sync Behavior

The Neatbase app syncs with the server automatically while it's open. This means:

  • API → App: Notes and fields created or modified via the API will appear in the app shortly.
  • App → API: Notes and fields created or modified in the app will be available via the API after the next sync cycle.
  • Deletions: Soft-deleted notes and fields (via API or app) are removed from both sides after sync.

The sync is bidirectional and automatic — no additional setup required.


Examples

List All Notes

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/notes

Sort and Filter Notes

# Get high-value notes, sorted by amount
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter=Amount:gte:1000&sort=Amount&order=desc"

# Find notes with a specific tag
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter=Priority:contains:High"

# Notes with upcoming due dates, sorted by most recently edited
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?filter=Due%20Date:gte:2026-03-29&sort=updated_at&order=desc"

Create a Note

curl -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "Name": "Acme Corp",
      "Email": "hello@acme.com",
      "Amount": 5000,
      "Priority": ["High"],
      "Active": true
    }
  }' \
  https://cloud.neatbase.app/api/v1/notes

Update Specific Fields

Only include the fields you want to change:

curl -X PUT \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"Amount": 7500, "Priority": ["High", "Urgent"]}}' \
  https://cloud.neatbase.app/api/v1/notes/YOUR_NOTE_ID

Delete a Note

curl -X DELETE \
  -H "Authorization: Bearer YOUR_API_KEY" \
  https://cloud.neatbase.app/api/v1/notes/YOUR_NOTE_ID

Paginate Through All Notes

# Page 1
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?page=1&per_page=50"

# Page 2
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://cloud.neatbase.app/api/v1/notes?page=2&per_page=50"

Python Example

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://cloud.neatbase.app/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# List notes
response = requests.get(f"{BASE_URL}/notes", headers=HEADERS)
notes = response.json()["notes"]

for note in notes:
    print(note["fields"]["Name"], "-", note["fields"].get("Email"))

# Create a note
new_note = requests.post(
    f"{BASE_URL}/notes",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={"fields": {"Name": "New Contact", "Email": "new@example.com"}}
)
print("Created:", new_note.json()["id"])

JavaScript Example

const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://cloud.neatbase.app/api/v1";

// List notes
const response = await fetch(`${BASE_URL}/notes`, {
  headers: { "Authorization": `Bearer ${API_KEY}` }
});
const { notes } = await response.json();

// Create a note
const created = await fetch(`${BASE_URL}/notes`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    fields: { "Name": "New Contact", "Email": "new@example.com" }
  })
});
console.log("Created:", (await created.json()).id);
esc
Type to search across all documentation pages.