API Quickstart

Goal
A live, self-improving classification endpoint, built entirely from the command line. No console steps, no training data, no model configuration.
Time
~5 minutes

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,
  "externalId": "msg-001"
}

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, rides along if the invoke is captured for review, and deduplicates the labeled sample you may submit later (step 5) — all without storing anything Nyckel-specific.
capture Defaults to true, which makes the invoke eligible for invoke capture — Nyckel selectively saves the most informative invokes to the review queue. Set capture=false for traffic you never want captured.

confidence is a calibrated 0.01.0 score. It’s what you branch on in production — see Tuning confidence thresholds.


5. Feed back the correct label

This is the step that makes a function improve. An invoke is not stored as a training sample — invoke capture selectively queues some invokes for console review, but your code shouldn’t count on any particular invoke being there. When your application learns the true label, submit the input together with that label as a new sample, reusing the externalId:

curl -X POST "https://www.nyckel.com/v1/functions/$NYCKEL_FN/samples" \
  -H "Authorization: Bearer $NYCKEL_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "data": "WINNER!! Claim your prize now, text CLAIM to 80086",
    "externalId": "msg-001",
    "annotation": { "labelName": "Not spam" }
  }'

If a sample with the same content or externalId already exists — earlier feedback from you, or a captured invoke that was annotated in the console — the call returns 409 Conflict carrying the existing sample’s id. Update that sample’s annotation instead:

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

  1. 1POST /invoke
  2. 2labelName + confidence
  3. 3your application acts
  4. 4POST labeled sample
  5. 5model retrains
Production loop

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 invokes worth reviewing

Nyckel is already picking review candidates for you: invoke capture sets aside the invokes most likely to improve the model — low-confidence predictions plus a random slice of traffic. Annotate them in the console’s Review tab, or pull the queue into your own annotation workflow (note the v0.9 prefix):

curl "https://www.nyckel.com/v0.9/functions/$NYCKEL_FN/captures?batchSize=20" \
  -H "Authorization: Bearer $NYCKEL_TOKEN"

Each item carries the input, the predicted label and confidence, the reason it was captured, and the externalId you sent on the invoke. Label the ones worth fixing and feed them back exactly as in step 5. Your own prediction log is the other good source — you know which invokes mattered to your application, so pick the ones to relabel and submit those.


Next