ESCIMate API

Programmatic access to the statistical consistency checker. Version 0.3.5.

Base URLs

EnvironmentURL
Productionhttps://escimate.app
Local developmenthttp://127.0.0.1:9422

Cold-start warning: the production server (Render free tier) sleeps after 15 minutes of inactivity. The first request after idle may take ~76 seconds. Probe /health first to wake the server.

No authentication required. No API keys. No rate limiting at the API level — but Plumber is single-threaded, so concurrent requests are queued.

Contents

1. Quick Start

Health check:

curl https://escimate.app/health

Analyze a PDF file:

curl -X POST https://escimate.app/api/v1/process \
  -F "file=@paper.pdf"

Analyze pasted text:

curl -X POST https://escimate.app/api/v1/process-text \
  -H "Content-Type: application/json" \
  -d '{"text": "t(28) = 2.21, p = .035, d = 0.80"}'

Analyze text with custom options:

curl -X POST https://escimate.app/api/v1/process-text \
  -H "Content-Type: application/json" \
  -d '{
    "text": "F(1, 58) = 7.23, p = .009, eta2 = .11",
    "options": {
      "alpha": 0.05,
      "one_tailed": false,
      "cross_type_action": "NOTE",
      "stats": ["t", "F", "r", "chisq"]
    }
  }'

Generate an HTML report (file or text):

curl -X POST "https://escimate.app/api/v1/report?style=beginner" \
  -F "file=@paper.pdf" \
  -o report.html

curl -X POST https://escimate.app/api/v1/report-text \
  -H "Content-Type: application/json" \
  -d '{"text": "t(28) = 2.21, p = .035, d = 0.80", "style": "expert"}' \
  -o report.html

Compare with statcheck:

curl -X POST https://escimate.app/api/v1/compare \
  -F "file=@paper.pdf"

curl -X POST https://escimate.app/api/v1/compare-text \
  -H "Content-Type: application/json" \
  -d '{"text": "t(28) = 2.21, p = .035, d = 0.80"}'

Python example:

import requests

# From text
r = requests.post(
    "https://escimate.app/api/v1/process-text",
    json={"text": "t(28) = 2.21, p = .035, d = 0.80",
          "options": {"alpha": 0.05}},
    timeout=120,
)
data = r.json()
for row in data["results"]:
    print(row["test_type"], row["status"], row.get("delta_effect"))

# From file
with open("paper.pdf", "rb") as f:
    r = requests.post(
        "https://escimate.app/api/v1/process",
        files={"file": f},
        data={"options": '{"alpha": 0.01}'},
        timeout=300,
    )
print(r.json()["summary"])

JavaScript / Node example:

// From text
const res = await fetch("https://escimate.app/api/v1/process-text", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    text: "t(28) = 2.21, p = .035, d = 0.80",
    options: { alpha: 0.05 },
  }),
})
const data = await res.json()
console.log(data.summary)

// From file (browser)
const fd = new FormData()
fd.append("file", fileInput.files[0])
fd.append("options", JSON.stringify({ alpha: 0.05 }))
await fetch("https://escimate.app/api/v1/process", { method: "POST", body: fd })

2. Endpoints

GET/health

Returns server health status. No auth. Useful for cold-start detection.

{"status":"healthy","time":"2026-04-27 12:00:00","version":"0.3.5"}
POST/api/v1/process

Analyze an uploaded file. Accepts PDF, HTML, DOCX, TXT.

Content-Type: multipart/form-data

FieldTypeRequiredDescription
filefileyes.pdf, .html, .docx, .txt
optionsJSON stringnoSee Configuration Options
POST/api/v1/process-text

Analyze raw text.

Content-Type: application/json

FieldTypeRequiredDescription
textstringyesNon-empty text to analyze
optionsobjectnoSee Configuration Options
POST/api/v1/report

Generate a self-contained HTML report from a file. Form field file required.

Query params: style=beginner (default) or style=expert.

Returns text/html.

POST/api/v1/report-text

HTML report from raw text. Body: { "text": "...", "style": "beginner" | "expert" }.

POST/api/v1/compare

Side-by-side comparison with statcheck on a file. Returns merged JSON results.

