freshjots — Python
Tiny Python client for the Fresh Jots API. One
file, no runtime dependencies for the core client (uses urllib from
stdlib). Client-side encryption is an optional extra.
Install
pip install freshjots
Use
from freshjots import Client
# Reads FRESHJOTS_TOKEN from the environment by default.
client = Client()
# Append text to a note (creates it if missing).
client.append("cron-jobs-prod", "backup ok")
# Read a note's body (by filename or numeric id).
print(client.note("cron-jobs-prod")["plain_body"])
print(client.note_by_id(42)["plain_body"])
# List notes — filter and paginate, or walk every page.
for note in client.notes(sort="created", folder_id=3, limit=20):
print(f"{note['filename']}\t{note['title']}")
everything = client.notes(all_pages=True)
# Create by title (server derives the filename); or create many at once.
created = client.create(title="Research 2026 Q2", body="Initial outline.")
print(created["filename"]) # server-derived stream name
client.bulk([
{"title": "Q2 plan", "plain_body": "…", "format": "plain"},
{"title": "Q2 risks", "plain_body": "…", "format": "plain"},
])
# Edit a note by id or by filename (only the fields you pass change).
client.update(42, title="Renamed", body="rewritten")
client.set("cron-jobs-prod", alert_email="ops@example.com")
# Organize: move (by id or folder name), delete, manage folders.
client.move("cron-jobs-prod", folder="Ops") # or folder=None for the root
client.delete("old-note")
client.create_folder("Archive")
for f in client.folders():
print(f"{f['id']}\t{f['name']}")
The method surface mirrors the bash CLI:
- Reading:
notes(sort=, folder_id=, limit=, offset=, all_pages=),note(filename),note_by_id(id) - Writing:
create(title, body=, client_encrypted=),append(filename, text, client_encrypted=),update(id, **fields),set(filename, **fields),bulk(notes) - Organizing:
move(id_or_filename, folder=),delete(id_or_filename),folders(),folder(id),create_folder(name),rename_folder(id, name),delete_folder(id)
note/note_by_id/create/update/set return the note dict directly (no {"note": …} wrapper); notes() and folders() return lists. update/set accept any of title, body, folder, root=True, deadline, alert_email, webhook_url, webhook_secret — and because a content change rewrites the body as a unit, a title change must also pass body. move/delete accept a numeric id or a filename; move's folder may be an id, a folder name, or None/"none"/"root" for the root.
Encryption
Keep notes the server can't read: encrypt locally with your own passphrase, store the ciphertext, decrypt locally on read. AES isn't in the standard library, so this needs the optional extra:
pip install freshjots[encryption]
import os
from freshjots import Client, encrypt, decrypt
client = Client()
pw = os.environ["FRESHJOTS_PASSPHRASE"]
# Store an encrypted note: encrypt the body, flag it client_encrypted.
client.create(title="Recovery codes", body=encrypt("1234-5678", pw), client_encrypted=True)
# Read it back and decrypt locally.
print(decrypt(client.note("recovery-codes")["plain_body"], pw))
The format (fj1: AES-256-CBC + HMAC-SHA256, PBKDF2-HMAC-SHA256) is
interoperable with the JS, Ruby, MCP, and shell (brew) clients. You hold the only key — Fresh Jots never receives it and
cannot recover the note if you lose it, so back the passphrase up somewhere
safe. Encryption is per-note and personal-only (not team notes); the title and
metadata stay in the clear, so keep secrets out of the title. decrypt raises
ValueError on a wrong passphrase. See https://freshjots.com/encrypted-notes.
Errors
Any non-2xx response raises freshjots.ApiError with status, code,
message, and (when present) details:
from freshjots import ApiError
try:
client.append("huge", "x" * 5_000_000)
except ApiError as e:
print(f"{e.status} {e.code}: {e}")
# 413 content_too_large: body exceeds the per-note 3 MB cap
Stable error codes: unauthenticated, forbidden, not_found,
validation_failed, cap_exceeded, storage_cap_exceeded,
content_too_large, content_type_mismatch, rate_limited. Full list:
https://freshjots.com/docs.
Auth
Mint a token at https://freshjots.com/settings/api_tokens (Dev or
Team tier required). Set it once, persisted for every new shell
(macOS defaults to zsh; use ~/.bashrc on bash):
echo 'export FRESHJOTS_TOKEN=<your-token>' >> ~/.zshrc && source ~/.zshrc
Or pass explicitly:
Client(token="mn_…")
License
MIT.
Metadata
Release files for freshjots 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| freshjots-2.0.0.tar.gz | 20.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| freshjots-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.7 kB
Release files / freshjots-2.0.0.tar.gz
| Download URL | freshjots-2.0.0.tar.gz |
|---|---|
| Size | 20.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e126a8c750444064bcc36579f758cce7f4d6f639dd66935933c74a406a859691
|
|
BLAKE2b-256 checksum How to use checksums |
2ab0fa965fec107b043167262d86ee54ea94dc7e518c06143172d2409e22a7fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / freshjots-2.0.0-py3-none-any.whl
| Download URL | freshjots-2.0.0-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e302459cbd36eaf7c4b3f794e5b9569ac5d771ddb2c9692f4fdb922b4fd922f
|
|
BLAKE2b-256 checksum How to use checksums |
7233f45b51cd9ffc84db5c3d774023ba510ad371a4ebf060b52e9f62efacf066
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for freshjots 2.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.