---
title: Developer REST API
description: Read and transactionally mutate an explicitly mapped Basalt Hosted vault.
slug: rest-api
path: /rest-api
section: APIs
availability: supported
nav_order: 5
canonical_url: https://developers.basaltnotes.com/rest-api
markdown_url: https://developers.basaltnotes.com/rest-api.md
mirror_url: https://basaltnotes.com/developers/rest-api
---
# Developer REST API

The Developer REST API is mounted at:

```text
/api/dev
```

It is intended for scripts and backends operating on an explicitly connected **Basalt Hosted** vault. It does not expose arbitrary browser-local vaults.

Actual API use requires the Developer entitlement boundary and an authenticated personal access token.

## Authentication

```http
Authorization: Bearer bda_…
```

Vault operations also require an explicit hosted `mappingId`. Depending on the endpoint you can send it as request data/query or:

```http
X-Basalt-Mapping: <mapping-uuid>
```

## List notes

```http
GET /api/dev/notes?mappingId=<uuid>
```

Returns a bounded inventory of hosted Markdown notes with path, title, revision, size, and update time. The current inventory limit is 1,000 notes per request.

Send `Accept: text/markdown` to supported read endpoints when you want a Markdown representation instead of JSON.

## Read one note

Current route shape:

```http
GET /api/dev/notes/:category/:filename?mappingId=<uuid>
```

The response includes the note content and its current revision. Basalt also emits the revision as an `ETag`.

Do not assume the current two-segment read route is a generic wildcard path. Use the route contract actually exposed by your deployment.

## Preview or write a note

```http
POST /api/dev/notes
Content-Type: application/json
Idempotency-Key: example-write-42
```

```json
{
  "mappingId": "<uuid>",
  "path": "Projects/Launch.md",
  "content": "# Launch\n",
  "dryRun": true
}
```

`dryRun` defaults to `true`. To apply the write, explicitly send `dryRun: false` and an idempotency key.

When replacing an existing note, provide the current expected revision/hash through `expectedHash` or the supported conditional header. Basalt should reject a stale update rather than silently overwrite a newer revision.

## Delete a note

```http
DELETE /api/dev/notes/:category/:filename?mappingId=<uuid>&dryRun=true
If-Match: <current-revision>
Idempotency-Key: example-delete-42
```

Deletes use the hosted knowledge transaction boundary and create recoverable hosted trash state before the live note is removed.

## Multi-note transactions

```http
POST /api/dev/transactions
Content-Type: application/json
Idempotency-Key: project-update-2026-08-16
```

```json
{
  "mappingId": "<uuid>",
  "dryRun": true,
  "actions": [
    {
      "type": "write-note",
      "path": "Projects/Launch.md",
      "content": "# Launch\nUpdated plan",
      "expectedHash": "<current-revision>"
    },
    {
      "type": "write-note",
      "path": "Projects/Launch Risks.md",
      "content": "# Risks\n"
    }
  ]
}
```

Applied actions commit through one hosted database transaction. Use the preview result to verify the intended mutation set before applying it.

## Provenance events

```http
GET /api/dev/events?mappingId=<uuid>&since=<cursor>&limit=<n>
```

The event feed is scoped to the authenticated user and explicit hosted mapping.

## Error handling

Treat HTTP status plus stable response `code` values as the programmatic signal where provided. Do not branch automation on human-readable message text.

Common failure classes include:

- authentication/entitlement failure;
- invalid or inaccessible `mappingId`;
- invalid note path;
- stale expected revision;
- missing idempotency for an applied write;
- quota/rate boundary;
- hosted note not found.

## Local-first limitation

If the user has not connected the logical vault to Basalt Hosted, this API cannot read it. Ask the user to configure an appropriate hosted mapping; do not create a shadow upload path in your integration.