POST/api/v1/compare-text

statcheck comparison on raw text. Body: { "text": "..." }.

3. Configuration Options

Pass via the options object (text endpoints) or as a JSON-encoded options form field (file endpoints).

OptionTypeDefaultDescription
alphanumber0.05Significance threshold for decision-error detection.
tol_effectobjectsee §8Per-type effect size tolerances. Partial overrides merged with defaults.
cross_type_actionstring"NOTE"Status for cross-type-only matches. ERROR | WARN | NOTE | SKIP.
design_ambiguous_actionstring"WARN"Status for design-ambiguous t-test ERRORs. ERROR | WARN | NOTE.
unknown_groups_actionstring"WARN"Status for d/g ERRORs when n1/n2 unknown. ERROR | WARN | NOTE.
min_confidenceinteger0Filter results below this 0–10 confidence score.
ci_affects_statusbooleantrueWhether CI bound mismatches downgrade PASS to NOTE.
one_tailedbooleanfalseAssume one-tailed tests when computing p-values.
plausibility_filterbooleantrueFlag implausible effect sizes as extraction suspects.
statsstring[]["t","F","r","chisq","z","U","W","H","regression"]Which test types to detect.
assume_equal_ns_when_missingbooleantrueAssume equal groups when n1/n2 not reported.
logbooleantrueAnonymous usage logging. Set false to suppress.

Additional R-only parameters (ci_level, paired_r_grid, tol_ci, tol_p, max_text_length, max_stats_per_text, ci_method_phi, ci_method_V, messages) are documented in API.md.

4. Response Format

Process endpoints return:

{
  "results": [ /* one object per detected statistic */ ],
  "normalized_text": "Full text after Unicode normalization...",
  "summary": {
    "total": 12,
    "pass": 8,
    "ok": 2,
    "note": 1,
    "warn": 0,
    "error": 1,
    "extraction_suspect_count": 0,
    "cross_type_count": 0
  },
  "effectcheck_version": "0.3.5"
}

Each results[] object includes 50+ fields across these groups:

  • Identificationlocation, raw_text, context_window, test_type, source
  • Parsed valuesdf1, df2, stat_value, N, n1, n2, table_r, table_c
  • Reported valuesreported_type, effect_reported, ciL_reported, ciU_reported, p_reported, p_symbol, p_valid, N_source
  • Type-matched comparisonmatched_variant, matched_value, delta_effect, ambiguity_level, all_variants (JSON)
  • Computed effect sizesd_ind, g_ind, dz, dav, drm, eta2, partial_eta2, omega2, cohens_f, phi, V, rank_biserial_r, cliffs_delta, epsilon_squared, kendalls_W, standardized_beta, partial_r, …
  • P-value & decision errorp_computed, decision_error, decision_error_reason
  • CI comparisonci_match, ciL_computed, ciU_computed, ci_delta_lower, ci_delta_upper, ci_check_status, ci_method_match, ci_width_ratio, ci_symmetry, ci_level_source
  • v0.3.5 CI auditeffect_reported_decimals, ciL_reported_decimals, ciU_reported_decimals, stat_value_decimals, ci_expected, ci_reported, ci_level_mismatch, ci_clipped_to_bound, ci_symmetry_class
  • Reproducibilityrepro_code, repro_output
  • Status & metadatastatus, check_type, extraction_suspect, design_ambiguous, design_inferred, variants_tested, uncertainty_level, uncertainty_reasons, assumptions_used, insufficient_data

Field-level documentation also lives in the R package's function help: ?effectcheck::check_text.

5. Status Taxonomy

StatusMeaningCriteria
PASSConsistentEffect size delta ≤ tolerance (or APA rounding match).
OKP-value consistentNo effect size to compare; reported p matches recomputed p. Also for 'ns' confirmed.
NOTECannot fully verifyMissing data, CI mismatch downgrade, plausibility filter, or cross-type fallback.
WARNModerate discrepancy1× < delta ≤ 5× tolerance, design-ambiguous t-test, or qualifying decision error.
ERRORLarge discrepancyDelta > 5× tolerance, or clear decision error (significance flips).
SKIPNot verifiableExtraction-only result with nothing to check.

