A free text classification API that returns the label, not a paragraph about the label
Free to call with a key and no card. Send the text and the labels you want it sorted into; get one of those labels back in a typed field with a number beside it. There is no prompt to tune, no JSON to parse, no training data, and no way for the response to come back as prose, because the response has no field that holds prose.
Your labels go in the request
No fine-tuning step, no labelled corpus, no model per task. The label set is an argument, so a new category is a new line in a JSON object rather than a retraining run. This is a support-ticket router, in full:
POST https://api.blockrun.ai/v1/decide
Authorization: Bearer <your key>
{
"state": "My card was charged twice for
the same order and I need one
of them back.",
"questions": {
"dept": {
"type": "choice",
"instructions": "Which team should
handle this ticket?",
"criteria": {
"billing": "a charge, refund, invoice
or payment problem",
"shipping": "a delivery, tracking or
address problem",
"technical": "the product or app is
broken or erroring",
"account": "login, password, or
account settings",
"sales": "a pre-purchase question
about buying"
}
}
}
}{
"model": "openjev",
"answers": {
"dept": {
"type": "choice",
"choice": "billing",
"probabilities": {
"billing": 0.6273,
"shipping": 0.0733,
"technical": 0.1004,
"account": 0.0722,
"sales": 0.1268
},
"confidence": 0.6273
}
},
"usage": {
"input_tokens": 18,
"output_tokens": 0
}
}output_tokens: 0 is not a bug. Nothing was generated. The model scored your labels against your text and returned the winner.
Read answers.dept.choice and you are done. The failure mode you normally budget for here — the model answered in a sentence, or wrapped the JSON in backticks, or invented a sixth department — cannot happen, because the reply is assembled from the keys you sent.
Where it gets it wrong, and why the number will not warn you
Two sentences, same three labels, same endpoint, on 2026-09-21. One is classified correctly and one is classified wrongly. The confidence is effectively the same on both.
“Another outage. This service is terrible today.”
"choice": "negative"
"probabilities": {
"positive": 0.0026,
"neutral": 0.0467,
"negative": 0.9507
}“Oh fantastic, another outage. Really loving this service today.”
"choice": "positive"
"probabilities": {
"positive": 0.9378,
"neutral": 0.0461,
"negative": 0.0161
}Sarcasm. The model reads the words and the words are praise. Sent three times, it returned 0.9378 three times — it is not unsure, it is wrong.
0.9507 on a right answer. 0.9378 on a wrong one. If you had only the number you could not tell which was which, and a threshold at 0.9 lets both through.
This is the single thing worth understanding before you put a classifier behind a decision. The number is how strongly the text supports that label against the others you offered. It is not the probability that the label is right, and no threshold turns it into one. The longer version is on the model page.
When nothing fits, it still answers
There is no other and no abstain. Feed the support router a sentence with nothing to do with support and it picks something:
“The mitochondria is the powerhouse of the cell.”
"choice": "shipping"
"probabilities": {
"billing": 0.334,
"shipping": 0.4515,
"technical": 0.2145
}The answer is nonsense and the spread says so. Three labels with nothing to choose between them sit near a third each; this one tops out at 0.4515 with 0.334 right behind it. Compare the ticket above, where the winner cleared the runner-up by more than four times.
So gate on the gap between the top two, not on the top score alone, and route a narrow gap to a human or to a fallback label. That catches “nothing fits”. It does not catch the sarcasm case above, which arrives wide and confident — nothing in the response catches that one, and you should assume a small, steady rate of it.
Several classifications in one request
questions is a map, so one call can carry up to 64 of them over the same text — and they do not all have to be label sets. One real customer message, four different answers, one round trip, 1.4 seconds:
“Honestly the checkout flow is a disaster. Third time this week it timed out and I gave up. I have been a customer for six years and I am about done.”
| Question | Type | Answer | Number |
|---|---|---|---|
| sentiment | choice | negative | 0.9649 |
| at risk of leaving? | noul | yes | 0.8512 |
| how urgent a reply | score | between “this week” and “today” | 1.176 |
| topic | choice | checkout | 0.7088 |
noul is a yes/no and comes back as one number. score takes an ordered list of rungs and returns a weighted position between them, so 1.176 means “a bit past reply-this-week, not yet reply-today” — a real answer to a question that a label set would have had to round off.
Use this, or use a chat model
- The answer is one of a set you can write down
- You want the same answer for the same input, every time
- You are doing it per message, at volume, and cost matters
- Routing, triage, tagging, moderation pre-filters, intent detection
- You have no labelled data and no appetite to make some
- The answer needs a reason, a summary, or a reply to the customer
- The categories depend on knowledge outside the text you send
- It turns on tone, irony, or implication rather than wording
- You need tool calls or a multi-step chain
- The label set is not knowable until you have read the text
These compose. Classify everything cheaply, then spend a chat model only on the slice where the top two labels were close — see what response_format actually does for why the second half of that pipeline needs a parse guard and this half does not.
What to expect in production
| Latency, warm | First call after idle | Determinism | Price |
|---|---|---|---|
| 0.8s to 1.4s | about 32s — the container is cold | Same input, same numbers | Free with a registered key |
The cold start is real and we would rather you read it here than discover it. It happens once after a quiet period, not per request; the four-question call above took 1.4 seconds warm. If your traffic is bursty, send one throwaway call before the burst.
Try it on your own labels
A key from the dashboard is free and needs no card, and this endpoint costs nothing to call — we host the model ourselves, so there is no per-call bill to pass on. Paste your own categories into the request above and see what it does with ten of your real messages before you believe any of this.
Text classification API questions: labels, accuracy, cost, limits
- Is there a genuinely free text classification API?
- This one. A registered key costs nothing and needs no card, and the classification calls are not metered, because we host the model ourselves rather than paying a provider per call. There is an hourly rate limit and no charge behind it.
- How does classification work without any training data?
- You describe each label in a sentence and send that alongside the text. The model scores how strongly the text supports each of your descriptions and returns the strongest. Nothing is fine-tuned and nothing is retained, so adding a category is another line in the request rather than a retraining run.
- How accurate is a zero-shot classifier like this?
- Good enough for routing and triage, and wrong in a way worth knowing before you ship. It reads wording, so plain statements go where they should and sarcasm does not: praise-shaped text about a bad experience comes back positive, confidently and repeatably. The page shows that failure with the captured reply. Measure it on your own messages.
- What does the confidence number actually mean?
- How strongly the text supports that label against the other labels you offered. It is not the probability the label is right. The page puts a correct answer and a wrong answer side by side at almost the same confidence, which is the clearest way to see that no threshold separates them.
- How should I set a threshold on the output?
- On the gap between the top two labels rather than on the top score. A near-tie means nothing in your label set fit, and that is the slice worth sending to a human. A confident wrong answer will not be caught by any threshold, so plan for a small steady error rate instead of filtering for it.
- What happens if none of my labels apply to the text?
- It picks one anyway. There is no abstain and no built-in catch-all. What changes is the spread: unrelated text lands near an even split across your labels, where a clear case leaves the runner-up far behind. Add your own catch-all label if you want somewhere for it to go.
- Can I classify several dimensions in a single call?
- Yes, dozens of questions over the same text in one request, and they need not all be label sets — a yes/no and a graded score can ride along. Each answer comes back independently typed, and the whole call still returns in about a second once warm.
- Do I get the same label for the same text every time?
- Yes. Identical input returns identical numbers, so a message routes the same way today and next month, and a rule you tune against yesterday's traffic still means what you thought. A chat model running at a temperature does not give you that.
- Text classification API vs prompting an LLM instead?
- Use a chat model when the answer needs a reason, a summary, or knowledge beyond the text in front of it. Use this when the answer is one of a set you can write down: it is free, deterministic, quicker, and cannot reply in a sentence, because the response has no field that holds one.