Ticket classification & routing API

Sort incoming tickets by topic and urgency, and whether a bot can handle them

For each ticket, chat or email, spinf gives the probability of each answer to your routing questions: which queue, is it urgent, can a bot resolve it. Automate the clear cases and send the uncertain ones to your team, at a confidence level you choose.

Cost at scale

1M tickets for about $81

On spinf-12b, our optimized Gemma 4 12B, only input is billed, at $0.09 per million tokens: the content once per call, each question's own tokens, and one empty floor per question. The scores are free.

Combine use cases in the same call

Check every message for prompt injection and policy breaches while you classify its intent: the message is read once, and each extra question adds only its own tokens.

tickets1,000,000× tokens each (about)900= tokens900M× $0.09 / 1M$81.00

Assumes 150-token tickets with 4 labelled examples in the content, 4 questions. The first 50M tokens are free. Gemma is a trademark of Google LLC.

Pricing details
Real time · reserved endpoint

$0.09 per million input tokens · the scores are free

Why spinf

Calibrated answers for ticket & message routing, at any scale

Only your labels

The answer is always one of your intents, queues or categories, with its probability: nothing to parse, no invented labels.

Thresholds, not guesses

Choose the confidence threshold at which a ticket is routed automatically, and send everything below it to a person. Measure the trade-off on your own history first.

Taught by examples

Few-shot: put a handful of your labelled tickets in the content and accuracy jumps. No training run and no model to host.

Live example

One ticket, three routing questions

Urgency, intent and topic, answered together. The bars show p; the tick shows the floor, the same question with no ticket.

Content
Customer support message: Hi, since this morning's SSO change nobody on our team can log in, and we have a board demo at 3pm today. We're on the Business plan. Please help ASAP!

Is this urgent (business blocked, security, legal threat, data loss, or a deadline within 24 hours)?

yes

0.97

no

0.03

Intent (login problem, outage, billing, cancellation, or feature request):

login problem

0.66

outage

0.30

billing

0.02

cancellation

0.00

feature request

0.02

Topic (billing, technical, account, shipping, or cancellation):

billing

0.08

technical

0.87

account

0.05

shipping

0.00

cancellation

0.00

import os
import requests

resp = requests.post(
    "https://api.spinf.com/v1/score",
    headers={"Authorization": f"Bearer {os.environ['SPINF_API_KEY']}"},
    json={
      "model": "spinf-12b",
      "messages": [
        {
          "role": "user",
          "content": "Customer support message:\nHi, since this morning's SSO change nobody on our team can log in, and we have a board demo at 3pm today. We're on the Business plan. Please help ASAP!"
        }
      ],
      "scoring": {
        "queries": [
          {
            "id": "urgent",
            "template": "\n\nIs this urgent (business blocked, security, legal threat, data loss, or a deadline within 24 hours)?\nAnswer:{?}",
            "options": [
              " yes",
              " no"
            ]
          },
          {
            "id": "intent",
            "template": "\n\nIntent (login problem, outage, billing, cancellation, or feature request):{?}",
            "options": [
              " login problem",
              " outage",
              " billing",
              " cancellation",
              " feature request"
            ]
          },
          {
            "id": "category",
            "template": "\n\nTopic (billing, technical, account, shipping, or cancellation):{?}",
            "options": [
              " billing",
              " technical",
              " account",
              " shipping",
              " cancellation"
            ]
          }
        ]
      }
    },
)
for query in resp.json()["results"][0]["queries"]:
    for combo in query["combinations"]:
        print(query["id"], combo["values"], [(o["text"], o["p"], o["floor_p"]) for o in combo["options"]])

A live call to spinf-12b, with no examples. With a few labelled tickets from your helpdesk in the content, the scores become sharper and closer to your team’s own decisions.

The API call behind this example, the docs and the benchmark code are easier to read on a larger screen. Start free now, and pick it up on your laptop.

Benchmark · 130 test tickets

Accurate with a few labelled tickets in the prompt

Measured on 130 synthetic support tickets written for our benchmark and labelled by a language model and checked blind by a second model, with no examples and with 4 or 8 labelled example tickets placed in the prompt (three different example sets, never the tickets being scored).

93%

correct topic (5 topics)

8 examples in the prompt · 87% with no examples (calibrated) · spinf-31b: 95% with no examples
93%

correct · bot can resolve?

8 examples in the prompt · 75% with no examples (calibrated)
92%

correct · urgent?

8 examples in the prompt · 85% with no examples · an urgent ticket outranks a non-urgent one 98% of the time (AUC 0.98)
87%

correct · needs a human?

8 examples in the prompt · 87% with no examples

The larger spinf-31b (Gemma 4 31B, on request) needs fewer examples for topics: with none, it gets 95% right, against 75% for spinf-12b (87% calibrated). Synthetic tickets are cleaner than real ones: expect lower numbers on your data, and measure them on your own history before going live. On spinf-12b, with 8 examples in the prompt, scoring costs about $0.12 per 1,000 tickets.

Test sets, questions and code on GitHub: reproduce it with your own key

The questions matter: iterate on yours

As with any language model, the wording of the questions and a few labelled examples change the results a lot. With spinf that is cheap to get right: try a few wordings and example sets on a few hundred of your own items for cents, and keep the best. How to write questions

How it works

Calibrate in bulk, then decide live

The on-demand API is built for throughput: use it to measure spinf on your own history and set your thresholds. Real-time decisions then run on an endpoint reserved for you.

1

Calibrate on your history

Score last year's tickets on the on-demand API, with your free tokens. Compare with what your team decided, and pick the thresholds where spinf acts alone and where it hands over to a person.

2

Go live on a reserved endpoint

The same questions and thresholds, on capacity reserved for you: always warm, sized to your traffic, and pinned with one request field.

3

Keep checking

Re-score a sample of new tickets in bulk every week to catch drift, and adjust the questions or thresholds when your business changes.

FAQ

Ticket & message routing: questions, answered

More in the docs and the guides: intent classification and routing and probabilistic if statements, or .

Yes, on a reserved endpoint. The on-demand API is tuned for throughput rather than real time, so for live triage we reserve capacity for you. Start by calibrating on your ticket history with the on-demand API and your free tokens.

No. You write the questions and the answers in plain language. To match your team’s decisions more closely, add a few labelled tickets to the content: in our benchmark, 8 examples took “can a bot resolve it?” from 67% to 93% correct.

It works best with a manageable list: a few to a few dozen intents, each named clearly. For a long list, ask two questions: first the broad category, then the intent within it, with a few labelled examples for each. Measure on a labelled sample of your own messages.

Score a labelled sample of past tickets, then pick the probability above which a ticket is routed automatically. Everything below goes to a person. The floor returned with each answer helps compare questions.

spinf is an API: call it from your helpdesk’s webhooks or automation rules with the ticket text, and write the answer back as a tag, a priority or a queue.

No. Content sent for scoring is processed in memory and not stored by default, and it is never used to train models.
Try it on your data

The first 50M tokens are on us

Score a sample of your history today, and talk to us when you are ready to go live.