Granite Templates API
The vault's note templates (Markdown notes in its templates folder), and notes made from them.
The vault's note templates (Markdown notes in its templates folder), and notes made from them.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/granite-md:granite-md-templates-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Granite Templates API
version: 1.0.0
summary: REST API for Granite clients, bots, and integrations.
description: 'Conventions (apply to every operation; see PLAN.md 3.2 and 3.6):
- **Base URL** `https://api.granite.md`. All public operations live under `/v1`.
After Phase 6 ships, `/v1` changes are additive only.
- **Errors** use RFC 9457 problem details (`application/problem+json`, schema `Problem`).
The `type` URI is `https://granite.md/problems/`; `code` refines it for programmatic handling.
Every response carries `X-Request-ID`, also echoed as `request_id` in problems.
- **Pagination** is cursor based. List operations accept `cursor` and `limit` and return
`{ "items": [...], "next_cursor": "..." }`. `next_cursor` is absent on the last page.
Cursors are opaque; clients must not parse or build them.
- **Idempotency**: non-idempotent `POST` operations accept an `Idempotency-Key` header
(1-255 printable ASCII). Repeating a request with the same key and body within 24 hours
returns the original response; the same key with a different body returns `409` with
code `idempotency_key_reused`.
- **IDs** are UUIDv7 strings. **Timestamps** are RFC 3339 in UTC.
- **Authentication**: `Authorization: Bearer ` with a session access token,
a personal API token (`gr_pat_...`), or an OAuth access token. Scopes are listed per operation.
- **Rate limits**: each personal API token may make 600 requests a minute. Over the limit
the API answers `429` with code `token_rate_limited` and a `Retry-After` header (seconds).'
license:
name: Proprietary
identifier: LicenseRef-Proprietary
servers:
- url: https://api.granite.md
description: Production
- url: http://localhost:8080
description: Local development
security:
- bearerAuth: []
tags:
- name: Templates
description: 'The vault''s note templates (Markdown notes in its templates folder), and notes made
from them.'
paths:
/v1/vaults/{vault_id}/notes/from-template:
parameters:
- $ref: '#/components/parameters/VaultID'
post:
operationId: createNoteFromTemplate
tags:
- Templates
summary: Create a note from a template
description: 'Fills the template''s `{{title}}` (the new note''s title), `{{date}}` (YYYY-MM-DD), and
`{{time}}` (HH:mm) in `timezone`, as the apps do. Without `path`, the note is named after
the template in `folder` (the top level when left out), numbered when the name is taken.
An unknown template answers 404 `template_not_found`. Needs `vaults:write`, `sync`, or
`notes:create` (with `folders:create` too when the folder does not exist yet).'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NoteFromTemplate'
responses:
'201':
description: The note with its text.
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
$ref: '#/components/responses/Error'
/v1/vaults/{vault_id}/templates:
parameters:
- $ref: '#/components/parameters/VaultID'
get:
operationId: listTemplates
tags:
- Templates
summary: List templates
description: 'The Markdown notes in the vault''s templates folder (`templatesFolder` in
`.granite/settings.json`, `Templates` by default), without their text. Needs
`vaults:read` or any write scope.'
responses:
'200':
description: The templates folder and its templates.
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateList'
default:
$ref: '#/components/responses/Error'
post:
operationId: createTemplate
tags:
- Templates
summary: Add a template
description: 'Saves `content` as `name`.md in the templates folder. A taken name answers 409
`path_taken`. Needs `vaults:write`, `sync`, or `templates:edit`.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateCreate'
responses:
'201':
description: The template.
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
$ref: '#/components/responses/Error'
/v1/vaults/{vault_id}/templates/{file_id}:
parameters:
- $ref: '#/components/parameters/VaultID'
- $ref: '#/components/parameters/FileID'
put:
operationId: updateTemplate
tags:
- Templates
summary: Replace a template's text
description: 'As updating a note, for a file in the templates folder (others answer 404
`template_not_found`). Needs `vaults:write`, `sync`, or `templates:edit`.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NoteUpdate'
responses:
'200':
description: The template.
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
$ref: '#/components/responses/Error'
delete:
operationId: deleteTemplate
tags:
- Templates
summary: Delete a template
description: 'It stays in version history and can be restored. Needs `vaults:write`, `sync`, or
`templates:edit`.'
parameters:
- name: base_version_id
in: query
required: false
schema:
type: string
format: uuid
responses:
'204':
description: Deleted.
default:
$ref: '#/components/responses/Error'
components:
headers:
RequestID:
description: Identifier of this request, for support and log correlation.
schema:
type: string
schemas:
Note:
type: object
required:
- id
- path
- version_id
- size
- updated_at
properties:
id:
type: string
format: uuid
path:
type: string
version_id:
type: string
format: uuid
size:
type: integer
format: int64
updated_at:
type: string
format: date-time
content:
type: string
description: The note's text; omitted in lists and after a move.
NoteUpdate:
type: object
required:
- content
properties:
content:
type: string
base_version_id:
type: string
format: uuid
TemplateCreate:
type: object
required:
- name
- content
properties:
name:
type: string
minLength: 1
maxLength: 255
description: The template's name; ".md" is added.
content:
type: string
Problem:
type: object
description: RFC 9457 problem details.
required:
- type
- title
- status
properties:
type:
type: string
format: uri
examples:
- https://granite.md/problems/conflict
title:
type: string
status:
type: integer
format: int32
detail:
type: string
instance:
type: string
code:
type: string
description: Machine-readable refinement of `type`, for example `version_conflict`.
request_id:
type: string
errors:
type: array
description: Per-field validation errors.
items:
$ref: '#/components/schemas/FieldError'
NoteFromTemplate:
type: object
required:
- template
properties:
template:
type: string
minLength: 1
maxLength: 1024
description: The template's path, or its name in the templates folder ("Meeting").
path:
type: string
maxLength: 1024
description: The new note's path. Left out, the note is named after the template.
folder:
type: string
maxLength: 1024
description: Where the note goes when `path` is left out ("" or left out is the top level).
timezone:
type: string
maxLength: 64
description: An IANA time zone for `{{date}}` and `{{time}}` (UTC when left out).
TemplateList:
type: object
required:
- folder
- items
properties:
folder:
type: string
description: The vault's templates folder.
items:
type: array
items:
$ref: '#/components/schemas/Note'
FieldError:
type: object
required:
- field
- detail
properties:
field:
type: string
description: JSON path of the invalid field, for example `ops[2].path`.
detail:
type: string
parameters:
VaultID:
name: vault_id
in: path
required: true
schema:
type: string
format: uuid
FileID:
name: file_id
in: path
required: true
schema:
type: string
format: uuid
responses:
Error:
description: Error response.
headers:
X-Request-ID:
$ref: '#/components/headers/RequestID'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: Session access token, personal API token, or OAuth access token.