Modifiers: decision error escalates to ≥ WARN; CI mismatch downgrades PASS → NOTE (when ci_affects_status); plausibility filter downgrades ERROR → NOTE; design-ambiguous t-test ERROR downgrades to design_ambiguous_action.

6. Effect Size Families

Test typeReportedComputed variants
t-testdd_ind, d_ind_equalN, d_ind_min, d_ind_max, dz, dav, drm
t-testgg_ind (Hedges' bias-corrected)
t-testrr (point-biserial from t)
F / ANOVAeta², partial η², ω², feta2, partial_eta2, omega2, cohens_f
F / ANOVAd (2-group)d (converted from F)
r (correlation)rr (verified via t-transformation)
chi-squarephi, V, OR, hphi (2×2), V (larger), OR, h
z-testd, rd = z/√N; r converted from z
Mann-Whitney Urank_biserial_r, cliffs_deltarank_biserial_r, cliffs_delta
Wilcoxon Wrank_biserial_rrank_biserial_r
Kruskal-Wallis Hepsilon², Kendall's Wepsilon_squared, kendalls_W
Regressionβ, partial_rstandardized_beta (from t and df), partial_r

7. R Package API

Install from CRAN (recommended) or GitHub:

# Stable release from CRAN
install.packages("effectcheck")

# Or development version from GitHub
# install.packages("remotes")
remotes::install_github("giladfeldman/escicheck")

Core functions:

library(effectcheck)

# From text
res <- check_text("t(28) = 2.21, p = .035, d = 0.80")
print(res); summary(res)

# Single file
res <- check_file("paper.pdf", alpha = 0.01)

# Whole directory (recursive)
res <- check_dir("manuscripts/", stats = c("t", "F"))

# HTML report
generate_report(res, out = "report.html", style = "beginner")

# statcheck side-by-side
cmp <- compare_with_statcheck("t(28) = 2.21, p = .035, d = 0.80")

statcheck-compatible wrappers also exported: checkPDF(), checkHTML(), checkPDFdir(), checkHTMLdir(), checkDOCXdir().

8. Tolerance Defaults

Effect sizeToleranceEffect sizeTolerance
d, g, dz, dav, drm0.02r, partial_r0.005
phi, V, h, cohens_f0.02eta2, etap2, omega20.01
beta, R20.01f20.02
rank_biserial_r, cliffs_delta0.02epsilon_squared, kendalls_W0.01
OR, RR, IRR0.5tol_ci / tol_p0.02 / 0.001

Plausibility bounds: |d|, |g|, |cohens_f|, |beta| > 10; |r|, |phi|, |V|, |R2|, |eta2|, |omega2|, |rank_biserial_r|, |cliffs_delta|, |epsilon_squared|, |kendalls_W| > 1; |OR|, |RR|, |IRR| > 100; |h| > 3.15. Any effect size delta > 1.0 is flagged as a likely extraction error.

9. Error Handling

CodeMeaningWhen
200SuccessRequest processed successfully.
400Bad RequestEmpty file or missing/empty text field.
500Internal Server ErrorCorrupt file, invalid format, or R error.

JSON endpoints return { "error": "message" }. HTML report endpoints return an HTML error page.

CORS allows: localhost:2249/3000, 127.0.0.1:2249/3000, escimate.app, www.escimate.app, *.vercel.app. Non-browser requests (no Origin) get *.

10. Limits & Performance

LimitDefaultNotes
max_text_length10,000,000 chars (~10 MB)Per request
max_stats_per_text10,000Per request
Upload size100 MBplumber.max_post_body
Cold start~76 sRender free tier sleeps after 15 min idle
Warm latency~12 sTypical PDF, single user
Concurrency1 (queued)Plumber single-threaded; 3 concurrent ≈ 22/35/47 s

No rate limiting at the API level. Be considerate — this is a free academic service. For heavy batch use, run the R package or self-host with the Docker image (see GitHub).

Run it yourself

The effectcheck R package is open-source on GitHub and CRAN — the same engine that powers this API. For local or batch use without going through the hosted API, install the R package and call check_text() / check_file() / check_dir() directly. The hosted web service (frontend, deployment glue) is not open-source.