Skip to content

Commit 961090b

Browse files
committed
docs: update integration API documentation for read-note endpoint
Add read-note endpoint to README API table, update endpoint count, and revise security tradeoff text to cover both create and read operations.
1 parent aff9ee8 commit 961090b

3 files changed

Lines changed: 86 additions & 20 deletions

File tree

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ worker/
309309

310310
## 📡 API
311311

312-
Six endpoints. That's the entire backend.
312+
Eight endpoints. That's the entire backend.
313313

314314
| Method | Endpoint | Description |
315315
| -------- | ----------------- | -------------------------------- |
@@ -324,15 +324,16 @@ Rate limited per IP. Max request body: 1 KB. Full API docs at [notefade.com/docs
324324

325325
### ⚠️ Third-Party Integration API
326326

327-
> **Security tradeoff:** This endpoint does NOT follow the zero-knowledge model. The server briefly sees plaintext (~1-2ms in volatile Worker memory) before encrypting. Never stored, never logged — but the server processes content, which the main application never does. Use the main app for sensitive secrets.
327+
> **Security tradeoff:** These endpoints do NOT follow the zero-knowledge model. The server briefly sees plaintext (~1-2ms in volatile Worker memory) during encryption or decryption. Never stored, never logged — but the server processes content, which the main application never does. The read endpoint additionally requires the full note URL (including the `#` fragment) to be sent to the server. Use the main app for sensitive secrets.
328328
329-
| Method | Endpoint | Description |
330-
| ------ | --------------------- | -------------------------------------- |
331-
| `POST` | `/api/v1/create-note` | Create a note (server-side encryption) |
329+
| Method | Endpoint | Description |
330+
| ------ | --------------------- | --------------------------------------- |
331+
| `POST` | `/api/v1/create-note` | Create a note (server-side encryption) |
332+
| `POST` | `/api/v1/read-note` | Read a note (server-side decryption) |
332333

333-
Requires an `X-Api-Key` header. Rate limited per key (60 req/min, KV-based). Max body: 4 KB. Fixed 24-hour TTL.
334+
Requires an `X-Api-Key` header. Rate limited per key (60 req/min, KV-based). Max body: 4 KB (create) / 16 KB (read). Fixed 24-hour TTL for created notes.
334335

335-
This is a convenience endpoint for trusted third-party apps that need to create notes programmatically. It produces the same encrypted output as the main app — AES-256-GCM, XOR key splitting, one-time-read — but encryption happens on the server instead of in the browser. See [notefade.com/docs#integration-api](https://notefade.com/docs#integration-api) for full documentation and security details.
336+
These are convenience endpoints for trusted third-party apps that need to create or read notes programmatically. They produce and consume the same encrypted format as the main app — AES-256-GCM, XOR key splitting, one-time-read — but crypto operations happen on the server instead of in the browser. See [notefade.com/docs#integration-api](https://notefade.com/docs#integration-api) for full documentation and security details.
336337

337338
## 📄 License
338339

src/components/docs/IntegrationApi.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ export function IntegrationApi() {
88
return (
99
<DocsSection id='integration-api' title='integration API (third-party)'>
1010
<DocsCallout variant='danger'>
11-
This endpoint does <strong>not</strong> follow notefade's zero-knowledge
12-
security model. The server receives plaintext, encrypts it, and returns
13-
a note URL. Plaintext is held in volatile Worker memory for ~1-2ms —
14-
never stored, never logged, no filesystem — but the server{' '}
15-
<em>processes</em> content, which the main application never does. Do
16-
not send highly sensitive plaintext through this endpoint ONLY EVER SEND
17-
ALREADY ENCRYPTED TEXT. It is a convenience API for trusted third-party
11+
These endpoints do <strong>not</strong> follow notefade's zero-knowledge
12+
security model. The create endpoint receives plaintext and encrypts it
13+
on the server. The read endpoint fetches the shard, reconstructs the
14+
key, and decrypts on the server. In both cases, plaintext is held in
15+
volatile Worker memory for ~1-2ms — never stored, never logged, no
16+
filesystem — but the server <em>processes</em> content, which the main
17+
application never does. Do not send highly sensitive plaintext through
18+
the create endpoint — ONLY EVER SEND ALREADY ENCRYPTED TEXT. The read
19+
endpoint will return whatever the note contains, so if the content was
20+
pre-encrypted before creation, the server only ever sees the opaque
21+
ciphertext. These are convenience APIs for trusted third-party
1822
applications, not a replacement for the main application's client-side
1923
encryption.
2024
</DocsCallout>
2125

2226
<p className={styles.text}>
23-
The integration API lets third-party applications create encrypted notes
24-
with a single HTTP request. It produces the same encrypted output as the
25-
main app — AES-256-GCM, XOR key splitting, one-time-read — but
26-
encryption happens on the server instead of in the browser.
27+
The integration API lets third-party applications create and read
28+
encrypted notes with a single HTTP request. It uses the same
29+
AES-256-GCM encryption and XOR key splitting as the main app, but
30+
encryption and decryption happen on the server instead of in the
31+
browser.
2732
</p>
2833

2934
<h3 className={styles.subheading}>How it differs from the main app</h3>
@@ -41,6 +46,11 @@ export function IntegrationApi() {
4146
<td>Client (browser)</td>
4247
<td>Server (Worker isolate)</td>
4348
</tr>
49+
<tr>
50+
<td>Decryption location</td>
51+
<td>Client (browser)</td>
52+
<td>Server (Worker isolate)</td>
53+
</tr>
4454
<tr>
4555
<td>Server sees plaintext</td>
4656
<td>Never</td>
@@ -66,13 +76,17 @@ export function IntegrationApi() {
6676

6777
<h3 className={styles.subheading}>When to use this</h3>
6878
<ul className={styles.list}>
69-
<li>Third-party apps that need to create notes programmatically</li>
79+
<li>Third-party apps that need to create or read notes programmatically</li>
7080
<li>
7181
Server-side services where importing the crypto module isn't practical
7282
</li>
7383
<li>
7484
Trusted integrations owned by the same operator running the Worker
7585
</li>
86+
<li>
87+
Consuming notes that were created with pre-encrypted content — the
88+
server only sees the opaque ciphertext, not the underlying secret
89+
</li>
7690
</ul>
7791

7892
<h3 className={styles.subheading}>When NOT to use this</h3>
@@ -144,7 +158,12 @@ export function IntegrationApi() {
144158
<ul className={styles.list}>
145159
<li>
146160
Plaintext is visible to the Worker isolate for ~1-2ms during
147-
encryption
161+
encryption or decryption
162+
</li>
163+
<li>
164+
The read endpoint requires sending the full note URL (including
165+
fragment) to the server — in normal browser usage, the fragment never
166+
leaves the client
148167
</li>
149168
<li>
150169
Cloudflare (as the infrastructure provider) could theoretically

src/components/docs/docs-data.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,52 @@ X-RateLimit-Reset: 1710720060
370370
"url": "https://notefade.com/#a1b2c3d4e5f67890:...",
371371
"shardId": "a1b2c3d4e5f67890",
372372
"expiresAt": 1710806400000
373+
}`,
374+
},
375+
{
376+
method: 'POST',
377+
path: '/api/v1/read-note',
378+
summary: 'Read a note (server-side decryption)',
379+
description:
380+
'Accepts a note URL, fetches the shard from storage, reconstructs the encryption key, and decrypts the content on the server. The shard is consumed — the note cannot be read again. Plaintext is held in volatile Worker memory for ~1-2ms during decryption — never stored, never logged. The full note URL (including fragment) must be sent to the server, which means the server momentarily has access to all key material. Requires a valid API key via the X-Api-Key header. Multi-chunk and custom-provider notes are not supported.',
381+
params: [
382+
{
383+
name: 'url',
384+
location: 'body',
385+
type: 'string',
386+
required: true,
387+
description: 'The full note URL including the fragment (e.g. https://notefade.com/#shardId:check:payload). The fragment is required — it contains the encrypted data and key material.',
388+
pattern: 'Must contain # fragment',
389+
},
390+
],
391+
responses: [
392+
{
393+
status: 200,
394+
description: 'Note decrypted and returned',
395+
body: '{ "text": "The secret message content", "shardId": "a1b2c3d4e5f67890" }',
396+
},
397+
{ status: 400, description: 'Invalid URL, bad fragment format, integrity check failed, or multi-chunk/custom-provider URL' },
398+
{ status: 401, description: 'Missing or invalid API key' },
399+
{ status: 404, description: 'Note not found — already read, expired, or invalid shard ID' },
400+
{ status: 413, description: 'Request body exceeds 16 KB' },
401+
{ status: 429, description: 'Per-key rate limit exceeded' },
402+
],
403+
exampleRequest: `POST /api/v1/read-note HTTP/1.1
404+
Content-Type: application/json
405+
X-Api-Key: nfk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
406+
407+
{
408+
"url": "https://notefade.com/#a1b2c3d4e5f67890:aBcDeF:..."
409+
}`,
410+
exampleResponse: `HTTP/1.1 200 OK
411+
Content-Type: application/json
412+
X-RateLimit-Limit: 60
413+
X-RateLimit-Remaining: 59
414+
X-RateLimit-Reset: 1710720060
415+
416+
{
417+
"text": "The deploy credentials are ...",
418+
"shardId": "a1b2c3d4e5f67890"
373419
}`,
374420
},
375421
]

0 commit comments

Comments
 (0)