{
  "info": {
    "name": "Document Operation API",
    "description": "Every endpoint, ready to run.\n\n1. Open **Variables** and paste your key into `apiKey`.\n2. Set `baseUrl` if you are not pointing at the default.\n3. Send **Render markup to PDF**. Postman shows the PDF in the response pane.\n\nThe key is a collection variable, so it is sent on every request automatically and\nappears in exactly one place when you need to rotate it.\n\n**Write template placeholders as `[[ name ]]` here.** `{{ name }}` also works and is\nthe same thing, but it is Postman's variable syntax as well as ours: a placeholder\nwhose name matches a variable you have defined \u2014 including this collection's own\n`apiKey`, `baseUrl` and `sessionToken` \u2014 is substituted **before the request leaves\nPostman**, so a body containing `{{ apiKey }}` arrives here with your real key\npasted into it and stored in the template. Postman does not touch `[[ ]]`.\n",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "version": "0.1.0"
  },
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "X-API-Key",
        "type": "string"
      },
      {
        "key": "value",
        "value": "{{apiKey}}",
        "type": "string"
      },
      {
        "key": "in",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.docufinery.com",
      "type": "string",
      "description": "Base URL of the API, no trailing slash."
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "string",
      "description": "Your dk_live_... key. Paste it here."
    },
    {
      "key": "sessionToken",
      "value": "",
      "type": "string",
      "description": "Only for the key-management routes. From POST /auth/google."
    }
  ],
  "item": [
    {
      "name": "account",
      "item": [
        {
          "name": "The signed-in account and its balance",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/account",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "account"
              ]
            },
            "description": "The signed-in account and its balance",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Recent jobs and what each one cost",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/account/usage",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "account",
                "usage"
              ]
            },
            "description": "One row per operation, newest first.\n\n`credits_used` is what was actually SETTLED, and is 0 for a refunded job.\nReporting the amount held would show a charge for work that was refunded,\nwhich is the line a customer screenshots.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Credit packs and where to buy them",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/account/packs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "account",
                "packs"
              ]
            },
            "description": "The pack catalogue, from the same table `/facts` and `llms.txt` use.\n\nOne source for the prices. Three hand-maintained copies would disagree\neventually, and the copy a customer sees before paying is the one that has\nto be right.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "archive",
      "item": [
        {
          "name": "Upload an export and get a payment link. No API key, no account.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/archive/job",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "archive",
                "job"
              ]
            },
            "description": "Upload, parse, hold, and hand back a payment link.\n\n**Keyless and rate-limited by IP**, like every other endpoint here that has\nno account behind it. Nothing touches the ledger, so \"no credits consumed\"\nis structural rather than something a code path has to remember.\n\n**The file is parsed before payment.** A customer who pays and then learns\ntheir export is unreadable has been taken money for nothing, and the refund\ncosts more than the sale was worth. The response says how many messages were\nfound and what it will cost, so they know what they are buying.\n\n**The price is flat and does not depend on the message count** just returned.\nThat is worth being explicit about here, because the two numbers sit next to\neach other in the response and a per-message reading of them would be wrong:\na five-year group chat and a fifty-message thread cost the same.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "How a per-job archive is getting on. No API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/archive/job/:job_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "archive",
                "job",
                ":job_id"
              ],
              "variable": [
                {
                  "key": "job_id",
                  "value": "<job_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Poll after paying. **The id is the credential.**\n\nA random UUID that only the person who uploaded the file has been shown is\nthe whole of the authorisation here, which is the price of having no\naccounts. It is not guessable, it is not enumerable, and it grants nothing\nexcept this one archive.\n\nCounted against the READ budget, not the free-work one: this is polled every\nfew seconds by a customer who has already paid, and charging that to the\nsame allowance as an upload locked the whole address out (BUGS.md UI28).",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "The finished archive. No API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/archive/job/:job_id/download",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "archive",
                "job",
                ":job_id",
                "download"
              ],
              "variable": [
                {
                  "key": "job_id",
                  "value": "<job_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "The result, for the person holding the id.\n\n**Also emailed**, because a consumer who closes the tab has no other way\nback. The download exists so the common case \u2014 pay, come back, take the file\n\u2014 does not depend on an email arriving.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Turn a chat or mail export into a readable archive",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/archive",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "archive"
              ]
            },
            "description": "Turn a chat or mail export into a readable archive",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "auth",
      "item": [
        {
          "name": "Public sign-in configuration",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/config",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "config"
              ]
            },
            "description": "Which sign-in methods this deployment offers.\n\n**Fetched rather than baked into the static export.** A `NEXT_PUBLIC_`\nvariable is frozen at build time, so the same build could not serve dev and\nprod. One deploy-time setting on the API, no frontend rebuild.\n\nSince D5 closed on 8 Sep 2026 this reports two booleans instead of a Google\nclient ID. `email_sign_in` is always true and needs no third-party\ncredential: with no `RESEND_API_KEY` the code prints to the log instead of\nbeing emailed, so a fresh checkout can still sign in.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Email a 6-digit sign-in code",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/email/start",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "email",
                "start"
              ]
            },
            "description": "Send a sign-in code to an address.\n\n**Always 202, whether or not an account exists.** There is nothing to leak:\nany verified address can sign in, and a first sign-in creates the account.\nThat also means this endpoint cannot be used to test whether someone has an\naccount here, which a \"no such user\" response would hand over for free.\n\n`delivered` reports whether it went to Resend or to the log. It is the\ndifference between \"check your inbox\" and \"check the backend log\", and on a\nfresh checkout with no `RESEND_API_KEY` it is the latter.",
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"string\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Exchange a sign-in code for a session",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/email/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "email",
                "verify"
              ]
            },
            "description": "Consume the code and issue a session, creating the account if needed.\n\nThe signup grant is written in the SAME transaction as the account, so a\ncrash between them cannot leave an account with no credits.",
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"string\",\n  \"code\": \"string\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "billing",
      "item": [
        {
          "name": "Stripe webhook. Signature-verified; the only path that adds credits.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/stripe/webhook",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "stripe",
                "webhook"
              ]
            },
            "description": "Stripe webhook. Signature-verified; the only path that adds credits.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "capture",
      "item": [
        {
          "name": "Capture a URL as evidence",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture"
              ]
            },
            "description": "Capture a URL as evidence",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "List this account's captures",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture"
              ]
            },
            "description": "List this account's captures",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Check a capture's hashes. Public, no API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/:capture_id/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                ":capture_id",
                "verify"
              ],
              "variable": [
                {
                  "key": "capture_id",
                  "value": "<capture_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "The trust artefact, and the reason the rest of this product exists.\n\n**Unauthenticated on purpose.** The person who needs to check a capture is\nthe one being shown it \u2014 an opposing solicitor, a regulator, a judge \u2014 and\nthey have no account here and never will. A verification page that requires\nthe owner's credentials verifies nothing to anybody who matters.\n\nRate-limited by IP like every other keyless endpoint, and it reads only:\nthere is nothing here to spend and nothing to change. That is why it counts\nagainst the READ budget rather than the free-work one \u2014 a solicitor\nre-checking a manifest must not be able to exhaust a shared address's\nallowance for the marketing site's tools.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Delete a capture and its stored files. Yours only.",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/:capture_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                ":capture_id"
              ],
              "variable": [
                {
                  "key": "capture_id",
                  "value": "<capture_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "**The other half of \"retained until you delete them\".** `BUGS.md` UI52.\n\nThe console said it, every #4 footer said it, and `/legal/retention/` said it\nin its exception list, and until 7 Oct 2026 the only way to stop storing a\ncapture was to ask a human. On the one product here that keeps anything, that\nis the sentence that has to be a mechanism.\n\nAuthenticated and scoped to the caller, unlike `verify` and the artefact\ndownload: reading a capture you were given a reference to is the product,\ndestroying one is not. The verify link stays public and starts returning 404\nthe moment this succeeds, which is the correct answer to \"has this been\ndeleted\".",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Download one stored artefact. Public, no API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/:capture_id/artefact/:name",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                ":capture_id",
                "artefact",
                ":name"
              ],
              "variable": [
                {
                  "key": "capture_id",
                  "value": "<capture_id>",
                  "description": "Replace with a real id before sending."
                },
                {
                  "key": "name",
                  "value": "<name>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "**The files the product is sold as.** `BUGS.md` UI45.\n\nEverything else about a capture worked: four artefacts written, hashed,\nRFC-3161 timestamped, and verifiable by a stranger with no account. There was\nno way to fetch one. A $6 buyer received an email with a verify link, and the\nsigned-in owner of a retained capture saw a `Verify` link and nothing else,\nwhile their 4,862 KB sat in R2.\n\n**Keyless, for the same reason `verify` is.** The point of a capture is that\nthe other side can check it, and a screenshot they cannot open is not\nevidence to them. The id is an unguessable UUID and it is the capability \u2014 the\nsame model as the verify link that is already public, and the same one the\nemailed link relies on. Making this one authenticated would mean the holder\nof a shared reference can verify hashes but not see the page they describe.\n\nOnly artefacts named in the signed manifest are served, so this cannot be\nwalked into a directory listing, and `..` or any other name simply is not in\nthe manifest and 404s.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "List this account's capture schedules",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/schedule",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "schedule"
              ]
            },
            "description": "List this account's capture schedules",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Capture a URL repeatedly",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/schedule",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "schedule"
              ]
            },
            "description": "Recurring capture. **No credits move here** \u2014 each RUN is billed.\n\nCharging at schedule time would be charging for work not yet done, and a\nschedule that is paused or deleted before its first run would have taken\nmoney for nothing.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"string\",\n  \"interval_minutes\": 1440,\n  \"evidence\": true,\n  \"notify_email\": \"\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Pause, resume or re-time a schedule",
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/schedule/:schedule_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "schedule",
                ":schedule_id"
              ],
              "variable": [
                {
                  "key": "schedule_id",
                  "value": "<schedule_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Pause, resume or re-time a schedule",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Delete a schedule. Its captures are kept.",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/schedule/:schedule_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "schedule",
                ":schedule_id"
              ],
              "variable": [
                {
                  "key": "schedule_id",
                  "value": "<schedule_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "**The captures survive.** `schedule_id` is nullable and does not cascade.\n\nDeleting a schedule is an operational act \u2014 \"stop doing this\". Deleting the\nevidence it collected is a different act, and it must not happen as a side\neffect of the first one.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Record a URL and get a payment link. No API key, no account.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/job",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "job"
              ]
            },
            "description": "Check the URL, record the job, and hand back a payment link.\n\n**Keyless and rate-limited by IP**, like every other endpoint here with no\naccount behind it. Nothing touches the ledger.\n\n**The URL is validated before payment**, through the same `netguard` the\npaid endpoint uses \u2014 private addresses, loopback and the rest are refused\nhere rather than after the money has moved. A customer who pays and then\nlearns the address was never fetchable has been taken money for nothing.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "How a per-job capture is getting on. No API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/capture/job/:job_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "capture",
                "job",
                ":job_id"
              ],
              "variable": [
                {
                  "key": "job_id",
                  "value": "<job_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Poll after paying. **The id is the credential.**\n\nA random UUID that only the person who submitted the URL has been shown is\nthe whole of the authorisation here, which is the price of having no\naccounts. It grants nothing except this one job.\n\nCounted against the READ budget, not the free-work one: this is polled every\nfew seconds by a customer who has already paid, and charging that to the\nsame allowance as a submission locked the whole address out (BUGS.md UI28).",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "convert",
      "item": [
        {
          "name": "Every conversion this API can actually do. Free, no API key.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/convert/formats",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "convert",
                "formats"
              ]
            },
            "description": "The capability list, probed from the installed binaries.\n\n**Free and unauthenticated**, like `/metadata/inspect`: a customer deciding\nwhether to buy needs to know whether their pair is supported, and putting\nthat behind a key means finding out by spending a credit on a 422.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Convert one small document. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/convert/free",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "convert",
                "free"
              ]
            },
            "description": "The working tool that sits on every generated page (F86).\n\n**This endpoint is what makes the generated page set defensible.** The rule\nkept from the superseded scaled-content-abuse restriction is that every page\ncarries a working tool \u2014 that is the property distinguishing iLovePDF's\nsurviving pages from a doorway set. A conversion page cannot run pandoc,\nLibreOffice or calibre in a browser, and shipping 64 pages whose \"tool\" is a\nlink to the docs would be exactly the pattern the policy describes.\n\nSame shape as `/metadata/inspect`, and for the same reasons: no `CallerDep`,\nso keyless is structural rather than remembered; nothing touches the ledger,\nso \"no credits consumed\" cannot drift; lower size cap and a per-address rate\nlimit, because free is what gets abused.\n\n`PRD.md` \u00a73.1's free-vs-credits split is the boundary: one file per run, a\nsmaller cap, web UI only. Batch, large documents and automation are the API.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Convert a document from one format to another",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/convert",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "convert"
              ]
            },
            "description": "Convert a document from one format to another",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "extract",
      "item": [
        {
          "name": "Read a web page as clean markdown, text, HTML, PDF or PNG",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/extract",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "extract"
              ]
            },
            "description": "Read a web page as clean markdown, text, HTML, PDF or PNG",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Read one page as markdown. Free, no API key, truncated.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/extract/preview",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "extract",
                "preview"
              ]
            },
            "description": "The free reader on F117's landing pages.\n\n**Truncated on purpose, and the truncation is stated.** #6 is a flat credit\nper page, so unlike #8's scanner there is no price to quote \u2014 the honest free\ntool is a real answer with a visible end, not a fake one. Someone can see the\nextraction quality on their own URL, which is the only question a landing\npage for this product has to answer, and reading a whole article costs a\ncredit like it does for everyone.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "The page as a PDF, first 3 pages. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/extract/preview/pdf",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "extract",
                "preview",
                "pdf"
              ]
            },
            "description": "The free PDF on `/webpage-to-pdf/` (UI43).\n\n**Why this is not the same page load as `/preview`.** The markdown preview\npasses `text_only`, which blocks images and CSS: cheaper, and it produces a\nPDF of a page with no pictures and no layout, which is worse than no PDF at\nall. So this asks for a `png`-grade load and takes the PDF out of it.\n\n**Trimmed with pdfcpu, in tmpfs, unlinked on the way out.** The alternative,\nstopping Chromium early, does not exist: a PDF comes out of one `printToPDF`\nwhole. A14's promise holds either way \u2014 nothing is written outside the\nworkspace and nothing survives the response.\n\nThe same per-address budget as every other keyless endpoint that does work.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "keys",
      "item": [
        {
          "name": "List Keys",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "keys"
              ]
            },
            "description": "List Keys",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Create Key",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "keys"
              ]
            },
            "description": "Create Key",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Revoke Key",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/keys/:key_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "keys",
                ":key_id"
              ],
              "variable": [
                {
                  "key": "key_id",
                  "value": "<key_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Revoke Key",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "mcp",
      "item": [
        {
          "name": "MCP endpoint. GET is for server-initiated streams, which this server has none of.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/mcp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "mcp"
              ]
            },
            "description": "Declined, deliberately, with the status the spec expects.\n\nStreamable HTTP lets a client open a GET for messages the server starts.\nThis server never starts one \u2014 every tool answers the call that asked for\nit \u2014 so 405 is the documented way to say \"not supported\", and a client that\nreceives it simply does not open the stream. Returning 200 with an empty\nstream instead leaves the client holding a connection for ever.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "MCP endpoint. JSON-RPC 2.0 over HTTP; tools/call needs an API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/mcp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "mcp"
              ]
            },
            "description": "MCP endpoint. JSON-RPC 2.0 over HTTP; tools/call needs an API key.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "meta",
      "item": [
        {
          "name": "Postman collection (v2.1.0) for every endpoint",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/postman/collection.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "postman",
                "collection.json"
              ]
            },
            "description": "Generated from `/openapi.json` on every request. See app/postman.py.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Short description of the product for AI answer engines",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/llms.txt",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "llms.txt"
              ]
            },
            "description": "Short description of the product for AI answer engines",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Full description of the product for AI answer engines",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/llms-full.txt",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "llms-full.txt"
              ]
            },
            "description": "Full description of the product for AI answer engines",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Canonical statement of what this product does and does not do",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/facts",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "facts"
              ]
            },
            "description": "Self-contained HTML with JSON-LD. See app/facts.py.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "metadata",
      "item": [
        {
          "name": "Show what a file reveals about you. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/metadata/inspect",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "metadata",
                "inspect"
              ]
            },
            "description": "Read a file's metadata without changing it, without a key, without a credit.\n\n**`POST`, not `GET`, despite the F-item's name.** It takes a file, and a GET\nhas nowhere to put one. The properties the item actually specifies \u2014 free,\nno key, rate-limited by IP \u2014 are all here.\n\nThis is the lead magnet for product #2: someone drops in a holiday\nphotograph, sees the coordinates of their house, and now understands what\nthe paid operation is for. It has to be free for that to happen, and free\nmeans it is the endpoint that gets abused, hence the lower size cap and the\nper-address limit.\n\n**No `CallerDep`.** Being outside the auth dependency is what makes it\nkeyless, and it is also why nothing here touches the ledger: there is no\naccount to charge, so the \"no credits consumed\" property is structural\nrather than something a code path has to remember.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Remove metadata from a PDF, JPEG or PNG",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/metadata/strip",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "metadata",
                "strip"
              ]
            },
            "description": "Remove metadata from a PDF, JPEG or PNG",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "operations",
      "item": [
        {
          "name": "Every operation a signed-in customer can run, and what it costs",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/operations",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "operations"
              ]
            },
            "description": "The run screen's source of truth.\n\n**Public, and it has to be.** A visitor deciding whether to buy needs to see\nwhat the product does and what each job costs before they have an account,\nwhich is the same reason `/pricing` is public. Nothing here is\naccount-specific: it is the catalog, not a quote.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "ops",
      "item": [
        {
          "name": "Health",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "health"
              ]
            },
            "description": "Process liveness. Never touches the database. See module docstring.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Ready",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/health/ready",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "health",
                "ready"
              ]
            },
            "description": "Readiness: the database answers.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Dashboard Elsewhere",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/",
              "host": [
                "{{baseUrl}}"
              ],
              "path": []
            },
            "description": "Not an error. The dashboard is a separate origin now (F154).",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "parse",
      "item": [
        {
          "name": "Parse a document to markdown",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/parse",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "parse"
              ]
            },
            "description": "Parse a document to markdown",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Parse many documents, streaming results",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/parse/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "parse",
                "batch"
              ]
            },
            "description": "The same parse applied to each document, over SSE.\n\n**Each item is priced on its own**, unlike every other batch here: a mixed\nupload of typed and scanned documents has no single per-item cost, and\ncharging the OCR rate across the batch because one item was a scan is the\novercharge F68 exists to prevent. `per_item_credits` is therefore the\n*cheapest* possible item, and the real figure rides in each event.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "pdf",
      "item": [
        {
          "name": "Run a PDF operation",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/pdf/:op",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "pdf",
                ":op"
              ],
              "variable": [
                {
                  "key": "op",
                  "value": "<op>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Run a PDF operation",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Compress or unlock one small PDF. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/pdf/free/:op",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "pdf",
                "free",
                ":op"
              ],
              "variable": [
                {
                  "key": "op",
                  "value": "<op>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "The free tool on `/compress` and `/unlock`.\n\n**Nothing is stored, and the password least of all.** The upload goes to a\ntmpfs workspace that is unlinked before the response completes. The password\nis never written to disk, never logged, and goes to qpdf **on stdin** rather\nthan in its argument vector \u2014 which used to be `--password=...`, readable in\n`/proc` by anything on the machine that can list processes. That was changed\nwhen this endpoint was written, because a keyless tool makes the exposure\neverybody's rather than one authenticated customer's. The page says all of\nthis, because \"type your PDF password into this website\" is a reasonable\nthing to hesitate over.\n\n**The same code as the paid endpoint**, through `_execute`. A second\nimplementation would be a second set of bugs and, worse, a free tool whose\noutput differs from what a customer gets after paying.",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Run a PDF operation over many files, streaming results",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/pdf/:op/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "pdf",
                ":op",
                "batch"
              ],
              "variable": [
                {
                  "key": "op",
                  "value": "<op>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "The same operation applied to each file independently, over SSE.\n\n**`merge` is refused here.** Batching means \"this op, to each file on its\nown\", and merge is many-to-one by definition \u2014 a batched merge is either\nevery file merged with nothing, or exactly what `POST /pdf/merge` already\ndoes. Refusing with that sentence is better than picking one and being wrong\nabout which the caller meant.\n\nOptions apply to every item. That is the point of a batch, and it is why\n`Options` is frozen: one instance is shared across concurrent items.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "redact",
      "item": [
        {
          "name": "Remove text from a PDF so it cannot be recovered",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/redact",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "redact"
              ]
            },
            "description": "Remove text from a PDF so it cannot be recovered",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "render",
      "item": [
        {
          "name": "Render markup to PDF",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/render",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "render"
              ]
            },
            "description": "Render markup to PDF, charging the caller's account.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"markup\": \"# Invoice 1042\\n\\n**ACME Corp** \\u2014 1,234.50 USD due 30 Sep 2026.\\n\",\n  \"format\": \"md\",\n  \"page_size\": \"a4\",\n  \"margin_mm\": 20,\n  \"footer\": \"Page {page} of {pages}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Render a stored template with data",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/render/from-template",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "render",
                "from-template"
              ]
            },
            "description": "Fill a stored template's placeholders and render it.\n\nThe retention hook for product #1: a customer with a stored template posts a\nfew hundred bytes of data on a schedule instead of re-sending the markup\nevery time, which is the difference between a one-off job and a recurring\none. Same price as `/render` \u2014 the template is free, the render is not.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"template_name\": \"invoice\",\n  \"data\": {\n    \"customer\": \"ACME Corp\",\n    \"total\": \"1234.50\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Render many documents, streaming results as Server-Sent Events",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/render/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "render",
                "batch"
              ]
            },
            "description": "Render many documents, streaming results as Server-Sent Events",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    {\n      \"markup\": \"= First\\nOne.\",\n      \"format\": \"typst\"\n    },\n    {\n      \"markup\": \"= Second\\nTwo.\",\n      \"format\": \"typst\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "results",
      "item": [
        {
          "name": "Fetch a result by signed URL",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/results/:key",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "results",
                ":key"
              ],
              "variable": [
                {
                  "key": "key",
                  "value": "<key>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Fetch a result by signed URL",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "spreadsheet",
      "item": [
        {
          "name": "Clean a messy spreadsheet: headers, types, merged cells, audit log",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/spreadsheet/clean",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "spreadsheet",
                "clean"
              ]
            },
            "description": "Clean a messy spreadsheet: headers, types, merged cells, audit log",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "What would change, and what it would cost. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/spreadsheet/preview",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "spreadsheet",
                "preview"
              ]
            },
            "description": "The changes, before the purchase. **No cleaned data comes back.**\n\nThat is what keeps this from being a free tier of the product: the caller\nlearns which columns would be reinterpreted, sees a few examples per kind,\nand gets the price. To have the file they have to buy it.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "tables",
      "item": [
        {
          "name": "Extract tables from a PDF as CSV, XLSX or JSON",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tables",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tables"
              ]
            },
            "description": "Extract tables from a PDF as CSV, XLSX or JSON",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Which pages have tables, and what it would cost. Free, no API key.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tables/detect",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tables",
                "detect"
              ]
            },
            "description": "The price, before the purchase.\n\n**Free and keyless on purpose.** This is priced per page, so the cost of a\nrequest is not knowable from the file's name or size \u2014 and a customer who\ncan only find out by being charged will assume the worst. It is also the\ntool that sits on F93's landing pages: someone drops a statement in and sees\n\"6 of 40 pages have tables, 18 credits\" before deciding anything.\n\nDetection only. No extraction, so nothing here is worth stealing as a free\ntier: the answer is a page list, not a spreadsheet.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "templates",
      "item": [
        {
          "name": "List this account's templates",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/templates",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "templates"
              ]
            },
            "description": "List this account's templates",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Store a reusable template",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/templates",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "templates"
              ]
            },
            "description": "Store a reusable template",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"invoice\",\n  \"format\": \"typst\",\n  \"body\": \"= Invoice for [[customer]]\\n\\nTotal due: [[total]] USD.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Fetch one template",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/templates/:template_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "templates",
                ":template_id"
              ],
              "variable": [
                {
                  "key": "template_id",
                  "value": "<template_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Fetch one template",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Update a template",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/templates/:template_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "templates",
                ":template_id"
              ],
              "variable": [
                {
                  "key": "template_id",
                  "value": "<template_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Update a template",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"body\": \"= Invoice v2 for [[customer]]\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete a template",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/templates/:template_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "templates",
                ":template_id"
              ],
              "variable": [
                {
                  "key": "template_id",
                  "value": "<template_id>",
                  "description": "Replace with a real id before sending."
                }
              ]
            },
            "description": "Delete a template",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "youtube",
      "item": [
        {
          "name": "Get a YouTube video's transcript as txt, srt, vtt or json",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/youtube",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "youtube"
              ]
            },
            "description": "Get a YouTube video's transcript as txt, srt, vtt or json",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sessionToken}}",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Get a transcript. Free, no API key, truncated.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/youtube/preview",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "youtube",
                "preview"
              ]
            },
            "description": "The free tool on F122's landing page.\n\n**F122 flagged the free-tool pattern as the one place it did not transfer**,\nbecause a keyless *video* download is an open bandwidth proxy that costs real\nmoney per click. With video gone that objection goes with it: this spends one\nmetadata call and one small text fetch, which is the same shape as every\nother free tool on the site.\n\n**Truncated, and the truncation is stated.** Long enough to prove the\ntranscript is real and the quality is what it is; short enough that the paid\nendpoint still has a job.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    }
  ]
}