Bearer key · JSON
POST /api/v1/text/stats
curl -s -X POST https://getattest.com.au/api/v1/text/stats \
-H "authorization: Bearer $ATTEST_API_KEY" \
-H "content-type: application/json" \
-d '{"text":"Hello there. General Kenobi!"}'
Send the key as a bearer token in the authorization header. One key and one credit balance cover every service, including Attest Capture. A failed call is refunded automatically. No key yet? POST /api/v1/keys issues one with 25 free credits and no signup — see the key guide.
Captured 2026-09-21
Example
This request was run against the running service on 2026-09-21 and the response below is what came back, unedited.
Request JSON
{
"text": "Hello there. General Kenobi!"
}
Captured response JSON
{
"call_id": "08ec544d-8ef5-4a40-9ab4-de81a788a6e1",
"characters": 28,
"code_points": 28,
"utf16_units": 28,
"bytes_utf8": 28,
"words": 4,
"sentences": 2,
"paragraphs": 1,
"lines": 1,
"whitespace": 3,
"reading_time_minutes": 0.02,
"speaking_time_minutes": 0.02,
"time_basis": {
"reading_words_per_minute": 238,
"speaking_words_per_minute": 183
},
"tokens": {
"o200k_base": 7,
"cl100k_base": 7,
"note": "OpenAI tokenizers, per the model table in js-tiktoken 1.0.21: o200k_base is listed for GPT-4o, GPT-4o mini, GPT-4.1, GPT-4.5 Preview, o1, o3, o4-mini and GPT-5; cl100k_base for GPT-4, GPT-4 Turbo and GPT-3.5 Turbo. Other models, including other vendors', may tokenize differently, so treat these counts as estimates for them."
},
"sms": {
"encoding": "GSM-7",
"segments": 1,
"characters_per_segment": 160,
"units": 28,
"max_segments": 255,
"within_concatenation_limit": true,
"note": "GSM 7-bit default alphabet without national language shift tables; extension characters (^ { } [ ] ~ | \\ € and form feed) cost two. Code 0x09 is capital Ç in the 3GPP table, so small ç is counted as UCS-2, the encoding a gateway following that table sends; a gateway following Unicode's GSM0338.TXT accepts ç as one septet and may need fewer segments than reported. Multipart sizes assume the standard 6-octet concatenation header; at most 255 parts fit in one concatenated message, so when segments exceeds max_segments, within_concatenation_limit is false and the text cannot be sent as a single concatenated SMS. Characters outside the Basic Multilingual Plane are never split between segments; senders that also keep whole emoji sequences together may need one more. Gateways may substitute characters or choose a different encoding."
},
"limits": [],
"sources": [
{
"name": "Brysbaert, M. (2019). How many words do we read per minute? A review and meta-analysis of reading rate. Journal of Memory and Language, 109, 104047.",
"url": "https://doi.org/10.1016/j.jml.2019.104047",
"used_for": "reading_time_minutes (238 wpm, adult silent reading of non-fiction) and speaking_time_minutes (183 wpm, adult reading aloud)"
},
{
"name": "OpenAI tiktoken encodings o200k_base and cl100k_base (MIT), rank files from js-tiktoken (MIT)",
"url": "https://github.com/openai/tiktoken",
"used_for": "tokens"
},
{
"name": "3GPP TS 23.038 (GSM 7-bit default alphabet and extension table) and 3GPP TS 23.040 clause 9.2.3.24.1 (concatenated short messages)",
"url": "https://www.3gpp.org/ftp/Specs/archive/23_series/",
"used_for": "sms"
},
{
"name": "Unicode GSM0338.TXT mapping — cited only for the divergence at GSM code 0x09, which it maps to small c-cedilla where the 3GPP table draws the capital; we follow 3GPP",
"url": "https://www.unicode.org/Public/MAPPINGS/ETSI/GSM0338.TXT",
"used_for": "sms"
}
],
"notice": "General information only. Reading and speaking times are averages for adult English readers; individual rates vary.",
"checked_at": "2026-09-20T16:55:57.499Z",
"credits_charged": 1,
"credits_remaining": 9992
}
For agents
Use when
Use this when a task needs counts for a piece of text: words, user-perceived characters, bytes, sentences, paragraphs, lines, reading or speaking time, OpenAI token counts, SMS segments, or a check against length limits such as a character, word, SMS or prompt-token budget.
2 fields
Input
Scroll the table horizontally to see all fields.
Field / Type / Required / What it does| Field | Type | Required | What it does |
|---|
text | string | Required | The text to count. Up to 200,000 UTF-16 code units. Whitespace-only text is valid and counts zero words. |
|---|
limits | array | Optional | Up to 20 budgets to check the text against. Each is { name, max, unit } where unit is characters, words, tokens_o200k, tokens_cl100k, bytes or sms_segments. |
|---|
HTTP 200
Response
Every successful response also carries call_id (your receipt for the charge), credits_charged and credits_remaining.
Scroll the table horizontally to see all fields.
Field / What it holds| Field | What it holds |
|---|
characters | User-perceived characters (graphemes). |
|---|
code_points | Unicode code points. |
|---|
utf16_units | JavaScript string length. |
|---|
bytes_utf8 | UTF-8 byte length. |
|---|
words | Word count. |
|---|
sentences | Sentence count. |
|---|
paragraphs | Paragraph count. |
|---|
lines | Line count. |
|---|
reading_time_minutes | At 238 words per minute, adult silent reading of non-fiction. |
|---|
speaking_time_minutes | At 183 words per minute, adult reading aloud. |
|---|
tokens | OpenAI o200k_base and cl100k_base token counts, with a note on which models each is listed for. |
|---|
sms | SMS encoding, segment count and concatenation limit, with the assumptions spelled out. |
|---|
limits | Each budget sent, with the measured value and whether it fits. |
|---|
sources | The research and specifications behind the reading, token and SMS figures. |
|---|
Machine-readable failures
Errors
Errors return JSON such as {"error":"invalid_api_key"}. A failed call is refunded automatically.
Scroll the table horizontally to see all fields.
Code / Status / Meaning| Code | Status | Meaning |
|---|
text_required | 400 | No text was sent. |
|---|
invalid_text | 400 | text is not a string. |
|---|
text_too_long | 400 | text is past the 200,000 code-unit cap; split it and add the counts up. |
|---|
invalid_limits | 400 | limits is not an array. |
|---|
too_many_limits | 400 | More than 20 limits were sent. |
|---|
invalid_limit_unit | 400 | A limit names a unit this service does not measure. |
|---|
invalid_limit_max | 400 | A limit's max is not a whole number of zero or more. |
|---|
limit_name_required | 400 | A limit has no name. |
|---|
On every service
Scroll the table horizontally to see all fields.
Code / Status / Meaning| Code | Status | Meaning |
|---|
invalid_api_key | 401 | The authorization header is missing or the key is unknown. |
|---|
insufficient_credits | 402 | The balance is below this call's cost. The response carries credits_required and credits_remaining. |
|---|
rate_limit_exceeded | 429 | Free keys share 10 calls a minute across every service. The response carries limit and window_seconds. |
|---|
services_unavailable | 503 | The credit store could not be reached. Retry once after 30 seconds. |
|---|
6 worked examples
Examples
Where the answer comes from
Source and scope
Reading rates from Brysbaert (2019), Journal of Memory and Language 109, 104047. Token counts from the OpenAI tiktoken encodings o200k_base and cl100k_base (MIT) via js-tiktoken (MIT). SMS segmentation from 3GPP TS 23.038 and TS 23.040.
Attest reports what it read, with the source it read it from. It is general information, not advice, and not a legal record.
All Attest tools · Service list as JSON · OpenAPI