jarrah

Spreadsheet generation API

Ship Export to Excel this afternoon.

One POST request turns JSON into a styled .xlsx file. Ten rows or ten million: same endpoint, no library to maintain, no memory tuning, no per-developer licence.

Start free Read the quickstart 100 documents a month, free. No card.
POST /v1/workbooks
{
  "styles": {
    "header": { "font": { "bold": true } },
    "money":  { "num_fmt": "#,##0.00" }
  },
  "sheets": [{
    "name": "Sales",
    "columns": [
      { "header": "Item",   "width": 30 },
      { "header": "Amount", "style": "money" }
    ],
    "header_style": "header",
    "rows": [
      ["Widget", 1250.5],
      { "Item": "Gadget", "Amount": 99.0 },
      { "cells": ["Total", { "f": "=SUM(B2:B3)" }],
        "style": "header" }
    ],
    "freeze": { "row": 1, "col": 0 },
    "autofilter": true
  }]
}
200 sales.xlsx
Rendered result
AB
1 Item Amount
2 Widget 1,250.50
3 Gadget 99.00
4 Total 1,349.50
Sales

Performance

Big exports are the hard part. That's the part we built for.

The engine is Rust, writing in constant-memory mode: rows stream to disk instead of accumulating in RAM, so a million-row export costs roughly what a thousand-row one does in memory. Every figure below is reproducible from the benchmarks/ directory.

1M rows × 10 cols

6.4s

JSON in to file out, 4-core container

Peak memory, same job

746 MB

Whole request, parse included

Small workbooks

1 request

Under ~50k cells, bytes come back inline

Per-developer licence

$0

Priced on what you generate, not headcount

How it works

Two paths, one payload shape.

Small workbooks come straight back as bytes. Anything large returns a job you poll or get a webhook for, with the finished file on a presigned URL. The JSON you send is identical either way.

# Sync: the response body is the file.
curl -X POST https://api.jarrah.sh/v1/workbooks \
  -H "Authorization: Bearer $JARRAH_KEY" \
  -H "Content-Type: application/json" \
  --data @workbook.json \
  -o sales.xlsx

Formatting

Styles by name, not by cell

Declare a style once, reference it from columns, rows or cells. Repeating a font object per cell is what turns a 20 MB request into a 200 MB one.

Correctness

Nothing is guessed

A string starting with = stays a string. A date stays text until you tag it. Guessing is how spreadsheets mangle part numbers, and how they execute things you pasted.

Errors

Every mistake, in one response

Validation collects all problems at once and points at each with a JSON pointer, so you fix a generated payload in one pass instead of ten round trips.

Durability

Jobs survive restarts

The queue is durable. If a worker dies mid-export the job is retried, not lost. A blip delays your file, it doesn't drop it.

Compare

What you'd otherwise be maintaining.

Comparing licensing and operating models, which are stable and checkable. Specific vendor pricing changes too often to quote honestly on a page like this.

Approach What you pay for Who runs the compute Large exports
Commercial library
Aspose, DevExpress, MESCIUS
A licence per developer, renewed yearly You do Your problem to tune
Open-source library
openpyxl, Apache POI, exceljs
Nothing, then engineering time You do Usually where teams hit memory walls
File-conversion API
generic converters
Per conversion They do Rarely a first-class case
Jarrah Documents generated. No seat count. We do The case the engine was built around

Early pricing

Priced on documents, not developers.

Add an engineer to the team and the bill doesn't move. No size surcharges either. A ten-row file and a ten-million-row file are both one document.

Free

$0

  • 100 documents / month
  • Files up to 50,000 rows
  • 1 concurrent job
  • Files kept 24 hours

Stops at 100. No card required.

Starter

$19 /mo

  • 2,500 documents / month
  • Files up to 250,000 rows
  • 3 concurrent jobs
  • Files kept 7 days

Then $0.01 / document. No hard cap.

Growth

$49 /mo

  • 15,000 documents / month
  • Files up to 2 million rows
  • 5 concurrent jobs
  • Files kept 30 days

Then $0.005 / document. No hard cap.

Scale

$149 /mo

  • 75,000 documents / month
  • Files up to 10 million rows
  • 10 concurrent jobs
  • Templates, charts, DPA, priority support

Then $0.003 / document. Files kept 90 days.

Webhooks, synchronous and asynchronous rendering are on every plan, including free. Integration primitives are never gated. A free tier you cannot build against is a demo, not a trial. Every account also gets a test-mode key: unlimited renders, never billed, watermarked output.

Annual billing is two months free. These are early prices: we may raise them for new customers, and if you sign up now you keep the rate you signed up at.

Start free Signing in creates the account. No card, and nothing to cancel if you stop.

Honest status. The API is live and you can sign up today. What is not settled is the pricing itself. These numbers are a first attempt, informed by what comparable services charge, and not yet validated against anyone who has paid one. The performance figures are real, measured on 2026-08-06 on a 4-core container and reproducible from benchmarks/, but they describe the engine in isolation rather than a deployed service under load. Jarrah is an internal codename; the public name is still open.