Quickstart
From an account to your first decision, then acting on it.
Five minutes, start to finish: an account, a key, one request, and an if on the answer.
Get access
Hartley is in private beta. Join the waitlist and we'll email you a link to create your account when you're in. A teammate's invitation to their organization gets you in straight away.
Create an API key
In the console, open API Keys and create one. The key (trodo_sk_…) is shown once: put it in your secret manager. New organizations also need credits before calls go through: add them under Billing (Billing and credits).
Try it in the playground
The Playground sends the same request as the API: paste a state, ask a few questions (yes or no, pick one, a score, or a value to extract) and look at the probabilities. It shows the request as curl, Python and TypeScript, ready to copy.
Make your first call
export TRODO_API_KEY=trodo_sk_...
curl https://models.trodo.ai/v1/decide \
-H "Authorization: Bearer $TRODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": "User: I was charged twice. Agent: I have refunded the duplicate charge.",
"questions": {
"resolved": {"type": "noul", "instructions": "Did the agent resolve the issue?"},
"sentiment": {"type": "choice", "instructions": "How does the user feel?", "criteria": ["happy", "neutral", "upset"]}
}
}'import os, requests
res = requests.post(
"https://models.trodo.ai/v1/decide",
headers={"Authorization": f"Bearer {os.environ['TRODO_API_KEY']}"},
json={
"state": "User: I was charged twice. Agent: I have refunded the duplicate charge.",
"questions": {
"resolved": {"type": "noul", "instructions": "Did the agent resolve the issue?"},
"sentiment": {"type": "choice", "instructions": "How does the user feel?", "criteria": ["happy", "neutral", "upset"]},
},
},
timeout=120, # the first call after a quiet spell can take up to a minute
)
res.raise_for_status()
answers = res.json()["answers"]const res = await fetch('https://models.trodo.ai/v1/decide', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.TRODO_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
state: 'User: I was charged twice. Agent: I have refunded the duplicate charge.',
questions: {
resolved: { type: 'noul', instructions: 'Did the agent resolve the issue?' },
sentiment: { type: 'choice', instructions: 'How does the user feel?', criteria: ['happy', 'neutral', 'upset'] },
},
}),
})
if (!res.ok) throw new Error(`Hartley ${res.status}: ${await res.text()}`)
const { answers } = await res.json()Read the answer
{
"model": "hartley-1",
"answers": {
"resolved": {"type": "noul", "noul": 0.93, "abstain": 0.02},
"sentiment": {
"type": "choice", "choice": "neutral",
"probabilities": {"happy": 0.31, "neutral": 0.58, "upset": 0.11},
"confidence": 0.37, "abstain": 0.04
}
},
"usage": {"input_tokens": 61, "output_tokens": 0},
"latency_ms": 31.2
}A call on a few thousand tokens usually comes back in about a second; longer states take longer. After a quiet spell the first call can take up to a minute while the model starts, so give your HTTP client a timeout of at least 120 seconds.
Both questions were answered from one read of the state. noul is the probability the answer is yes; a choice comes back with the most likely option and a probability for every option. Every field is in Reading the response.
Act on it
The answer is a number, so the rest is ordinary code. Act on what Hartley is sure about and send the rest on:
resolved = answers["resolved"]["noul"]
if resolved >= 0.9:
close_ticket()
elif resolved <= 0.1:
reopen_ticket()
else:
send_to_review() # Hartley isn't sure: let a person decideWhere to put those lines is covered in Acting on confidence.