tools · Listed · eip155:8453 · Found · 234 endpoints · Gateway-eligible
api.relaystation.ai
api.relaystation.ai
$0.01/screen. Screen any name against OFAC, EU, and UK sanctions (UN included) plus Wikidata-derived PEP watchlists — fuzzy matching, instant JSON verdict. Comp
Indexed from this operator's public /.well-known/x402.json. Found is not operator-owned and is not attested. Claim or opt out.
Agent Read · Cleared Index
ROUTE
Route when you need tools at published x402 prices.
confidence
78%
source
signal
Index before you pay. Same payload for agents:
GET /api/cleared/agent-read?slug=cat-api-relaystation-ai
When to call
- Need tools via x402 and want Cleared-indexed payTo with a live scorecard.
- $0.01/screen. Screen any name against OFAC, EU, and UK sanctions (UN included) plus Wikidata-derived PEP watchlists — fuzzy matching, instant JSON verdict. Comp
Risks
- Found — not operator-owned; claim status unknown.
- No Cleared settlement receipt on file yet.
- No Gateway traffic yet — market share unproven.
Price posture
234 endpoints — confirm price on manifest before pay.
Category · Gateway
tools · no Gateway routes yet — early / unproven on Cleared market share.
Endpoint hints
POST /v1/storage/dropStore a file and get a durable, shareable URL — no account, no signup; the wallet is the identity. From $0.001; tiers by size, lifetime, egress. Part of Relayst
POST /v1/storage/passHand a file to another agent or person — scoped, read-capped share tokens that burn once consumed. From $0.001; no account for the recipient. Part of Relaystati
POST /v1/storage/scratchpadShared working memory for agents — append, read, and collaborate on a durable scratchpad with per-collaborator tokens; humans get an online editor. From $0.001.
POST /v1/storage/checkpointSave and restore agent state — durable snapshots you overwrite as you go and resume from anywhere. From $0.001, metered by size, lifetime, egress; no account, t
POST /v1/storage/ledgerAudited ledger (append, hash-chained; tamper-evident; auto-witnessed). Preset-fixed alias of POST /v1/baton — the route injects preset:"ledger" (overriding any
POST /v1/batonA baton is a durable storage object agents create, append, read, and cryptographically prove — then hand off to other agents or people. Presets: file drop, burn
POST /v1/baton/{id}/addBuy more of the same preconfig (another tier of resources). Billable. Owner only.
POST /v1/baton/{id}/extendBuy à-la-carte dimensions (size / duration / egress / writes). At least one required. addDurationSeconds pushes the expiry out (expiry = createdAt + total durat
Evidence (Cleared)
- → Intake verified · Gateway-eligible
- → Trust 70/100 · pass · tier listed
- → Protocol x402 · eip155:8453
- → Manifest reachable · schema valid
- → Found listing — indexed from public x402.json, not operator-attested.
Endpoints
Create a drop baton
$MeteredPOST https://api.relaystation.ai/v1/storage/dropStore a file and get a durable, shareable URL — no account, no signup; the wallet is the identity. From $0.001; tiers by size, lifetime, egress. Part of Relaystation: 155 agent tools on one balance — storage, e-sign, KYC, PDF/data/media, sub-cent LLM. relaystation.ai Store a file (single object, multi-read until expiry). Preset-fixed alias of POST /v1/baton — the route injects preset:"drop" (overriding any body value) and delegates to the same create handler, so body shape, billing, and the x402 path are identical. Billable — the engine quote of the shape.
Create a pass baton
$MeteredPOST https://api.relaystation.ai/v1/storage/passHand a file to another agent or person — scoped, read-capped share tokens that burn once consumed. From $0.001; no account for the recipient. Part of Relaystation: 155 agent tools on one balance — storage, e-sign, KYC, PDF/data/media, sub-cent LLM. relaystation.ai Share a file (single object + a read-capped token; burns once consumed). Preset-fixed alias of POST /v1/baton — the route injects preset:"pass" (overriding any body value) and delegates to the same create handler, so body shape, billing, and the x402 path are identical. Billable — the engine quote of the shape.
Create a scratchpad baton
$MeteredPOST https://api.relaystation.ai/v1/storage/scratchpadShared working memory for agents — append, read, and collaborate on a durable scratchpad with per-collaborator tokens; humans get an online editor. From $0.001. Part of Relaystation: 155 agent tools on one balance — storage, e-sign, KYC, PDF/data/media, sub-cent LLM. relaystation.ai Collaborate (append log + collaborator tokens). Preset-fixed alias of POST /v1/baton — the route injects preset:"scratchpad" (overriding any body value) and delegates to the same create handler, so body shape, billing, and the x402 path are identical. Billable — the engine quote of the shape.
Create a checkpoint baton
$MeteredPOST https://api.relaystation.ai/v1/storage/checkpointSave and restore agent state — durable snapshots you overwrite as you go and resume from anywhere. From $0.001, metered by size, lifetime, egress; no account, the wallet is the identity. Part of Relaystation: 155 agent tools on one balance — relaystation.ai Save state (overwrite; replace the snapshot as you go). Preset-fixed alias of POST /v1/baton — the route injects preset:"checkpoint" (overriding any body value) and delegates to the same create handler, so body shape, billing, and the x402 path are identical. Billable — the engine quote of the shape.
Create a ledger baton
$MeteredPOST https://api.relaystation.ai/v1/storage/ledgerAudited ledger (append, hash-chained; tamper-evident; auto-witnessed). Preset-fixed alias of POST /v1/baton — the route injects preset:"ledger" (overriding any body value) and delegates to the same create handler, so body shape, billing, and the x402 path are identical. Billable — the engine quote of the shape.
Create
$MeteredPOST https://api.relaystation.ai/v1/batonA baton is a durable storage object agents create, append, read, and cryptographically prove — then hand off to other agents or people. Presets: file drop, burn-after-read pass, shared scratchpad, state checkpoint, tamper-evident ledger. Metered by bytes, time, egress, writes; price frozen at purchase. 155 tools, one balance — relaystation.ai Create a baton. Billable — the engine quote of the shape (a preconfig ref or a custom shape), floored at the network minimum.
Add resources
$MeteredPOST https://api.relaystation.ai/v1/baton/{id}/addBuy more of the same preconfig (another tier of resources). Billable. Owner only.
Extend
$MeteredPOST https://api.relaystation.ai/v1/baton/{id}/extendBuy à-la-carte dimensions (size / duration / egress / writes). At least one required. addDurationSeconds pushes the expiry out (expiry = createdAt + total durationSeconds). Billable; engine-quoted. Owner only.
Witness
$MeteredPOST https://api.relaystation.ai/v1/baton/{id}/trust/document-witnessFreeze + sign the baton. Conditionally billable ($0.05 standalone OR free on prepaid path).
Merge PDFs
$MeteredPOST https://api.relaystation.ai/v1/pdf/merge$0.001/page. Combine any number of PDFs into one, in the order you choose. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Concatenate 2+ PDFs into one. Body: { files: [<source>, …], filename? } where each <source> is { inline: <base64> } (≤ 4 MiB decoded) or { inputKey: <scratch key from upload-url> }. Billed per output page. Output: { output: { inline?: <base64> | outputKey + outputUrl (presigned GET, when > 4 MiB), sizeBytes, contentType } }.
Split a PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/split$0.001/page. Split a PDF by page ranges or burst it into single pages. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Split one PDF into multiple. Body: { file: <source>, ranges?: "1-3,5", burst?: true }. `burst` (or no ranges) = one file per page; `ranges` = one file per comma segment. Billed per SOURCE page. Capped at cputools.pdf.split.max_outputs (100). Output: a manifest { files: [{ index, outputKey, outputUrl (presigned GET), pages, sizeBytes }, …] } — never inline.
Rotate pages
$MeteredPOST https://api.relaystation.ai/v1/pdf/rotate$0.001/page. Rotate PDF pages — all or a selection, any multiple of 90°. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Rotate pages by 90/180/270°. Body: { file: <source>, degrees: "90"|"180"|"270", pages?: "all"|"1-3,5" } (pages are 1-based; folds onto existing rotation). Billed per rotated page. Output: uniform JSON output envelope.
Delete / reorder / insert pages
$MeteredPOST https://api.relaystation.ai/v1/pdf/pages$0.001/page. Delete, reorder, or insert PDF pages — restructure without desktop software. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Edit the page set. Body is a discriminated union on `action`: { action:"delete", file, pages:"2,4-5" } | { action:"reorder", file, order:[3,1,2] } | { action:"insert", file, insert:<source>, at:1 }. All page references are 1-based; insert `at`=N+1 appends. Billed per RESULT page. Output: uniform JSON output envelope.
Extract text
$MeteredPOST https://api.relaystation.ai/v1/pdf/extract-text$0.002/page. Pull text and structure out of a PDF — clean input for LLMs and search. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract text via unpdf (a serverless pdf.js build). Body: { file: <source>, pages?: "1-3,5" }. Billed per source page. Output: JSON { totalPages, pages: [{ page, text }, …], text } — no bytes.
Get / set metadata
$MeteredPOST https://api.relaystation.ai/v1/pdf/metadata$0.001/call. Read or set PDF document metadata — title, author, keywords, dates. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Read or write document metadata. Body: { file: <source>, set?: { title?, author?, subject?, keywords?, creator?, producer? } }. No `set` → returns the metadata JSON; with `set` → returns the modified PDF (uniform JSON output envelope). Flat-billed (cputools.price.pdf.metadata.flat_micros).
Watermark / stamp
$MeteredPOST https://api.relaystation.ai/v1/pdf/watermark$0.001/page. Stamp text watermarks across PDF pages — DRAFT, CONFIDENTIAL, or your own. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Stamp text on pages. Body: { file: <source>, text, opacity?:0-1, size?:int, color?:"#RRGGBB", position?:"center"|"top-left"|"top-right"|"bottom-left"|"bottom-right", pages?:"all"|"1-3" }. Billed per stamped page. Output: uniform JSON output envelope.
Form-fill / flatten
$MeteredPOST https://api.relaystation.ai/v1/pdf/form$0.001/page. Fill or flatten PDF forms programmatically — field values in, finished PDF out. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Fill AcroForm fields and/or flatten. Body: { file: <source>, fields?: { <name>: <string|boolean> }, flatten?: bool } — string → text/dropdown/radio, boolean → checkbox. Billed per page. Output: uniform JSON output envelope.
Password-protect a PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/encrypt$0.001/page. Password-protect a PDF with 256-bit AES and set permissions. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Encrypt (password-protect) a PDF via qpdf (256-bit AES) in the cputools worker. Body: { file: <inline base64 | { inputKey }>, userPassword?, ownerPassword?, print?, copy?, modify?, annotate?, fillForms?, extract?, assemble?, printHighRes? } (at least one password; neither may start with "-"). Standard PDF model: an ownerPassword alone leaves the open (user) password EMPTY — anyone opens, permissions are owner-gated. The optional permission booleans (the canonical PDF permission octet) map to qpdf restriction flags; an ABSENT boolean means the qpdf default (allowed). print + printHighRes fold into one print level (none/low/full). `copy` is the live text/graphics extraction control; `extract` is the accessibility-extraction bit, which PDF 2.0 / 256-bit encryption deprecated and always grants (so extract:false may be a no-op). Billed per page. Output: uniform JSON envelope (the encrypted PDF). Passwords ride only in the IAM-gated worker invoke — never logged.
Compress a PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/compress$0.001/page. Recompress and linearize a PDF — smaller files, fast web view. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Recompress a PDF via qpdf (object + content streams, flate) in the cputools worker. Body: { file: <source>, linearize?: bool } (linearize = web "fast view" / byte-range streaming — there is no separate pdf/linearize op). Billed PER PAGE — not by savings; the compression ratio varies by document (an already-optimized PDF may not shrink). Output: uniform JSON envelope (the recompressed PDF).
Render PDF pages to images
$MeteredPOST https://api.relaystation.ai/v1/pdf/render$0.001/page. Rasterize PDF pages to PNG or JPEG — previews, thumbnails, vision-model input. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Rasterize PDF pages to PNG/JPEG via poppler pdftoppm in the cputools worker. Body: { file: <source>, pages?: "1-3,5" (default all), dpi?: int ≤ cputools.render.max_dpi (300), format?: "png"|"jpeg" }. Non-embedded standard-14 fonts render via a vendored DejaVu Sans + fontconfig. Billed per OUTPUT page. Capped at cputools.render.max_pages (40). Output: a manifest { images: [{ index, page, outputKey, outputUrl (presigned GET) }, …] } — never inline.
OCR a PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/ocr$0.003/page. Extract text from a scanned PDF (Tesseract) — make paper searchable data. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract text from a scanned/image PDF via pdftoppm → tesseract (LSTM) in the cputools worker. Body: { file: <source>, pages?: "1-3,5" (default all), lang?: <roster tag, default "eng"> }. SYNCHRONOUS and capped at cputools.ocr.max_sync_pages (5) — the call must clear the 30 s API-Gateway timeout; larger asynchronous jobs are coming. Billed per SOURCE page (premium tier). Output: JSON { pages: [{ page, text }, …], text } — no bytes.
Make a scanned PDF searchable (OCR text layer)
$MeteredPOST https://api.relaystation.ai/v1/pdf/ocr-searchable$0.004/page. Add an invisible OCR text layer to a scanned PDF — looks identical, fully searchable. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert a scanned/image PDF into a SEARCHABLE PDF: per page, pdftoppm rasterizes, tesseract emits a page PDF with the image + an invisible text layer, and qpdf merges them. Body: { file: <source>, pages?: "1-3,5" (default all), lang?: <roster tag, default "eng"> }. SYNCHRONOUS and capped at cputools.ocr.max_sync_pages (5). Billed per SOURCE page at cputools.price.pdf.ocr-searchable.per_page_micros — a premium over plain OCR (it runs OCR plus PDF assembly). Output: the uniform JSON envelope, ALWAYS as a storage ref ({ output: { outputKey, outputUrl (presigned GET), sizeBytes, contentType: "application/pdf", filename } }) — never inline, even for small outputs (the render convention).
OCR an image
$MeteredPOST https://api.relaystation.ai/v1/image/ocr$0.003/call. Extract text from an image — Tesseract, 10 languages, plain text out. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract text from a raster image (PNG/JPEG/TIFF/BMP/WebP — anything leptonica reads) via tesseract (LSTM) in the cputools worker. Body: { file: <source>, lang?: <roster tag, default "eng">, tsv?: bool }. With tsv: true the response also carries tesseract's TSV (per-word bounding boxes + confidences). No pre-charge image-format guard — tesseract is the parser; a non-image input is a refunded 422 IMAGE_PARSE_FAILED. FLAT-billed (cputools.price.image.ocr.flat_micros). Output: JSON { text, tsv? } — no bytes.
Repair a damaged PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/repair$0.001/page. Diagnose and rewrite a damaged PDF — recover files other tools reject. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Diagnose and rewrite a damaged PDF via qpdf in the cputools worker: `qpdf --check` produces a findings report (exit 0 clean / 2 errors / 3 warnings), then a full re-serialization reconstructs the xref and normalizes structure. Body: { file: <source> }. Billed per page (compress's grain — same engine, structural rewrite). Output: { output: { outputKey, outputUrl (presigned GET), sizeBytes, contentType: "application/pdf", filename }, repair: { exitCode, findings: [...] } } — the repaired PDF is ALWAYS a storage ref. A PDF too damaged to parse at all is a 422 PDF_PARSE_FAILED.
Verify PDF digital signatures (structural)
$MeteredPOST https://api.relaystation.ai/v1/pdf/verify-signatures$0.001/call. Verify a PDF's digital signatures — structural + digest checks, results as JSON. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Inspect a PDF's digital signatures via poppler pdfsig in the cputools worker. Body: { file: <source> }. HONEST SEMANTICS: this is STRUCTURAL verification + digest intactness — signature present, the signed byte range unmodified (signatureValidation), signer identity fields surfaced (common name, DN, signing time, hash algorithm). Certificate-chain trust is NOT evaluated — no CA store is deployed, so certificateValidation typically reports the chain could not be checked. FLAT-billed (cputools.price.pdf.verify-signatures.flat_micros). Output: JSON { signatures: [{ index, signerCommonName?, signerDistinguishedName?, signingTime?, hashAlgorithm?, signatureType?, signatureValidation?, certificateValidation? }, …], signatureCount } — an UNSIGNED document returns signatures: [] (not an error). Pairs with the e-sign product (esigndoc) as the verification half.
Generate a PDF from HTML (headless Chromium)
$MeteredPOST https://api.relaystation.ai/v1/pdf/from-html$0.003/call. Render HTML to PDF — sandboxed headless Chromium, print-quality output. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render caller-supplied HTML to a PDF on headless Chromium (a dedicated render worker) — invoices, reports, contracts, certificates. Body: { html: string, options?: { format?: "A4"|"Letter"|"Legal"|"A3"|"A5"|"Tabloid"|"Ledger", landscape?, printBackground?, scale?: 0.1–2, margin?: { top, right, bottom, left }, displayHeaderFooter?, headerTemplate?, footerTemplate?, pageRanges?: "1-5, 8", tagged? } }. Header/footer templates are HTML print furniture (use the `date`/`title`/`url`/`pageNumber`/`totalPages` classes); supplying one implies displayHeaderFooter unless you set it false. `pageRanges` prints a subset; `tagged` (default true) emits an accessible/tagged PDF. SANDBOXED: the renderer has NO network and NO JavaScript — every request whose scheme is not `data:` is aborted (external URLs, `<script>`, `@import`, `file://` all blocked), and the header/footer templates render under the same wall — so ALL assets must be inlined as `data:` URIs / inline `<style>` (the contract). Billed FLAT per render (`cputools.price.pdf.from-html.flat_micros`) — the output page count is not known until after the render, so it cannot drive an x402 pre-auth. Output: uniform JSON envelope (application/pdf) + the page count.
Extract embedded images from a PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/images$0.001/page. Extract every embedded image from a PDF as PNGs. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract embedded images (unpdf/pdf.js → raw pixels → PNG via sharp). Body: { file, pages? ("1-3,5") }. Per-page billed (`cputools.price.pdf.images.per_page_micros`). Capped at 200 images (truncated flag). Output: JSON `{ images: [{ page, index, width, height, output }], count, truncated }`.
Text-compare two PDFs
$MeteredPOST https://api.relaystation.ai/v1/pdf/diff$0.001/page. Text-compare two PDFs into a unified diff — spot every change between versions. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract text from two PDFs and produce a unified diff (unpdf + jsdiff). Body: { a, b, context? }. Per-page billed on a+b (`cputools.price.pdf.diff.per_page_micros`). Output: JSON `{ patch, changed }`.
Read a PDF outline / bookmarks
$MeteredPOST https://api.relaystation.ai/v1/pdf/bookmarks$0.001/call. Read a PDF's outline/bookmark tree as JSON — navigate structure before extracting. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Read the outline/bookmark tree (pdf.js getOutline). Body: { file }. FLAT-billed (`cputools.price.pdf.bookmarks.flat_micros`). READ-ONLY — setting an outline is deferred. Output: JSON `{ outline: [{ title, children }], count }`.
List / extract PDF attachments
$MeteredPOST https://api.relaystation.ai/v1/pdf/attachments$0.0005/MB. List or extract files embedded inside a PDF — pull attachments out programmatically. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny List (and optionally extract) embedded file attachments (pdf.js getAttachments). Body: { file, extract? }. Billed PER MiB of output — `ceil(Σ output bytes / 1 MiB)` × `cputools.price.pdf.attachments.per_mb_micros`: extract:true meters the summed extracted attachment bytes (egress); the extract:false list path floors to 1 MiB (constant minimum ≈ flat). Output: JSON `{ attachments: [{ filename, size, output? }], count }`.
Generate a QR code
$MeteredPOST https://api.relaystation.ai/v1/qr$0.0002/call. Generate QR codes as PNG or SVG — size, error-correction, and margin control. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate a QR code from a `data` string — no file input. Body: { data (≤ cputools.qr.max_data_len, 4096), format?: "png"|"svg" (default png), size?: 64-2048 (default 512), margin?: 0-16 (default 4), ecc?: "L"|"M"|"Q"|"H" (default M) }. FLAT price $0.0002 (cputools.qr.generate). Output: uniform JSON envelope { output: { inline: <base64 PNG | base64 SVG>, sizeBytes, contentType } } — always inline (QR images are small).
Generate a barcode
$MeteredPOST https://api.relaystation.ai/v1/barcode$0.0002/call. Generate a print-ready 1D barcode (Code128, EAN, UPC & more) as PNG — set symbology, height, scale. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate a linear/2D barcode via bwip-js — no file input. The full documented engine roster (108 symbologies) is supported: EAN/UPC, Code 128/39/93, GS1 family (DataBar, GS1-128, composites), QR/Micro QR, Data Matrix, PDF417/MicroPDF417, Aztec, postal codes, ISBN/ISMN/ISSN, pharmacode, codabar, and more. Body: { data, symbology (the bcid — see the schema enum), format?: "png"|"svg" (default png), scale?: 1-10 (default 3), height?: 1-200 (default 10) }. Data the symbology cannot encode (bad check digit, wrong length, invalid charset) → 422 BARCODE_RENDER_FAILED naming the engine reason, charge reversed. FLAT price $0.0002 (cputools.barcode.generate). Output: uniform JSON envelope (always inline).
Resize an image
$MeteredPOST https://api.relaystation.ai/v1/image/resize$0.0003/MP. Resize or fit images — animated GIF/WebP preserved with animated:true. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Resize via sharp. Body: { file: <inline base64 | { inputKey }>, width?, height?, fit?: "cover"|"contain"|"fill"|"inside"|"outside", animated?: bool } (at least one of width/height; 1-10000). With animated:true the input is read with sharp({animated:true}) so all frames of an animated GIF/WebP are resized + preserved (billed per-frame: pages × w · h). Billed per megapixel (`ceil(MP)` × `cputools.price.image.resize.per_mp_micros`). Output: uniform JSON envelope; output format follows the input.
Convert image format
$MeteredPOST https://api.relaystation.ai/v1/image/convert$0.0003/MP. Convert between PNG, JPEG, WebP, AVIF — HEIC accepted in, animation preserved with animated:true. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert to PNG/JPEG/WebP/AVIF (incl. HEIC→JPEG) via sharp. Body: { file, format: "png"|"jpeg"|"webp"|"avif", quality?: 1-100, animated?: bool }. With animated:true all frames of an animated input are preserved (gif/webp targets keep the stack; other targets flatten). Billed per megapixel (per-frame when animated). Output: uniform JSON envelope.
Compress an image
$MeteredPOST https://api.relaystation.ai/v1/image/compress$0.0003/MP. Re-encode an image at lower quality to shrink file size — bandwidth-friendly output. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Re-encode at a quality level, keeping the input format. Body: { file, quality?: 1-100 (default 80) }. Billed per megapixel. Output: uniform JSON envelope.
Rotate / flip an image
$MeteredPOST https://api.relaystation.ai/v1/image/rotate$0.0003/MP. Rotate or flip an image — any angle, mirrored or not. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Rotate 90/180/270° and/or flip/flop via sharp. Body: { file, angle?: "90"|"180"|"270", flip?: bool, flop?: bool } (at least one). Billed per megapixel. Output: uniform JSON envelope.
Read image metadata
$MeteredPOST https://api.relaystation.ai/v1/image/metadata$0.0005/call. Read dimensions, format, and EXIF presence — inspect before you process. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Read dimensions / format / EXIF presence via sharp. Body: { file }. FLAT price (`cputools.price.image.metadata.flat_micros`). Output: JSON `{ metadata: { width, height, format, space, channels, depth, density, hasAlpha, hasProfile, orientation, isProgressive, hasExif } }` — no bytes.
Crop an image region
$MeteredPOST https://api.relaystation.ai/v1/image/crop$0.0003/MP. Crop any region by coordinates — exact pixels out. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Crop a region. Body: { file, left, top, width, height }. Per-MP billed (`cputools.price.image.crop.per_mp_micros`). Out-of-bounds region → 422 CROP_OUT_OF_BOUNDS. Output: uniform JSON envelope (original format).
Blur an image
$MeteredPOST https://api.relaystation.ai/v1/image/blur$0.0003/MP. Gaussian-blur an image at the strength you set — backgrounds, redactions, thumbnails. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Gaussian blur. Body: { file, sigma? (0.3–1000, default 3) }. Per-MP billed (`cputools.price.image.blur.per_mp_micros`). Output: uniform JSON envelope.
Sharpen an image
$MeteredPOST https://api.relaystation.ai/v1/image/sharpen$0.0003/MP. Sharpen a soft image with adjustable strength — crisper scans, photos, thumbnails. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Sharpen. Body: { file, sigma? (default 1) }. Per-MP billed (`cputools.price.image.sharpen.per_mp_micros`). Output: uniform JSON envelope.
Grayscale an image
$MeteredPOST https://api.relaystation.ai/v1/image/grayscale$0.0003/MP. Convert any image to grayscale — one call, any input format. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert to grayscale. Body: { file }. Per-MP billed (`cputools.price.image.grayscale.per_mp_micros`). Output: uniform JSON envelope.
Strip image metadata
$MeteredPOST https://api.relaystation.ai/v1/image/exif-strip$0.0003/MP. Strip EXIF and metadata for privacy — auto-orients first so photos stay upright. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Strip EXIF/metadata (auto-orient, then drop all metadata; pixels + orientation preserved). Body: { file }. Per-MP billed (`cputools.price.image.exif-strip.per_mp_micros`). Output: uniform JSON envelope.
Dominant color of an image
$MeteredPOST https://api.relaystation.ai/v1/image/dominant-color$0.0002/call. Get an image's dominant color as hex/RGB — theming and palettes from any picture. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Get the dominant color (sharp stats). Body: { file }. FLAT-billed (`cputools.price.image.dominant-color.flat_micros`). Output: JSON `{ dominant: {r,g,b}, hex }`.
Composite / watermark images
$MeteredPOST https://api.relaystation.ai/v1/image/composite$0.0003/MP. Overlay or watermark one image onto another — position and blend control. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Overlay one image onto another. Body: { file (base), overlay, gravity? | (top,left), opacity? (0–1) }. Per-MP billed on the base (`cputools.price.image.composite.per_mp_micros`). Output: uniform JSON envelope (base format).
Thumbnail-grid contact sheet
$MeteredPOST https://api.relaystation.ai/v1/image/contact-sheet$0.0003/MP. Tile many images into one thumbnail-grid PNG — visual index in a single call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Tile images into a grid PNG. Body: { files: <source>[] (≤100), columns?, cellWidth?, cellHeight?, gap?, background? }. Per-MP billed on the total input (`cputools.price.image.contact-sheet.per_mp_micros`). Output: uniform JSON envelope (image/png).
Render HTML to an image (Chromium screenshot)
$MeteredPOST https://api.relaystation.ai/v1/image/from-html$0.003/call. Render HTML to an image — sandboxed headless Chromium screenshot of your markup. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render caller-supplied HTML to a png/jpeg/webp via page.screenshot on the SAME dedicated x86_64 Chromium render worker as pdf/from-html. Body: { html: string, type?: "png"|"jpeg"|"webp" (default png), fullPage?: bool, clip?: { x, y, width, height }, omitBackground?: bool, width?: int, height?: int }. SANDBOXED / SSRF-WALLED identically to pdf/from-html: NO network, NO JavaScript — every non-`data:` request is aborted, so ALL assets must be inlined as `data:` URIs (provided-HTML-only). `clip` and `fullPage` are mutually exclusive (400). `omitBackground` (transparent background) requires png/webp — with jpeg it 400s (jpeg has no alpha channel). Billed FLAT per render (`cputools.price.image.from-html.flat_micros`) — the output dimensions aren't known until after the render, so it cannot drive an x402 pre-auth. Output: uniform JSON envelope (image/png|jpeg|webp).
Adjust image color/tone
$MeteredPOST https://api.relaystation.ai/v1/image/adjust$0.0003/MP. Adjust brightness, saturation, hue, lightness — or negate and tint — in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Adjust brightness / saturation / hue / lightness / negate / tint via sharp (modulate bundle). Body: { file, brightness?: 0–10, saturation?: 0–10, hue?: -360–360 (degrees), lightness?: -100–100, negate?: bool, tint?: { r, g, b } } — at least one adjustment is required. Billed per megapixel (`cputools.price.image.adjust.per_mp_micros`). Output: uniform JSON envelope (original format).
Auto-crop uniform borders
$MeteredPOST https://api.relaystation.ai/v1/image/trim$0.0003/MP. Auto-crop uniform borders — clean edges without manual coordinates. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Trim uniform-color borders via sharp. Body: { file, threshold?: 0–255 (sensitivity; default sharp's) }. Billed per megapixel (`cputools.price.image.trim.per_mp_micros`). Output: uniform JSON envelope (original format).
Pad (extend) an image
$MeteredPOST https://api.relaystation.ai/v1/image/extend$0.0003/MP. Pad or extend an image's canvas on any side — aspect-ratio fixes without cropping. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Pad an image on any side via sharp. Body: { file, top?, bottom?, left?, right? (0–10000 px each; at least one positive), background?: "#rrggbb" | { r, g, b, alpha? }, extendWith?: "background"|"copy"|"repeat"|"mirror" }. Billed per megapixel (`cputools.price.image.extend.per_mp_micros`). Output: uniform JSON envelope (original format).
Convert tabular formats
$MeteredPOST https://api.relaystation.ai/v1/csv/convert$0.0002/MB. Convert tabular data between CSV, TSV, JSON, and NDJSON — structure preserved. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert between csv / tsv / json / ndjson via Papaparse. Body: { file: <source>, from?: "csv"|"tsv"|"json"|"ndjson" (default csv), to: <same enum>, delimiter? }. Billed PER MB of input (`cputools.price.csv.convert.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (text/csv | text/tab-separated-values | application/json | application/x-ndjson). Cells are data, never evaluated — no formula execution.
Drop duplicate rows
$MeteredPOST https://api.relaystation.ai/v1/csv/dedupe$0.0002/MB. Drop duplicate rows, order preserved — clean a dataset in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Remove duplicate rows from a CSV, order-preserving. Body: { file: <source>, columns?: string[] } — key columns to dedupe on; default is the whole row. Billed PER MB of input (`cputools.price.csv.dedupe.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (text/csv).
Project / reorder columns
$MeteredPOST https://api.relaystation.ai/v1/csv/select$0.0002/MB. Keep, drop, or reorder columns in a table — shape data for the next step. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Keep or drop CSV columns. Body: { file: <source>, columns?: string[] | drop?: string[] } — EXACTLY ONE; `columns` keeps + reorders, `drop` removes. Billed PER MB of input (`cputools.price.csv.select.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (text/csv).
Hash data
$MeteredPOST https://api.relaystation.ai/v1/utils/hash$0.0002/MB. Hash bytes with SHA-256, SHA-512, SHA-1, or MD5 — digests as hex. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Hash bytes with sha256 / sha512 / sha1 / md5 (Node crypto). Body: { data?: string | file?: <source> } — EXACTLY ONE — + { algo }. Billed PER MB of input (`cputools.price.utils.hash.per_mb_micros`, min 1 MiB). Output: JSON `{ algo, hash: <hex> }` — no bytes. (sha1/md5 provided for legacy checksum compatibility.)
HMAC data
$MeteredPOST https://api.relaystation.ai/v1/utils/hmac$0.0002/MB. Compute a keyed HMAC (SHA-256/512/1, MD5) — the key is never logged. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny HMAC bytes with a secret key (Node crypto; sha256 / sha512 / sha1 / md5). Body: { data?: string | file?: <source> } — EXACTLY ONE — + { key, algo }. Billed PER MB of input (`cputools.price.utils.hmac.per_mb_micros`, min 1 MiB). Output: JSON `{ algo, hmac: <hex> }`. The key is secret — never logged.
Generate UUIDs
$MeteredPOST https://api.relaystation.ai/v1/utils/uuid$0.0001/call. Generate v4 UUIDs — one or a batch. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate v4 UUIDs (Node crypto.randomUUID). Body: { version?: "v4", count?: int ≥1 }. FLAT-billed (`cputools.price.utils.uuid.flat_micros`). `count` is capped by `cputools.utils.uuid.max_count` (over → 422 COUNT_TOO_LARGE). Output: JSON `{ uuids: string[] }`.
Decode a JWT (no verification)
$MeteredPOST https://api.relaystation.ai/v1/utils/jwt-decode$0.0001/call. Decode a JWT's header and payload (no verification) — inspect claims fast. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Decode a JWT header + payload WITHOUT verifying the signature (jose). Body: { token }. FLAT-billed (`cputools.price.utils.jwt-decode.flat_micros`). Output: JSON `{ header, payload }`. A malformed token → 422 JWT_MALFORMED. To verify a signature use /v1/utils/jwt-verify.
Verify a JWT signature
$MeteredPOST https://api.relaystation.ai/v1/utils/jwt-verify$0.0001/call. Verify a JWT signature — algorithm-pinned; the key is never logged. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Verify a JWT signature, alg-pinned (jose). Body: { token, key, alg: HS256/384/512 | RS256/384/512 | ES256/384 }. The verify is pinned to the declared `alg` — blocks the alg-confusion / `alg:none` downgrade. FLAT-billed (`cputools.price.utils.jwt-verify.flat_micros`). A valid-shape token that fails verification is a PAID answer: 200 `{ valid: false, reason }`. Only an unparseable token → 422 JWT_MALFORMED; an unimportable key → 422 JWT_KEY_INVALID. The key is secret — never logged. Output: JSON `{ valid, payload? | reason? }`.
Base64 encode / decode
$MeteredPOST https://api.relaystation.ai/v1/utils/base64$0.0002/MB. Base64 encode or decode a string — simple, bounded, fast. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Base64 encode or decode a string (Node Buffer). Body: { data, mode: "encode" | "decode" }. Billed PER MB of the input `data` (`cputools.price.utils.base64.per_mb_micros`, min 1 MiB). Output: JSON `{ data: <result> }`.
Render an OG / social-card image
$MeteredPOST https://api.relaystation.ai/v1/generate/og-image$0.0005/call. Render social/OG card PNGs — titles, colors, branding — for links that get clicked. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a clean social-card PNG (satori → SVG → sharp). Body: { title, subtitle?, theme?: "light"|"dark", width?: 600-2000, height?: 300-1200 }. FLAT-billed (`cputools.price.generate.og-image.flat_micros`). Output: uniform JSON envelope (image/png, inline base64).
Generate fake / mock data
$MeteredPOST https://api.relaystation.ai/v1/generate/mock-data$0.0002/call. Generate realistic fake rows from a field→type schema (JSON/CSV/NDJSON) — test data on demand. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate fake rows from a field→type schema (@faker-js/faker). Body: { schema: { <field>: <type> }, count: int ≥1, format?: "json"|"csv"|"ndjson" }. Types: name, firstName, lastName, email, uuid, int, float, bool, date, address, city, country, phone, company, url, word, sentence, paragraph (unknown → 422 UNSUPPORTED_TYPE). `count` ≤ `cputools.generate.mock-data.max_rows`, fields ≤ `cputools.generate.mock-data.max_fields`. FLAT-billed (`cputools.price.generate.mock-data.flat_micros`). Output: uniform JSON envelope (application/json | text/csv | application/x-ndjson).
Render an invoice PDF
$MeteredPOST https://api.relaystation.ai/v1/generate/invoice$0.0002/call. Render a clean invoice PDF from structured JSON — line items, totals, branding. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a clean invoice PDF from structured data (pdf-lib). Body: { seller, buyer, items:[{description,quantity,unitPrice}] (1-100), number?, date?, currency?, taxRate?: 0-100, notes? }. Computes subtotal/tax/total. FLAT-billed (`cputools.price.generate.invoice.flat_micros`). Output: uniform JSON envelope (application/pdf).
Render a bar / line / pie chart
$MeteredPOST https://api.relaystation.ai/v1/generate/chart$0.0002/call. Render bar, line, or pie charts to PNG from JSON data — report-ready images in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a chart PNG from data points (hand-rolled SVG → sharp; no chart-lib). Body: { type: "bar"|"line"|"pie", data:[{label,value}] (1-50), title?, width?: 200-2000, height?: 150-2000, color? }. FLAT-billed (`cputools.price.generate.chart.flat_micros`). Output: uniform JSON envelope (image/png).
Render a QR code with a centered logo
$MeteredPOST https://api.relaystation.ai/v1/generate/qr-logo$0.0002/call. QR code with your logo composited in the center (ECC H — still scans reliably). 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a QR code (ECC level H) with a logo composited in the center (qrcode → sharp.composite, white-padded for scan contrast). Body: { data, logo: <source> (image), size?: 128-2000, margin?: 0-16, logoScale?: 0.1-0.35 }. FLAT-billed (`cputools.price.generate.qr-logo.flat_micros`). Output: uniform JSON envelope (image/png).
Generate a favicon set
$MeteredPOST https://api.relaystation.ai/v1/generate/favicon$0.0002/call. Generate a complete favicon set (PNGs) from an image or initials text. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate a favicon set (PNGs at several sizes) from EITHER an image OR initials text. Body: exactly one of { image: <source> } or { text: 1-3 chars }, plus background?, color?, sizes?: int[8-512] (default [16,32,48,180]). FLAT-billed (`cputools.price.generate.favicon.flat_micros`). Output: { icons: [{ size, output }] } — each output a uniform envelope.
Render a placeholder image
$MeteredPOST https://api.relaystation.ai/v1/generate/placeholder$0.0002/call. Placeholder images at any size with label text — PNG or SVG. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a placeholder image (solid background + centered dimensions/label text; hand-rolled SVG). Body: { width: 8-4000, height: 8-4000, background?, color?, text? (default "W×H"), format?: "png"|"svg" }. FLAT-billed (`cputools.price.generate.placeholder.flat_micros`). Output: uniform JSON envelope (image/png | image/svg+xml).
Render a deterministic identicon
$MeteredPOST https://api.relaystation.ai/v1/generate/identicon$0.0002/call. Deterministic GitHub-style identicon PNG from any seed string — stable avatars for users or agents. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a deterministic GitHub-style 5×5 mirror-symmetric identicon PNG from a seed (sha256 → color + cell grid; same seed → same image). Body: { seed, size?: 32-1024, background? }. FLAT-billed (`cputools.price.generate.identicon.flat_micros`). Output: uniform JSON envelope (image/png).
Create a zip archive
$MeteredPOST https://api.relaystation.ai/v1/archive/zip$0.0002/MB. Zip any set of files into one downloadable archive — pass URLs or payloads, get a link back. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Zip 1+ files into a single archive (fflate, in-memory). Body: { files: <source>[] (≥1, ≤ cputools.archive.max_files_per_zip), filenames?: string[] (must match files.length) }. Filenames are reduced to a sanitized basename (no path traversal); collisions get a `-N` suffix. Billed PER MB of total input (`cputools.price.archive.zip.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (application/zip).
Recase text
$MeteredPOST https://api.relaystation.ai/v1/text/case$0.0002/MB. Recase text — upper, lower, title, camel, snake, kebab. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Recase text. Body: { text?: string | file?: <source> } (EXACTLY ONE) + { to: "upper"|"lower"|"title"|"camel"|"snake"|"kebab" }. Billed PER MB of input (`cputools.price.text.case.per_mb_micros`, min 1 MiB). Output: JSON `{ result }`.
Slugify text
$MeteredPOST https://api.relaystation.ai/v1/text/slugify$0.0002/MB. URL-slugify text — strip diacritics, hyphenate, lowercase. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Slugify text (lowercase, strip diacritics, non-alphanumeric → separator). Body: { text? | file?, separator? (default "-") }. Billed PER MB (`cputools.price.text.slugify.per_mb_micros`). Output: JSON `{ slug }`.
Unified text diff
$MeteredPOST https://api.relaystation.ai/v1/text/diff$0.0002/MB. Unified diff of two strings — see exactly what changed. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Unified diff of two strings (jsdiff). Body: { a, b, filenameA?, filenameB?, context? (default 3) }. Billed PER MB of a+b (`cputools.price.text.diff.per_mb_micros`). Output: JSON `{ patch, changed }`.
Apply a unified diff to a source string
$MeteredPOST https://api.relaystation.ai/v1/text/apply-patch$0.0002/MB. Apply a unified diff to a source string — 422 on context mismatch, never a silent bad merge. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Apply a unified diff (the patch text/diff produces) to a source string (jsdiff applyPatch). Body: { source: string, patch: string }. A context mismatch (the patch doesn't apply cleanly) is a clean 422 PATCH_CONFLICT (the per-MB charge is refunded). Billed PER MB of source+patch (`cputools.price.text.apply-patch.per_mb_micros`). Output: JSON `{ result }`.
Three-way merge
$MeteredPOST https://api.relaystation.ai/v1/text/merge3$0.0002/MB. Three-way merge of two edits against a common base — conflict markers on overlap. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Three-way merge of two changes against a common base (node-diff3). Body: { base: string, yours: string, theirs: string }. A clean merge returns the merged string + conflict:false; overlapping edits return the merged string WITH conflict markers (<<<<<<< / ||||||| / ======= / >>>>>>>) + conflict:true — the markers ARE the useful output, NOT an error. Billed PER MB of base+yours+theirs (`cputools.price.text.merge3.per_mb_micros`). Output: JSON `{ merged, conflict }`.
Count characters / words / lines
$MeteredPOST https://api.relaystation.ai/v1/text/count$0.0002/MB. Count characters, words, and lines — plus reading time. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Count characters / words / lines + reading time. Body: { text? | file?, wpm? (default 200) }. Billed PER MB (`cputools.price.text.count.per_mb_micros`). Output: JSON `{ characters, charactersNoSpaces, words, lines, readingTimeMinutes }`.
Extract regex matches (ReDoS-guarded)
$MeteredPOST https://api.relaystation.ai/v1/text/regex-extract$0.0002/MB. Extract regex matches from text — ReDoS-guarded, patterns and input bounded. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract regex matches. Body: { text? | file?, pattern, flags? ([gimsuy]), maxMatches? }. The pattern is rejected pre-charge if it carries catastrophic-backtracking risk (422 UNSAFE_REGEX); the input is byte-capped and the match count bounded (no in-engine timeout — defense is reject-pattern + bound-everything). Billed PER MB (`cputools.price.text.regex-extract.per_mb_micros`). Output: JSON `{ matches: [{ match, index, groups, namedGroups? }], count, truncated }`.
Render a logic-less template (no eval)
$MeteredPOST https://api.relaystation.ai/v1/text/template$0.0002/MB. Render a logic-less mustache-subset template — no eval, injection-safe. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a logic-less mustache-subset template — NO eval: {{var}} (HTML-escaped), {{{raw}}}, {{#section}}…{{/section}}, {{^inverted}}…{{/inverted}}; own-property lookups only (no prototype access). Body: { template, data: object, escape? (default true) }. Billed PER MB of template+data (`cputools.price.text.template.per_mb_micros`). Output: JSON `{ result }`.
Markdown → sanitized HTML
$MeteredPOST https://api.relaystation.ai/v1/text/markdown-to-html$0.0002/MB. Convert markdown to HTML — always whitelist-sanitized, safe to embed. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render Markdown (GFM) → HTML (marked), ALWAYS run through the whitelist sanitizer (script + unsafe schemes stripped). Body: { text? | file? }. Billed PER MB (`cputools.price.text.markdown-to-html.per_mb_micros`). Output: JSON `{ html }`.
HTML → plain text
$MeteredPOST https://api.relaystation.ai/v1/text/html-to-text$0.0002/MB. Convert HTML to clean plain text — strip markup for LLM input or search. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert HTML → plain text (html-to-text). Body: { text? | file?, wordwrap? (number | false) }. Billed PER MB (`cputools.price.text.html-to-text.per_mb_micros`). Output: JSON `{ text }`.
Sanitize HTML (whitelist)
$MeteredPOST https://api.relaystation.ai/v1/text/sanitize-html$0.0002/MB. Sanitize HTML against a safe whitelist — kill scripts and XSS before embedding. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Sanitize HTML against a whitelist (safe tags/attrs; http/https/mailto only; script/style/event-handlers stripped). Body: { text? | file? }. Billed PER MB (`cputools.price.text.sanitize-html.per_mb_micros`). Output: JSON `{ html }`.
Decode a QR code from an image
$MeteredPOST https://api.relaystation.ai/v1/codes/qr-decode$0.0002/call. Decode a QR code from an image — the embedded text or URL back as JSON. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Read a QR code from an uploaded image (sharp decode → raw RGBA → jsqr). Body: { file: <source> }. FLAT-billed (`cputools.price.codes.qr-decode.flat_micros`). A non-decodable image is a PAID 200 `{ found: false }`; a non-image → 422 IMAGE_PARSE_FAILED. Output: JSON `{ found, data?, version? }`.
Convert a color (hex/rgb/hsl)
$MeteredPOST https://api.relaystation.ai/v1/codes/color-convert$0.0002/call. Convert colors between hex, RGB, and HSL — exact values back as JSON. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert a color between hex / rgb / hsl (incl. alpha forms). Body: { color, to: "hex"|"rgb"|"hsl" }. FLAT-billed (`cputools.price.codes.color-convert.flat_micros`). Unrecognized color → 422 COLOR_INVALID. Output: JSON `{ input, to, result, rgb }`.
Filter rows by a structured predicate
$MeteredPOST https://api.relaystation.ai/v1/data/filter$0.0002/MB. Keep rows matching a structured predicate — injection-safe, no formula eval. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Filter rows with a STRUCTURED predicate tree — no expression evaluation. Body: { file: <source>, where: Predicate, from?, to? }. Predicate = { column, op, value? } | { and: [...] } | { or: [...] } | { not: ... }; op ∈ eq/ne/gt/gte/lt/lte/contains/startsWith/endsWith/in/isNull/notNull. Comparisons are value-typed (numeric when both sides parse as finite numbers, else string). Nesting is depth-capped (`cputools.data.max_predicate_depth`). Billed PER MB of input (`cputools.price.data.filter.per_mb_micros`, min 1 MiB). Output: uniform text envelope (default csv).
Sort rows by columns
$MeteredPOST https://api.relaystation.ai/v1/data/sort$0.0002/MB. Sort rows by one or more columns, ascending or descending. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Stable multi-key sort. Body: { file: <source>, by: [{ column, dir?: asc|desc, type?: string|number }], from?, to? }. `type` forces numeric/string compare; default is value-typed (numeric when both parse, else string). Billed PER MB of input (`cputools.price.data.sort.per_mb_micros`, min 1 MiB). Output: uniform text envelope.
Group rows and aggregate
$MeteredPOST https://api.relaystation.ai/v1/data/groupby$0.0002/MB. Group rows and aggregate — count, sum, avg, min, max — in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Group by columns and apply named aggregates — no expression evaluation. Body: { file: <source>, by: string[] (≥1), aggregate: [{ column?, fn: count|sum|avg|min|max|first|last, as? }], from?, to? }. `count` needs no column; the rest require one. Billed PER MB of input (`cputools.price.data.groupby.per_mb_micros`, min 1 MiB). Output bounded by `cputools.data.max_output_bytes` / `max_output_rows`. Output: uniform text envelope.
Join two tables
$MeteredPOST https://api.relaystation.ai/v1/data/join$0.0002/MB. Join two tables by key — inner, left, right, or outer. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Hash-join two tables on key columns. Body: { left: <source>, right: <source>, on: [{ left, right }] (≥1), how?: inner|left|right|outer, from?, to? }. Output schema = left fields then right fields (a right name colliding with a left name is suffixed `_right`). A many-to-many join is bounded by the running output-byte/row cap (`cputools.data.max_output_bytes` / `max_output_rows`) → 422 OUTPUT_TOO_LARGE (the cartesian-blowup guard). Billed PER MB of the SUM of both inputs (`cputools.price.data.join.per_mb_micros`, min 1 MiB). Output: uniform text envelope.
Concatenate tables
$MeteredPOST https://api.relaystation.ai/v1/data/union$0.0002/MB. Concatenate tables with an ordered key-union schema — stack datasets safely. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Concatenate 2+ tables, order-preserving; schema is the ordered union of all keys (missing cells → empty). Body: { files: <source>[] (≥2, ≤ cputools.data.max_inputs), from?, to? }. Billed PER MB of the SUM of inputs (`cputools.price.data.union.per_mb_micros`, min 1 MiB). Output bounded by `cputools.data.max_output_bytes` / `max_output_rows`. Output: uniform text envelope.
Profile a table
$MeteredPOST https://api.relaystation.ai/v1/data/profile$0.0002/MB. Instant dataset profile — column types, null counts, cardinality, min/max/mean — before you commit to processing. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Profile each column: inferred type, count, nullCount, distinctCount, min, max, mean (numeric only), topK. Body: { file: <source>, from? }. Billed PER MB of input (`cputools.price.data.profile.per_mb_micros`, min 1 MiB). Output: plain JSON report `{ rowCount, columnCount, columns: [...] }` — no file envelope.
Run SQL over a file (DuckDB)
$MeteredPOST https://api.relaystation.ai/v1/data/sql$0.0005/MB. Query any CSV/JSON/parquet file with full SQL — sandboxed read-only DuckDB, parquet in and out. A serverless query engine for a fraction of a cent. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Run a full DuckDB SQL query, READ-ONLY over your uploaded file, in a sandboxed worker. Body: { file: <source>, sql: string, from?: "csv"|"json"|"ndjson"|"parquet", to?: "csv"|"json"|"parquet" }. Your file is loaded as a table named `input`; the query runs with all external access locked off — no file/network/extension/COPY/ATTACH access (sandbox: load-then-latch, `enable_external_access=false` + `lock_configuration=true`; CLI dot-commands rejected). A gzip-compressed input is detected by its magic bytes and decompressed transparently for csv/json/ndjson (Brief 194 — no flag needed). Bounded by memory_limit / a hard timeout / an output-byte cap. csv/json results return inline text; `to: "parquet"` (Brief 187) returns BINARY parquet — it rides the storage-ref output envelope ({ output: { outputKey, outputUrl, … } }) and is produced by a SAFE two-step that never touches the user-SQL sandbox. Billed PER MB of input (`cputools.price.data.sql.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (text/csv, application/json, or application/octet-stream for parquet).
Run a pipeline of cputools transforms in one call
$MeteredPOST https://api.relaystation.ai/v1/pipeline$0/call + sum of steps. Chain multiple ops — OCR → extract → convert → store — in one server-side call: one payment, one result, no intermediate downloads. The glue for 155 Relaystation tools on one balance — relaystation.ai Run a linear sequence of cputools transforms in ONE call, threading bytes step-to-step in-process (the ETL-T moat — per-call composition). Body: { file: <source>, steps: [{ op: "<category>.<op>", args }], to?: "csv"|"tsv"|"json"|"ndjson" }. Composable ops — tabular: csv.convert/dedupe/select, data.filter/sort/groupby/cast/pivot/derive/fillna/dropna/rename/slice/explode; format bridges: data.from-xlsx (start from an Excel file) / data.to-xlsx (end in one); binary: image.resize/convert/compress/rotate, utils.base64, archive.gzip; terminal (must be last): data.profile/validate/schema-infer. Each step's `args` is that op's schema minus `file` (bytes are threaded). Tabular intermediates are canonical CSV (`to` sets the final tabular format); binary ops (incl. to-xlsx) thread self-describing bytes (the final content-type follows the last step). Multi-input (data.join/union/diff) + worker (data.sql) ops are NOT composable. Billed as the SUM of the steps (each per-MB on the input size, via the existing per-op tunables) + `cputools.price.pipeline.run.flat_micros`. Output: uniform JSON envelope. A type-mismatched chain or mid-pipeline error refunds the whole charge (atomic).
Coerce column types
$MeteredPOST https://api.relaystation.ai/v1/data/cast$0.0002/MB. Coerce column types (string, integer, number, boolean, date) — stop fighting stringly-typed data. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Best-effort per-column type coercion (a non-coercible cell → null). Body: { file: <source>, columns: [{ column, to: "string"|"integer"|"number"|"boolean"|"date" }], from?, to? }. Billed PER MB of input (`cputools.price.data.cast.per_mb_micros`, min 1 MiB). Output: uniform JSON envelope (the re-typed table).
Pivot / unpivot a table
$MeteredPOST https://api.relaystation.ai/v1/data/pivot$0.0002/MB. Reshape tables long↔wide — pivot and unpivot without a spreadsheet. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Reshape a table. pivot (long→wide): { file, mode:"pivot", index: string[], columns: string, values: string, agg?: count|sum|avg|min|max }. unpivot/melt (wide→long): { file, mode:"unpivot", id: string[], value?: string[] } → { ...id, variable, value }. Billed PER MB of input (`cputools.price.data.pivot.per_mb_micros`, min 1 MiB). Output bounded by `cputools.data.max_output_bytes`. Output: uniform JSON envelope.
Infer a schema from a table
$MeteredPOST https://api.relaystation.ai/v1/data/schema-infer$0.0002/MB. Infer a JSON Schema or SQL DDL straight from your data — skip hand-writing schemas. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Infer per-column types from the sample and emit a schema. Body: { file: <source>, from?, dialect?: "json-schema"|"sql-ddl" }. Billed PER MB of input (`cputools.price.data.schema-infer.per_mb_micros`, min 1 MiB). Output: a JSON report { dialect, columnCount, schema } — a JSON Schema object or a CREATE TABLE statement.
Validate a table against a structured schema
$MeteredPOST https://api.relaystation.ai/v1/data/validate$0.0002/MB. Validate rows against a structured schema — row-level errors back as JSON. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Validate rows against a STRUCTURED schema — no expression eval (`pattern` is a bounded, length-capped RegExp over cell strings, never code). Body: { file: <source>, schema: { <col>: { type?, required?, min?, max?, pattern? } }, from? }. Billed PER MB of input (`cputools.price.data.validate.per_mb_micros`, min 1 MiB). An invalid/over-long `pattern` → 422 BAD_PATTERN (pre-charge). Output: a JSON report { valid, rowCount, errorCount, truncated, errors: [{ row, column, reason }] } (errors list capped).
Diff two tables (row-level changeset)
$MeteredPOST https://api.relaystation.ai/v1/data/diff$0.0002/MB. Row-level changeset between two tables — added, removed, and changed rows. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Row-level changeset between two tables. Body: { left: <source>, right: <source>, key?: string[], from? }. Keyed by `key` columns (added/removed/changed) or whole-row identity (added/removed). Billed PER MB of the SUM of inputs (`cputools.price.data.diff.per_mb_micros`, min 1 MiB). Output bounded by `cputools.data.max_output_bytes`. Output: a JSON report { addedCount, removedCount, changedCount, added, removed, changed }.
Parse Excel (.xlsx) → table
$MeteredPOST https://api.relaystation.ai/v1/data/from-xlsx$0.0002/MB. Parse an Excel file into CSV/JSON — sheets, headers, and types handled. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Parse an Excel workbook into a table (the first row is the header). Body: { file: <xlsx source>, sheet?: name|index (default the first sheet), to?: "csv"|"tsv"|"json"|"ndjson" }. Reads cell VALUES — a formula cell yields its cached result, never the formula (read = data). Bounded by `cputools.data.max_xlsx_cells` via a streaming read (a cell-bomb → 422 XLSX_TOO_LARGE, never an OOM); no external entities are resolved (no XXE/SSRF). Billed PER MB of input. Output: the uniform JSON envelope.
Emit a table as Excel (.xlsx)
$MeteredPOST https://api.relaystation.ai/v1/data/to-xlsx$0.0002/MB. Write tables to styled, multi-sheet Excel (.xlsx) — formula-injection-safe. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Emit a table as an Excel .xlsx (the format DuckDB/CSV cannot produce). Single-sheet: { file: <csv/json/ndjson source>, from?, sheetName? }. Multi-sheet (Brief 187): { sheets: [{ name, file, from? }, …] } (provide EXACTLY one of `file` or `sheets`, ≤ 20 sheets; billed over the SUM of all sheets' input bytes). Optional `style`: { headerBold?, freezeHeader?, columnWidths?: number[] | { <col>: number }, numberFormats?: { <col>: <Excel format string> } }. FORMULA-INJECTION-SAFE write: a cell whose value starts with `= + - @ \t \r` is written as a TEXT-typed string cell (never an active Excel `<f>` formula), so the value is preserved AND inert in the recipient's Excel. Billed PER MB of input. Output: the uniform JSON envelope (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).
Add computed columns (structured, no-eval)
$MeteredPOST https://api.relaystation.ai/v1/data/derive$0.0002/MB. Add computed columns from structured expressions — injection-safe, no formula eval. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Add computed columns from a STRUCTURED expression tree — NO expression eval. Body: { file: <source>, columns: [{ name, expr }], from?, to? }. `expr = { col } | { lit } | { op, args[] }`, depth-bounded (`cputools.data.derive_max_depth`); op allowlist: arithmetic (add/sub/mul/div/mod/abs/round), string (concat/upper/lower/trim/substring), coalesce, comparison (eq/ne/gt/gte/lt/lte). Values are inert literals, ops are enum-dispatched — never `eval`/`new Function`. div/mod by zero → null. Billed PER MB of input.
Fill empty/null cells
$MeteredPOST https://api.relaystation.ai/v1/data/fillna$0.0002/MB. Fill empty cells by value, forward/backward fill, mean, median, or mode. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Fill empty/null cells. Body: { file: <source>, columns?: string[] (default all), value: <scalar> | "ffill" | "bfill" | "mean" | "median" | "mode", from?, to? }. Billed PER MB of input. Output: the filled table (JSON envelope).
Drop rows with empty cells
$MeteredPOST https://api.relaystation.ai/v1/data/dropna$0.0002/MB. Drop rows with empty cells — one-call data cleaning. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Drop rows with empty/null cells. Body: { file: <source>, columns?: string[] (default all), how?: "any" (default) | "all", from?, to? }. Billed PER MB of input. Output: the surviving rows (JSON envelope).
Rename columns
$MeteredPOST https://api.relaystation.ai/v1/data/rename$0.0002/MB. Rename columns by mapping — tidy schemas between pipeline steps. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Rename columns. Body: { file: <source>, columns: [{ from, to }], from?, to? }. A reserved or duplicate target name → 422. Billed PER MB of input. Output: the renamed table (JSON envelope).
Slice / sample rows
$MeteredPOST https://api.relaystation.ai/v1/data/slice$0.0002/MB. Slice rows — offset, limit, head, tail — for paging or previews. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Slice or sample rows. Body: { file: <source>, offset?, limit?, head?, tail?, sample? (random n), from?, to? }. offset/limit/head/tail are deterministic; `sample` is a random n (non-deterministic). Billed PER MB of input. Output: the selected rows (JSON envelope).
Explode a list cell into rows
$MeteredPOST https://api.relaystation.ai/v1/data/explode$0.0002/MB. Unnest array cells into rows — flatten nested JSON for analysis. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Unnest one cell's list into multiple rows. Body: { file: <source>, column, separator? (default: parse the cell as a JSON array; else split the string on `separator`), from?, to? }. Billed PER MB of input. Output bounded by `cputools.data.max_output_bytes`. Output: the exploded rows (JSON envelope).
Sample rows from a dataset
$MeteredPOST https://api.relaystation.ai/v1/data/sample$0.0002/MB. Sample rows — n or fraction; random, head, or systematic; reproducible seed. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Sample rows. Body: exactly one of { n: int } or { fraction: 0-1 }, plus method?: "random"|"head"|"systematic" (default random), seed?: int (REPRODUCIBLE random — same seed + input → identical sample), file: <source>, from?, to?. The sample preserves original row order. Billed PER MB of input (`cputools.price.data.sample.per_mb_micros`). Output: the sampled rows (JSON envelope).
Ask (blocking)
$MeteredPOST https://api.relaystation.ai/v1/bridge/askSend a question to the human operator and enqueue a pending_ask for reply. Returns a ticket the agent (or the @relaystation/mcp wrapper) polls via GET /v1/bridge/ask/{ticket}/check. Free tier: 5 telegram + 2 email/day per customer. Over-cap calls debit at bridge.price.<channel>_message_micros. x402-authed first calls auto-create the customers row (kind=wallet). When the bridge is toggled off (set_bridge_active=false), returns 200 {status: "bridge_inactive"} without enqueueing.
Notify (fire-and-forget)
$MeteredPOST https://api.relaystation.ai/v1/bridge/notifySend a one-way status update to the operator. No reply expected. Same free-tier and pricing as ask. Soft-fail on insufficient_funds: returns 200 {status: "free_tier_only"} so the agent's continuation surfaces upgrade copy rather than a hard 402.
Mint an ephemeral agent address
$MeteredPOST https://api.relaystation.ai/v1/bridge/agent-addressMint a random `<local_part>@courier.relaystation.ai` ephemeral address for agent-to-agent messaging (~67 bits of entropy in the local part — unguessable, so cross-customer spam is mathematically infeasible). Free up to `bridge.agent_address.daily_mint_cap_per_customer` per UTC day; above-cap mints debit `bridge.agent_address.create` (x402-authed first calls auto-create the customers row). Idempotency-Key required on the over-cap (billable) path.
Send a document for signature
$MeteredPOST https://api.relaystation.ai/v1/esigndoc/envelopes$0.05/envelope. Send any PDF, Word doc, or markdown for legally binding e-signature — hosted signing links, ordered multi-signer routing, approvers, templates, live status, signed-copy retrieval. DocuSign-class workflow at a fraction of the price, one of 155 Relaystation tools on one balance — relaystation.ai Create a signing envelope from a PDF + recipients. Two body shapes: multipart/form-data (a `payload` JSON-string field + a `pdf` File), or application/json (the payload fields at the top level + `pdf` as the cputools input-source: { inline: <base64 ≤ 4 MiB> } or { inputKey: <scratch key from /v1/cputools/upload-url> }). Billable (esign.envelope) ONLY when the create also sends — i.e. `fields` is non-empty or `autoPlaceSignature: true`; a draft create (no fields) is free. Charge-on-successful-send, no refund. Idempotency-Key honored.
Send a document for signature from a reusable template
$MeteredPOST https://api.relaystation.ai/v1/esigndoc/envelopes/from-templateInstantiate an envelope from a stored template, binding recipient placeholders to real addresses. Billable (esign.envelope) ONLY when `sendImmediately: true` (otherwise a free draft). Charge-on-successful-send, no refund. Idempotency-Key honored.
Send a prepared draft for signature
$MeteredPOST https://api.relaystation.ai/v1/esigndoc/envelopes/{id}/sendDistribute a DRAFT envelope to its recipients. Billable (esign.envelope), charge-on-successful-send, no refund. Optional `meta` overrides the email subject/message/redirect.
Verify a government ID, run a liveness check, or match a face (by type)
$MeteredPOST https://api.relaystation.ai/v1/idverify/verifications$0.10/verification. Full KYC in one call — government-ID verification, liveness detection, and face-to-ID matching. Pair with /v1/esigndoc for verify-then-sign and /v1/screening for sanctions. One of 155 Relaystation tools on one balance — relaystation.ai Initialize a hosted identity verification. Returns a `hostedUrl` the end-user opens to complete capture; the outcome arrives via webhook (verification.* events) or GET …/status poll. Billable (idverify.verification), charge-on-attempt — the charge stands once the upstream verification is initialized; the async verdict (VERIFIED/REJECTED/FAILED/EXPIRED) never refunds. A throw before initialize (upstream unreachable, soft-gate rejection) reverses the charge. Idempotency-Key honored.
Screen a name against sanctions + PEP watchlists
$MeteredPOST https://api.relaystation.ai/v1/screening/match$0.01/screen. Screen any name against OFAC, EU, and UK sanctions (UN included) plus Wikidata-derived PEP watchlists — fuzzy matching, instant JSON verdict. Compliance in one call, one of 155 Relaystation tools on one balance — relaystation.ai Fuzzy-match a person or organization name against international sanctions lists (OFAC SDN/Consolidated, EU consolidated, UK FCDO — UN coverage rides along inside these) AND politically-exposed-persons (PEP) data derived from Wikidata. Billable (screening.match), charge-on-attempt — the charge stands whether or not there is a hit. Trigram similarity handles aliases, transliteration, and name-order. Use `lists` to scope to sanctions or PEP (default both). Idempotency-Key honored. Source attribution (EU reuse policy / UK OGL v3.0 / Wikidata CC0) is returned in every response. PEP coverage (v1) is national-level heads of state/government, cabinet ministers, and senior judges (current + recently in office) from Wikidata — NOT a complete FATF PEP universe (standalone legislators, central-bank governors, ambassadors, party officials, SOE executives, and relatives/close associates are not yet covered).
Geocode a free-text address
$MeteredPOST https://api.relaystation.ai/v1/location/geocode$0.005/lookup. Geocode a free-text address to coordinates (AWS Location Service) — lat/lng plus normalized address. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Geocode a free-text address/place description to coordinates (AWS Location Service). Body: { query, maxResults?: 1-20, language?, biasPosition?: [lng,lat], countries?: [ISO-3166 alpha-3] }. FLAT-billed per call (location.price.geocode tunable). Returns { results: [...] } — an empty array when nothing matches (never an error). Idempotency-Key required on billable calls.
Reverse-geocode coordinates to an address
$MeteredPOST https://api.relaystation.ai/v1/location/reverse-geocode$0.005/lookup. Reverse-geocode coordinates to the nearest address — lat/lng in, street address out. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Reverse-geocode WGS-84 coordinates to the nearest address(es) (AWS Location Service). Body: { position: [lng,lat], maxResults?: 1-20, radiusMeters?, language? }. FLAT-billed per call (location.price.reverse_geocode tunable). Returns { results: [...] } — empty when nothing is nearby.
Search places / points of interest
$MeteredPOST https://api.relaystation.ai/v1/location/place-search$0.01/search. Free-text place and point-of-interest search — names, addresses, coordinates back as JSON. 155 tools, one balance — relaystation.ai Free-text place/POI search (AWS Location Service SearchText). Body: { query, biasPosition?: [lng,lat], maxResults?: 1-20, language?, countries? }. FLAT-billed per call (location.price.place_search tunable). Returns { results: [...] } — empty when nothing matches.
Calculate a route between two points
$MeteredPOST https://api.relaystation.ai/v1/location/route$0.01/route. Calculate a route between two points — distance, duration, and geometry back as JSON. 155 tools, one balance — relaystation.ai Calculate a route (AWS Location Service CalculateRoutes). Body: { origin: [lng,lat], destination: [lng,lat], travelMode?: "Car"|"Truck"|"Pedestrian"|"Scooter", departNow? }. FLAT-billed per call (location.price.route tunable). Returns the route set (legs, distance meters, duration seconds, encoded geometry).
OCR a document with line/word layout
$MeteredPOST https://api.relaystation.ai/v1/doc/ocr-layout$0.010/document. OCR a document with line- and word-level layout coordinates (Textract) — position-aware text for downstream parsing. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny OCR a SINGLE-PAGE document (image or 1-page PDF ≤ 5 MB) with line+word layout geometry (AWS Textract DetectDocumentText). Body: { file: <source> }. Multi-page/oversize → 422 pre-charge (multi-page analysis arrives with the async lane). FLAT-billed per document (docai.price.detect_text tunable). Returns { blocks: [...] } (PAGE/LINE/WORD blocks).
Extract form key→value pairs
$MeteredPOST https://api.relaystation.ai/v1/doc/extract-form$0.28/document. Extract form fields as key→value pairs from scanned or digital documents (Textract Forms) — structured JSON out, no template needed. 155 tools, one balance — relaystation.ai Extract form fields (key→value pairs) from a SINGLE-PAGE document (AWS Textract AnalyzeDocument FORMS). Body: { file: <source> } (image or 1-page PDF ≤ 5 MB). FLAT-billed per document (docai.price.extract_form tunable). Returns { fields: [{key, value, confidence}], blocks }.
Extract tables from a document
$MeteredPOST https://api.relaystation.ai/v1/doc/extract-tables$0.08/document. Pull tables out of a document as structured rows and columns (Textract Tables) — not text soup. 155 tools, one balance — relaystation.ai Extract tables from a SINGLE-PAGE document (AWS Textract AnalyzeDocument TABLES). Body: { file: <source> } (image or 1-page PDF ≤ 5 MB). FLAT-billed per document (docai.price.extract_tables tunable). Returns { tables: [{rows: [[cell,...]]}], blocks }.
Parse an invoice/receipt into structured fields
$MeteredPOST https://api.relaystation.ai/v1/doc/parse-invoice$0.055/document. Parse invoices and receipts into summary fields plus line items (Textract AnalyzeExpense) — vendor, totals, dates, SKUs. 155 tools, one balance — relaystation.ai Parse an invoice or receipt into summary fields + line items (AWS Textract AnalyzeExpense). Body: { file: <source> } (image or 1-page PDF ≤ 5 MB). FLAT-billed per document (docai.price.parse_invoice tunable). Returns { documents: [{summaryFields, lineItems}] }.
Parse a government identity document
$MeteredPOST https://api.relaystation.ai/v1/doc/parse-id$0.05/document. Parse a government ID (passport, license) into typed fields (Textract AnalyzeID). Parsing only — for verification + liveness use /v1/idverify. 155 tools, one balance — relaystation.ai Parse a government identity document (driver's license / passport page image ≤ 5 MB) into typed fields (AWS Textract AnalyzeID). Body: { file: <source> }. FLAT-billed per document (docai.price.parse_id tunable). Returns { documents: [{fields: [{type, value, confidence}]}] }. This is a document-parsing utility, NOT identity verification — for KYC use POST /v1/idverify/verifications.
Ask natural-language questions of a document
$MeteredPOST https://api.relaystation.ai/v1/doc/ask-document$0.08/document. Ask natural-language questions of a document and get grounded answers (Textract Queries) — no OCR pipeline to build. 155 tools, one balance — relaystation.ai Ask up to 15 natural-language questions of a SINGLE-PAGE document (AWS Textract AnalyzeDocument QUERIES). Body: { file: <source>, questions: [string, ...] } (image or 1-page PDF ≤ 5 MB). FLAT-billed per document (docai.price.ask_document tunable). Returns { answers: [{question, answer, confidence}] } — an unanswerable question returns no answer entry, never an error.
Analyze a multi-page document asynchronously
$MeteredPOST https://api.relaystation.ai/v1/doc/analyze-asyncAnalyze a MULTI-PAGE PDF asynchronously (AWS Textract StartDocumentAnalysis). Submit returns a job ticket immediately; poll GET /v1/jobs/{id} or receive the job.completed webhook when the parsed result is ready. Body: { file: <source> (PDF only, up to docai.async_max_pages / docai.async_max_doc_bytes), features: ["FORMS"|"TABLES"|"QUERIES"] (≥1), questions?: [string] (with QUERIES), deliver?: { batonId } (write the result into an owned baton) }. Billed per PAGE (ceiling = pages × docai.price.async_per_page_micros, counted at submit; the x402 rail settles the exact ceiling at submit, the balance rail captures the actual at completion). Returns { ticket, job_id, status: "running", ceiling_micros }.
Detect objects/scenes in an image
$MeteredPOST https://api.relaystation.ai/v1/vision/detect-labels$0.005/image. Detect objects, scenes, and concepts in an image (Rekognition) — labels with confidence scores. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Detect objects, scenes, and concepts in an image ≤ 5 MB (AWS Rekognition DetectLabels). Body: { file: <source>, maxLabels?: 1-100, minConfidence?: 0-100 }. FLAT-billed per image (vision.price.detect_labels tunable). Returns { labels: [...] } — empty when nothing clears the bar.
Detect unsafe content in an image
$MeteredPOST https://api.relaystation.ai/v1/vision/moderate$0.005/image. Flag unsafe or inappropriate image content (Rekognition moderation) — categories with confidence. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Detect unsafe/inappropriate content in an image ≤ 5 MB (AWS Rekognition DetectModerationLabels). Body: { file: <source>, minConfidence?: 0-100 }. FLAT-billed per image (vision.price.moderate_image tunable). Returns { labels: [...] } — an EMPTY array means nothing was flagged.
Detect faces + attributes in an image
$MeteredPOST https://api.relaystation.ai/v1/vision/detect-faces$0.005/image. Detect faces with attributes — age range, emotions, pose, landmarks (Rekognition). 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Detect faces with attributes (age range, emotions, pose, quality) in an image ≤ 5 MB (AWS Rekognition DetectFaces). Body: { file: <source>, attributes?: "DEFAULT"|"ALL" }. FLAT-billed per image (vision.price.detect_faces tunable). Returns { faces: [...] } — empty when no faces.
Compare faces between two images
$MeteredPOST https://api.relaystation.ai/v1/vision/compare-facesCompare the largest face in a source image against faces in a target image (AWS Rekognition CompareFaces). Body: { sourceFile: <source>, targetFile: <source>, similarityThreshold?: 0-100 } (each image ≤ 5 MB). FLAT-billed per call (vision.price.compare_faces tunable). Returns { matches: [...], unmatchedFaces: [...] } — empty matches when nothing clears the threshold.
Recognize celebrities in an image
$MeteredPOST https://api.relaystation.ai/v1/vision/detect-celebrities$0.005/image. Recognize celebrities in an image (Rekognition) — names with confidence scores. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Recognize celebrities in an image ≤ 5 MB (AWS Rekognition RecognizeCelebrities). Body: { file: <source> }. FLAT-billed per image (vision.price.detect_celebrities tunable). Returns { celebrities: [...], unrecognizedFaces } — empty when nobody is recognized.
Detect protective equipment on persons
$MeteredPOST https://api.relaystation.ai/v1/vision/detect-ppe$0.005/image. Detect protective equipment — face, hand, head covers — on people in an image. Site-safety audits by API. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Detect personal protective equipment (face/hand/head covers) on persons in an image ≤ 5 MB (AWS Rekognition DetectProtectiveEquipment). Body: { file: <source>, requiredEquipment?: ["FACE_COVER"|"HAND_COVER"|"HEAD_COVER"], minConfidence?: 0-100 }. FLAT-billed per image (vision.price.detect_ppe tunable). Returns { persons: [...], summary } — empty persons when none detected.
Generate text embedding vectors
$MeteredPOST https://api.relaystation.ai/v1/llm/embed$0.002 per 10 KB. Generate text embeddings, single or batch — pairs with the baton vector index for pay-per-query RAG memory. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Generate embedding vectors for one string or a batch (AWS Bedrock; amazon.titan-embed-text-v2 by default — the model id is the llm.embed.model_id tunable). Body: { input: string | string[] (batch ≤ llm.embed.max_batch, seed 20), dimensions?: 256|512|1024, normalize?: bool }. METERED per started 10 KB of total input (llm.embed.per_10kb_micros tunable); total input ≤ llm.embed.max_input_kb (seed 100). Returns { embeddings: [{index, vector, inputTokens}], model, dimensions }.
Run SQL over a large stored file (Athena)
$MeteredPOST https://api.relaystation.ai/v1/data/sql-large$0.01 per 100 MB scanned. Run SQL over huge stored datasets — pay only for bytes scanned, ≈100 MB per penny. Warehouse-scale queries without the warehouse. 155 tools, one balance — relaystation.ai Run SQL over a LARGE CSV already on Relaystation storage via AWS Athena — for datasets past the in-process /v1/data/sql ceiling. Body: { file: {inputKey}|{batonId}, sql (SELECT over a table named `input`), format?: 'csv'|'json' }. The scannable size is capped by the data.sql_large.max_scan_mb tunable (seed 500; over-cap → 422 pre-charge). METERED on Athena's actually-scanned bytes (data.sql_large.per_100mb_scanned_micros per started 100 MB): you authorize the cap-derived ceiling, the charge settles at actual (authorize_capture). Returns rows in the uniform JSON output envelope (inline, or a storage ref when large).
Batch-write vectors into a vector baton's index
$MeteredPOST https://api.relaystation.ai/v1/baton/{id}/vectors$0.002/batch of 10. Batch-write embeddings into a prepaid vector index inside a baton — Relaystation's durable shared-storage object — agent RAG memory without running a vector DB. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Batch-write [{id, vector, metadata?}] into a VECTOR-preset baton's prepaid index (S3 Vectors). Each vector's length must equal the baton's frozen dims (create with preset 'vector' + vector:{dims}). Owner/editor or a write X-Baton-Token. Writes draw the baton's prepaid SIZE quota (a quota event, not a ledger row); the op is METERED per started batch (baton.vector.price.put_per_batch_micros per baton.vector.put_batch_unit vectors). Metadata (≤ baton.vector.max_metadata_bytes each) typically carries the chunk text for RAG.
Top-k similarity search over a vector baton
$MeteredPOST https://api.relaystation.ai/v1/baton/{id}/vectors/query$0.005/query (+embed units for raw text). Top-k similarity search over a baton's vector index (durable shared storage) — send a vector or raw text, get nearest matches with scores. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Query a VECTOR-preset baton's index with { vector } OR { text } (exactly one; text is embedded inline via the live embed model and its per-10KB units fold into this call's price). topK ≤ baton.vector.max_topk. Owner/reader/editor or a read X-Baton-Token; results draw the prepaid EGRESS quota. FLAT-billed (baton.vector.price.query_micros). Returns { matches: [{id, distance, metadata}] } — empty when the index holds no vectors.
Grounded answer over a vector baton (RAG in one call)
$MeteredPOST https://api.relaystation.ai/v1/rag/answerThe full RAG loop under ONE charge: embeds your question, retrieves top-k chunks from the baton's index, and answers with the live llm answer task using ONLY those chunks (they are treated as untrusted data). Body: { batonId, question, topK?, tier?: budget|value|best }. Owner/reader or a read X-Baton-Token. authorize_capture settle-at-actual: you authorize a ceiling (embed units + query flat + the tier's published LLM ceiling + rag.answer.margin_bp), you pay the actual component costs + margin. Returns { answer, sources: [{id, distance}], usage }.
One-call RAG ingest (chunk → embed → vector-write; create-if-absent)
$MeteredPOST https://api.relaystation.ai/v1/bundles/rag-ingest~$0.01–$0.02/run, bills the sum of steps. One-call RAG ingest: chunk text, embed every chunk, write the vectors into a durable vector index (created for you on first use) — agent memory that persists across sessions, no vector DB to run. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Chunk your text, embed every chunk, and write the vectors into a VECTOR-preset baton — creating one when batonId is absent (persist the returned batonId: it is the memory address across sessions). Body: { text, batonId?, chunkBytes?: 256-8192, name? }. Bills the SUM of the steps as ONE deterministic charge: embed units (llm.embed.per_10kb_micros × chunks) + vector batches (baton.vector.price.put_per_batch_micros) + the engine-quoted create when applicable. Existing batons need write access (owner/writer or a write X-Baton-Token). Returns { batonId, created, chunks, batches, dims }. Recipe: https://relaystation.ai/recipes/agent-rag-memory.
One-call RAG query (vector query → optional grounded answer)
$MeteredPOST https://api.relaystation.ai/v1/bundles/rag-query~$0.01/run, bills the sum of steps. One-call RAG query: embed the question, similarity-search your vector memory, optionally get an answer grounded ONLY in the retrieved chunks with sources. Recipe: relaystation.ai/recipes/agent-rag-memory. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Embed the question, nearest-neighbor query the vector baton, and (answer: true) synthesize a grounded answer from ONLY the retrieved chunks (untrusted data; sources listed). Body: { batonId, question, topK?, answer?, tier?: budget|value|best }. Owner/reader or a read X-Baton-Token. Bills the SUM of the steps as ONE deterministic charge: embed unit(s) + the query flat + (answer) the FLAT bundles.rag_query.answer_flat_micros adder — sync_debit, so the bundle x402-exact-settles (unlike cost-plus /v1/rag/answer, which settles at actual). Returns { batonId, matches: [{id, distance, text}], answer? }. Recipe: https://relaystation.ai/recipes/agent-rag-memory.
One-call document ingest (OCR-searchable + tables → xlsx → drops)
$MeteredPOST https://api.relaystation.ai/v1/bundles/ingest-document~$0.04–$0.06/run, bills the sum of steps. One-call document ingest: OCR a scanned single-page document into a searchable PDF, extract its tables (AWS Textract), write them to xlsx, and store both artifacts at durable URLs. The full scan→spreadsheet chore in one payment. Recipe: relaystation.ai/recipes/document-chores The cputools showcase in one payment: OCR a scanned SINGLE-PAGE document (image or 1-page PDF, ≤ docai.max_doc_bytes) into a searchable PDF, extract its tables (AWS Textract TABLES), write them to xlsx (one sheet per table), and store both artifacts in durable drop batons. Body: { file } (inline / scratch inputKey / baton ref). Bills the SUM of the steps as ONE charge: OCR per-page + docai.price.extract_tables + xlsx per-MB + two engine-quoted drop creates. Returns { searchablePdf: {batonId, url, sizeBytes}, tablesXlsx: {batonId, url, sizeBytes}, tables } — urls are 24h scratch links, batonIds the durable copies. Multi-page documents → the async lane (/v1/doc/analyze-async). Recipe: https://relaystation.ai/recipes/document-chores.
Render a URL to PDF
$MeteredPOST https://api.relaystation.ai/v1/web/pdf$0.02/render. Render any public web page to PDF — headless Chromium, SSRF-guarded egress. 155 tools, one balance — relaystation.ai Render a public web page (by URL) to PDF on a headless Chromium worker. Body: { url (http/https), viewport?: {width,height}, fullPage?, waitMs?, pdfOptions? }. SSRF-GUARDED: private/loopback/link-local/multicast/cloud-metadata and the platform's own hosts are rejected PRE-charge (422 URL_BLOCKED); the fetch runs ONLY in the worker with DNS-pinned resolution and per-redirect re-validation (≤ web.max_redirects). FLAT-billed (web.price.url_to_pdf). Per-customer rate cap (web.rate_per_min). Returns the PDF (uniform output envelope).
Screenshot a URL
$MeteredPOST https://api.relaystation.ai/v1/web/screenshot$0.01/screenshot. Screenshot any public web page to PNG/JPEG/WebP — headless Chromium, SSRF-guarded. 155 tools, one balance — relaystation.ai Screenshot a public web page (by URL) to PNG/JPEG/WebP on a headless Chromium worker. Body: { url (http/https), type?: png|jpeg|webp, viewport?, fullPage?, waitMs? }. Same SSRF guard as /v1/web/pdf (pre-charge URL_BLOCKED; DNS-pinned worker-only fetch). FLAT-billed (web.price.url_screenshot). Returns the image (uniform output envelope).
Extract clean article text from a URL
$MeteredPOST https://api.relaystation.ai/v1/web/readability$0.005/extract. Extract the clean article text — title, byline, body — from any public URL. No boilerplate, no nav junk. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract the readable article of a public web page (by URL) — title, byline, excerpt, and body text with chrome/ads/nav stripped (Mozilla Readability, run in-page on the Chromium worker). Body: { url (http/https) }. Same SSRF guard as /v1/web/pdf. FLAT-billed (web.price.url_readability). Returns { title, byline, excerpt, textContent, length } — null fields when the page is not article-shaped.
Create a binding agreement (terms + parties)
$MeteredPOST https://api.relaystation.ai/v1/contracts$0.02/contract. Agents strike binding-by-goodwill agreements: create terms, add parties, sign, check signatures — with paid arbitration when disputes arise. The trust layer for agent-to-agent work, one of 155 Relaystation tools on one balance — relaystation.ai Create a binding-by-goodwill agreement between agents/parties. The contract IS a hash-chained, auto-witnessed record (terms = entry 1, consents append after); it is tamper-evident and permanently verifiable, but NOT legally binding, NOT court-enforceable, and involves NO escrow or money movement — enforcement rests on the good faith of the parties. Billable (contracts.create), charge-on-attempt; Idempotency-Key honored. The system appends a canonical signature block (and, if arbitration:true, an arbitration block) to your terms — your terms body must NOT itself contain those blocks (free 422 INVALID_FOR_SIGNING). Each required signer is identified by EXACTLY one method: a wallet (0x-address, satisfied only by an EIP-712 ContractConsent signature) or an account (a Relaystation customerId, satisfied only by that authenticated account). Returns per-signer read tokens for visibility. See GET /v1/contracts/disclosure for the EIP-712 domain + witness key.
Open a dispute and get a decision
$MeteredPOST https://api.relaystation.ai/v1/contracts/{id}/arbitrateSubmit a dispute on an arbitrable, fully-executed contract you own; get back a transparent AI ruling. Billable (contracts.arbitrate = a flat fee + the LLM cost + markup); Idempotency-Key honored. The arbiter is a PURE FUNCTION — it reads the published arbitration prompt + the full contract chain + your issue and returns a TEXT decision; it moves no money and takes no action (binding by goodwill, not law). The submitted issue, the exact prompt + model, and the decision are appended to the contract permanently. The arbiter treats the contract + issue as UNTRUSTED DATA and flags any embedded instruction aimed at it (injectionDetected). A provider failure reverses the charge and appends nothing.
Convert an Office document to PDF
$MeteredPOST https://api.relaystation.ai/v1/pdf/from-office$0.005/call. Convert Word, Excel, or PowerPoint to PDF via LibreOffice — layout preserved. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert an Office document (docx, xlsx, pptx, odt, ods, odp, rtf, txt, csv) to PDF via LibreOffice. Body: { file: <source>, filename, options? } where <source> is { inline: <base64 ≤ 4 MiB> } or { inputKey: <scratch key from /v1/cputools/upload-url, ≤ 50 MB> } and `filename` carries the source extension (drives both the format allowlist guard and the conversion). Optional `options` (export controls passed to the engine): pageRanges (e.g. "1-5,8"), quality (JPEG quality 1–100 for embedded images), losslessImageCompression, reduceImageResolution + maxImageResolution (DPI ceiling — one of 75/150/300/600/1200; reduceImageResolution must be on to take effect), landscape (force orientation). FLAT price (cputools.pdf.from-office) — the output page count is not known pre-convert. Charge-on-attempt, no refund: a convert that reaches the engine and succeeds stands; an engine 4xx/5xx/timeout reverses the charge. Output: the uniform cputools JSON output envelope. Idempotency-Key required.
Rescue an exotic/legacy office file to PDF (best-effort)
$MeteredPOST https://api.relaystation.ai/v1/office/rescue$0.008/call. Rescue exotic or legacy Office files into PDF via LibreOffice — opens what modern Office won't. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Best-effort convert an exotic/legacy office format to PDF via LibreOffice — Apple iWork (pages/numbers/key), Visio (vsd/vsdx), MS Publisher (pub), CorelDRAW (cdr), flat-ODF (fodt), legacy MS binaries (doc/xls/ppt), WordPerfect (wpd) — plus the everyday from-office roster. Body: { file: <source>, filename, options? } ({ inline } ≤ 4 MiB / { inputKey } ≤ 50 MB); `filename` carries the source extension (drives the rescue-roster allowlist + the conversion); `options` mirrors /v1/pdf/from-office (pageRanges/quality/losslessImageCompression/reduceImageResolution/maxImageResolution/landscape). Fidelity is honest best-effort — output is ALWAYS PDF (office↔office is not offered). An extension outside the roster → free 422 UNSUPPORTED_FORMAT naming GET /v1/office/formats. Premium FLAT price (cputools.office.rescue). Charge-on-attempt, no refund: a convert that reaches the engine and succeeds stands; an engine 4xx/5xx/timeout reverses. Output: the uniform cputools JSON output envelope. Idempotency-Key required.
Probe media metadata (ffprobe)
$MeteredPOST https://api.relaystation.ai/v1/media/probe$0.0002/call. Inspect any media file via ffprobe — duration, container, streams, codecs, dimensions, bitrate as JSON. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Inspect a media file via ffprobe — duration, container, streams, codecs, dimensions, bitrate. Body: { file: <source> } ({ inputKey } ≤ 50 MB primary / { inline } ≤ 4 MB). Cheap, read-only — FLAT price (cputools.media.probe). Returns { probe: { formatName, durationSeconds, hasVideo, hasAudio, width, height, videoCodec, audioCodec, bitRate, sizeBytes, streams } }.
Trim a media time range (stream-copy)
$MeteredPOST https://api.relaystation.ai/v1/media/trim$0.0005/MB. Cut a time range from audio/video by fast stream-copy — codecs preserved, no quality loss. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Cut a time range from audio/video via fast stream-copy (codecs preserved; use /v1/media/convert to change them). Body: { file: <source>, start: seconds, end?: seconds | duration?: seconds, format?: mp4|mov|mkv|webm|m4a|mp3|wav|ogg|aac|flac (default: the input container) }. Per-MB-of-input price, min 1 MiB (cputools.media.trim). Input duration capped at cputools.media.max_seconds (pre-charge free 422). Output: the uniform cputools JSON output envelope.
Convert media container/codec (re-encode)
$MeteredPOST https://api.relaystation.ai/v1/media/convert$0.0005/MB. Re-encode video/audio to another container or codec (H.264/AAC and more) — scale, crop, rotate in the same pass. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Re-encode a media file to another container/codec. Body: { file: <source>, format: mp4|mov|mkv (H.264/AAC video) | mp3|m4a|aac|wav|ogg|flac (audio), width?, height?, crop?: { w, h, x, y }, rotate?: 90|180|270 }. Video is downscaled to cputools.media.convert.max_height (default 720) at preset cputools.media.convert.preset (default veryfast), and the input duration is capped at cputools.media.convert.max_seconds (default 60 — tight, to clear the synchronous window). Optional transforms: width/height force a scale (omit one to preserve aspect), crop selects a region (w×h at x,y), rotate turns the frame by 90/180/270°; absent → the default aspect-preserving downscale. Per-MB-of-input price, min 1 MiB (cputools.media.convert). Charge-on-attempt; a timeout/undeliverable convert reverses. Output: the uniform JSON output envelope.
Grab a video frame (thumbnail)
$MeteredPOST https://api.relaystation.ai/v1/media/thumbnail$0.0003/call. Grab a single video frame at any timestamp — PNG or JPEG out. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Grab a single frame from a video at a timestamp → PNG/JPEG. Body: { file: <source>, timestamp?: seconds (default cputools.media.thumbnail.default_timestamp), format?: png|jpeg (default cputools.media.thumbnail.format) }. Needs a video stream. FLAT price (cputools.media.thumbnail). Output: the image in the uniform JSON output envelope.
Extract the audio track
$MeteredPOST https://api.relaystation.ai/v1/media/audio-extractStrip + (re)encode a media file's audio track. Body: { file: <source>, format?: mp3|m4a|aac|wav|ogg|flac (default cputools.media.audio.format), bitrate?: e.g. "192k" (default cputools.media.audio.bitrate) }. Needs an audio stream. Per-MB-of-input price, min 1 MiB (cputools.media.audio-extract). Output: the audio file in the uniform JSON output envelope.
Video segment → animated GIF
$MeteredPOST https://api.relaystation.ai/v1/media/gif$0.0005/MB. Turn a video segment into a palette-optimized animated GIF — share-ready loops. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Turn a video segment into a palette-optimized animated GIF. Body: { file: <source>, start?: seconds (default 0), duration?: seconds (default cputools.media.gif.default_seconds, cap cputools.media.gif.max_seconds), width?: px (default 480, cap cputools.media.gif.max_width), fps?: (default cputools.media.gif.fps) }. GIFs blow up — over-cap requests are rejected pre-charge. Needs a video stream. Per-MB-of-input price, min 1 MiB (cputools.media.gif). Output: the GIF in the uniform JSON output envelope.
Normalize audio loudness (EBU R128)
$MeteredPOST https://api.relaystation.ai/v1/media/loudnorm$0.0005/MB. Normalize audio loudness to broadcast EBU R128 — LUFS, true-peak, and range targets. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Normalize a media file's audio loudness with ffmpeg's loudnorm (EBU R128) — a consistent perceived level for podcasts/voiceover/music. Body: { file: <source>, ext?: mp3|m4a|aac|wav|ogg|flac (default cputools.media.audio.format), i?: integrated-loudness target LUFS (-70..-5, default -16), tp?: true-peak ceiling dBTP (-9..0, default -1.5), lra?: loudness-range LU (1..50, default 11) }. AUDIO output (the audio stream, re-encoded; any video is dropped). Needs an audio stream. Input duration capped at cputools.media.max_seconds (pre-charge free 422). Per-MB-of-input price, min 1 MiB (cputools.media.loudnorm). Output: the normalized audio in the uniform JSON output envelope.
Transcode audio (standalone re-encode)
$MeteredPOST https://api.relaystation.ai/v1/media/audio-convert$0.0005/MB. Re-encode audio to another format, bitrate, or sample rate — mp3, aac, wav, flac and more. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Re-encode an audio file to another audio format/bitrate/sample-rate — a standalone audio↔audio transcode (vs /v1/media/audio-extract which pulls audio off a video). Body: { file: <source>, format?: mp3|m4a|aac|wav|ogg|flac (default cputools.media.audio.format), bitrate?: e.g. "192k" (default cputools.media.audio.bitrate), sampleRate?: Hz (8000..192000) }. Needs an audio stream. Input duration capped at cputools.media.max_seconds. Per-MB-of-input price, min 1 MiB (cputools.media.audio-convert). Output: the audio file in the uniform JSON output envelope.
Change playback speed (pitch-preserving)
$MeteredPOST https://api.relaystation.ai/v1/media/speed$0.0005/MB. Speed up or slow down audio/video — pitch-preserving by default. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Speed up or slow down audio/video. Body: { file: <source>, factor?: 0.25..4 (default 1.0; 2 = twice as fast, 0.5 = half), ext?: output container (default: input's — video→mp4, audio→mp3), pitchCorrect?: boolean (default true — preserve pitch via atempo; set false for a tape-style pitch shift) }. Per-MB-of-input price, min 1 MiB (cputools.media.speed). Input duration capped at cputools.media.max_seconds. Output: the speed-changed media in the uniform JSON output envelope.
Extract an embedded subtitle track
$MeteredPOST https://api.relaystation.ai/v1/media/subtitle-extractPull an embedded subtitle/caption track out of a container to a text sidecar (SRT or WebVTT). Body: { file: <source>, format?: srt|vtt (default srt), index?: subtitle-stream index ≥ 0 (default 0 — the first subtitle track) }. Returns the chosen subtitle stream as a text file. If the requested stream does not exist → free 422 NO_SUBTITLE_STREAM. FLAT price (cputools.media.subtitle-extract). Output: the subtitle text in the uniform JSON output envelope.
Concatenate clips (stream-copy)
$MeteredPOST https://api.relaystation.ai/v1/media/concat$0.0005/MB. Join 2–10 clips end-to-end by fast stream-copy — no quality loss, no re-encode. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Join 2–10 clips end-to-end via the ffmpeg concat demuxer (fast STREAM-COPY — no re-encode). Body: { files: [<source>, …] (2..10, each itself an input-source: { inline: <base64 ≤ 4 MiB> } or { inputKey: <scratch key ≤ 50 MB>}), ext?: output container (default: the first clip's) }. The inputs MUST share the same codec + container (concat-demuxer requirement) — a mismatched set is a CONVERT_FAILED (re-encode each via /v1/media/convert to a common format first). Per-MB-of-the-SUM price, min 1 MiB (cputools.media.concat). The summed size is capped at cputools.media.concat.max_total_mb and the count at cputools.media.concat.max_inputs (pre-charge free 422). Output: the joined media in the uniform JSON output envelope.
Overlay an image onto a video (watermark)
$MeteredPOST https://api.relaystation.ai/v1/media/overlay$0.0005/MB. Watermark an image or logo onto a video — position and opacity control. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Composite an image (logo/watermark) onto a video. Body: { file: <video source>, overlay: <image source> (itself an input-source: { inline: <base64 ≤ 4 MiB> } or { inputKey: <scratch key ≤ 50 MB>}), position?: top-left|top-right|bottom-left|bottom-right|center (default top-left), ext?: output container (default: the video's) }. The primary input must be a video (else NO_VIDEO_STREAM, free pre-charge). Re-encodes the video. Per-MB-of-the-VIDEO price, min 1 MiB (cputools.media.overlay). Input duration capped at cputools.media.max_seconds. Output: the watermarked video in the uniform JSON output envelope.
Burn subtitles into a video (libass)
$MeteredPOST https://api.relaystation.ai/v1/media/subtitle-burn$0.0005/MB. Burn subtitles permanently into video via libass — styled captions everywhere the file goes. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render a subtitle file (SRT/WebVTT) permanently INTO the video frames via libass. Body: { file: <video source>, subtitle: <srt/vtt source> (itself an input-source: { inline: <base64 ≤ 4 MiB> } or { inputKey: <scratch key ≤ 50 MB>}), ext?: output container (default: the video's) }. NOTE — the subtitles are BURNED (rasterized) into the picture, NOT a soft/toggleable track; the result has no separate subtitle stream and the captions cannot be turned off. The primary input must be a video. Re-encodes the video. Per-MB-of-the-VIDEO price, min 1 MiB (cputools.media.subtitle-burn). Input duration capped at cputools.media.max_seconds. Output: the captioned video in the uniform JSON output envelope.
Render a waveform / spectrogram PNG
$MeteredPOST https://api.relaystation.ai/v1/media/waveform$0.0005/call. Render audio as a waveform or spectrogram PNG — visualize any track. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Render an audio file as a waveform OR spectrogram PNG (ffmpeg showwavespic / showspectrumpic). Body: { file: <source>, mode?: waveform|spectrogram (default waveform), width?: 100..2000 (default 640), height?: 50..1080 (default 120 waveform / 480 spectrogram), color?: blue|red|green|white|black|cyan|magenta|yellow|orange|gray (waveform only, default blue) }. Needs an audio stream. Input duration capped at cputools.media.waveform.max_seconds (default 600, pre-charge free 422). FLAT price (cputools.media.waveform). Output: the PNG in the uniform JSON output envelope.
Detect or trim silence
$MeteredPOST https://api.relaystation.ai/v1/media/silence$0.0005/call. Detect silent intervals as JSON or trim the silence out — tighter podcasts and voice notes. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Detect OR trim silence in audio (ffmpeg silencedetect / silenceremove). Body: { file: <source>, action?: detect|trim (default detect), thresholdDb?: -90..0 (default -30), minDurationSeconds?: 0.1..60 (default 0.5), format?: mp3|m4a|aac|wav|ogg|flac (trim output, default mp3) }. action=detect → JSON { silence: [{ start, end, duration }], count } (no file). action=trim → the silence-removed audio in the uniform JSON output envelope. Needs an audio stream. Input duration capped at cputools.media.silence.max_seconds (default 1800). FLAT price (cputools.media.silence).
Mix N audio inputs → 1
$MeteredPOST https://api.relaystation.ai/v1/media/audio-mix$0.0005/MB. Mix multiple audio tracks down to one (amix), optional loudness normalize — voiceover + music in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Mix multiple audio inputs down to one track (ffmpeg amix). Body: { file: <primary source>, inputs: [<source>, …] (additional tracks, each itself an input-source { inline ≤ 4 MiB } / { inputKey ≤ 50 MB }), format?: mp3|m4a|aac|wav|ogg|flac (default mp3), normalize?: boolean (default false — true scales by 1/N to avoid clipping) }. TOTAL input count (primary + additional) capped at cputools.media.audio-mix.max_inputs (default 8 → up to 7 additional; over is a free 422 TOO_MANY_INPUTS). Primary duration capped at cputools.media.audio-mix.max_seconds (default 1800). Per-MB-of-the-PRIMARY price, min 1 MiB (cputools.media.audio-mix). Output: the mixed audio in the uniform JSON output envelope.
Build a thumbnail sprite sheet
$MeteredPOST https://api.relaystation.ai/v1/media/storyboard$0.0008/call. Frame-sampled thumbnail sprite sheet from a video — scrubbers and previews in one call. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Build a frame-sampled thumbnail sprite sheet from a video (ffmpeg fps-sample + tile). Body: { file: <source>, cols?: 1..10 (default 5), rows?: 1..10 (default 5), intervalSeconds?: 0.5..3600 (overrides the auto fps; default: sample cols×rows frames evenly across the whole clip so the grid fills), tileWidth?: 32..640 px (default 160) }. Needs a video stream. Input duration capped at cputools.media.storyboard.max_seconds (default 3600). FLAT price (cputools.media.storyboard). Output: the sprite-sheet PNG in the uniform JSON output envelope.
Read or write container metadata
$MeteredPOST https://api.relaystation.ai/v1/media/metadata$0.0002/call. Read media container tags as JSON or write them back — stream-copy, no re-encode. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Read OR write container metadata tags (ffprobe / ffmpeg -metadata, STREAM-COPY — no re-encode). Body: { file: <source>, set?: { title?|artist?|album?|comment?|genre?|date?|track?|composer?: string|number } }. set absent → JSON { metadata: { …tags } } (read). set present → the re-tagged file in the uniform JSON output envelope (source container preserved). Unknown tag keys are ignored (only the allowlisted set is written). FLAT price (cputools.media.metadata).
Extract frames → presigned manifest
$MeteredPOST https://api.relaystation.ai/v1/media/frames$0.0003/MP. Extract N evenly-sampled frames from a video — a manifest of presigned image links back. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Extract evenly-sampled frames from a video → a manifest of presigned image refs (mirrors POST /v1/pdf/render). Body: { file: <source>, count?: 1..50 (default 10), format?: png|jpeg|jpg (default png), width?: 32..1920 px (height auto) }. Frames are sampled evenly across the whole clip. Needs a video stream. Input duration capped at cputools.media.frames.max_seconds (default 3600). Billed PER MEGAPIXEL of output — `ceil(Σ frames × outW × outH / 1e6)` × `cputools.price.media.frames.per_mp_micros` (meters output egress; large-resolution frames cost proportionally more). Output: { frames: [{ index, outputKey, outputUrl }], count } — fetch each via its presigned outputUrl (~1 h) or chain outputKey as another op's inputKey.
Convert a document (pandoc)
$MeteredPOST https://api.relaystation.ai/v1/doc/convert$0.0003/MB. Convert documents between markdown, HTML, docx, odt, rtf, epub, LaTeX, and rst via pandoc — citations supported. 1¢ x402 min; remainder auto-credits — relaystation.ai/penny Convert a markup/structured document between formats via pandoc — markdown, html, docx, odt, rtf, epub, latex, rst, org, textile, mediawiki, plain. Body: { file: <source>, filename?, from?, to, options?: { standalone? } }. `to` is required; `from` is sniffed from `filename` (extension) when omitted. An unsupported (from,to) pair → free 422 UNSUPPORTED_CONVERSION listing the valid targets for that source (the error teaches the matrix; see GET /v1/doc/formats). NO direct pdf target (pandoc→PDF needs a LaTeX engine — deferred; compose doc/convert→html then /v1/pdf/from-html). Runs sandboxed (no file/network access from within the document). Per-MB-of-input price, min 1 MiB (cputools.doc.convert). Charge-on-attempt; an undeliverable convert reverses. Output: the uniform cputools JSON output envelope. Idempotency-Key required.
Run a language task (translate, summarize, extract, classify, proofread, and more) — pick a tier
$MeteredPOST https://api.relaystation.ai/v1/llm/{task}Run a registry task. `{task}` is the task key (see GET /v1/llm/tasks). Body: { tier: "budget"|"value"|"best", input: <the text>, params?: <task-specific, validated against the task's param_schema> }. The registry maps tier→model; the admin-only instruction template wraps your `input` (which is DATA — a separate message, never the instruction). ONE OpenRouter call; chargedMicros = ceil(provider usage.cost × (1 + markup)). x402 is `upto`: the 402 advertises the published per-increment ceiling; you authorize it and pay the actual. Prepaid holds the ceiling and captures the actual. An unsupported task/tier → free 422 UNSUPPORTED listing the active ones (the error teaches the registry). Upstream 4xx/5xx/timeout → nothing delivered → reverse. Output-cap truncation → truncated:true, charge stands. Idempotency-Key required. Returns { result, truncated, usage: { model, inputTokens, outputTokens, providerCostMicros, markupPct, chargedMicros } }.
Checks
reachable
valid
2026-10-09T01:45:58.955Z
No settlement evidence found in chain signals.
Gateway routing
Score ≥70/100 — Cleared attestation pass. Route via Gateway before pay.
Claim this listing to upgrade to Cleared attestation.
Claim listing