API Quickstart
This is the code-first path. If you’d rather see the same loop in the UI first, the Spam Classifier tutorial covers the same ground through the console.
You need a Nyckel account and a clientId / clientSecret pair. Both are in the
Access Management section of your account, and on the Integrate tab of any function.
1. Get an access token
Every API request carries a bearer token. Tokens come from connect/token, which sits outside the
/v1/ API surface.
curl -X POST 'https://www.nyckel.com/connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id=<clientId>&client_secret=<clientSecret>'
{
"access_token": "<accessToken>",
"token_type": "Bearer",
"expires_in": 3600
}
Tokens are valid for one hour. Request a new one when it expires — see Authentication for rotation details.
export NYCKEL_TOKEN='<accessToken>'
2. Create a function
A function is the whole unit: endpoint, model, sample store, and review queue. You pick its input
modality (Text, Image, or Tabular) and its output modality at creation time. Both are
immutable — a function that classifies text can’t later be switched to images.
curl -X POST 'https://www.nyckel.com/v1/functions' \
-H "Authorization: Bearer $NYCKEL_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "sms-spam-classifier",
"input": "Text",
"output": "Classification"
}'
{
"id": "<functionId>",
"name": "sms-spam-classifier",
"input": "Text",
"output": "Classification"
}
export NYCKEL_FN='<functionId>'
3. Define the labels
Labels are the decision space — the set of answers the function is allowed to give. Create one call per label.
curl -X POST "https://www.nyckel.com/v1/functions/$NYCKEL_FN/labels" \
-H "Authorization: Bearer $NYCKEL_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "name": "Spam" }'
curl -X POST "https://www.nyckel.com/v1/functions/$NYCKEL_FN/labels" \
-H "Authorization: Bearer $NYCKEL_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "name": "Not spam" }'
That’s the whole setup. You have not uploaded a single training example, and the function is already callable.
4. Invoke it
curl -X POST "https://www.nyckel.com/v1/functions/$NYCKEL_FN/invoke?externalId=msg-001" \
-H "Authorization: Bearer $NYCKEL_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "data": "WINNER!! Claim your prize now, text CLAIM to 80086" }'
{
"labelName": "Spam",
"labelId": "<labelId>",
"confidence": 0.94
}
This first prediction is zero-shot — it comes from a foundation model reasoning about your label names, not from a model trained on your data. For plenty of use cases the zero-shot accuracy is good enough to ship on. See How functions work for what happens underneath.
Two parameters worth knowing now:
| Parameter | Why it matters |
|---|---|
externalId |
Your own id for this input. It comes back on the response and lets you find the captured sample later, without storing anything Nyckel-specific. |
capture |
Defaults to true. Every invoke is captured as a sample you can review. Set capture=false for traffic you don’t want in the review queue. |
confidence is a calibrated 0.0–1.0 score. It’s what you branch on in production — see
Tuning confidence thresholds.
5. Correct it
This is the step that makes a function improve. Find the captured sample by the externalId you
sent, then set its annotation.
curl "https://www.nyckel.com/v1/functions/$NYCKEL_FN/samples?externalId=msg-001" \
-H "Authorization: Bearer $NYCKEL_TOKEN"
[
{
"id": "<sampleId>",
"externalId": "msg-001",
"data": "WINNER!! Claim your prize now, text CLAIM to 80086",
"prediction": { "labelId": "<labelId>", "confidence": 0.94 }
}
]
curl -X PUT "https://www.nyckel.com/v1/functions/$NYCKEL_FN/samples/<sampleId>/annotation" \
-H "Authorization: Bearer $NYCKEL_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "labelName": "Not spam" }'
Annotations feed the retraining pipeline. Nyckel retrains as they accumulate, benchmarks the new model against the current one, and promotes it only if it scores better. You don’t trigger any of that.
The loop, in one picture
- 1POST /invoke
- 2labelName + confidence
- 3your application acts
- 4PUT /annotation
- 5model retrains
Steps 4 and 5 are the whole production pattern. Everything else in the API — sample sets, function summaries, field management — exists to support that loop at scale.
Finding samples worth reviewing
In production you won’t annotate by externalId. You’ll pull the samples the model was least sure
about and review those first:
# Captured but not yet annotated
curl "https://www.nyckel.com/v1/functions/$NYCKEL_FN/samples?annotated=false&count=20" \
-H "Authorization: Bearer $NYCKEL_TOKEN"
# Samples where the model's prediction disagreed with the annotation
curl "https://www.nyckel.com/v1/functions/$NYCKEL_FN/samples?predictionAndAnnotationAgree=false" \
-H "Authorization: Bearer $NYCKEL_TOKEN"
List Samples documents the full filter set.
Next
- Build a feedback loop — wiring step 5 into a real application.
- Production integration patterns — where the invoke call belongs in your request path.
- Function types — detection, search, and OCR, when classification isn’t the right shape.
- Structured data functions — classifying rows of fields instead of a single input.
- API Reference — every endpoint, with auth, errors, and throttling.