Contents

Policies and settings

Policies, templates and bucket keys.

The Policy object

Attributes

  • name required Type: string
  • version required Type: integer
  • id required Type: string

    name@version

  • auto_approve_enabled required Type: boolean
  • auto_threshold required Type: number
  • approve_threshold required Type: number
  • fail_threshold required Type: number
  • quality required Type: QualityPolicy null
  • review_rate required Type: number null
  • forgery_rate required Type: number null
  • created_by required Type: string
  • created_at required Type: string

Policy on its own page

The Policy object
{
  "name": "strict",
  "version": 2,
  "id": "strict@2",
  "auto_approve_enabled": false,
  "auto_threshold": 0.7,
  "approve_threshold": 0.85,
  "fail_threshold": 0.3,
  "quality": null,
  "review_rate": null,
  "forgery_rate": null,
  "created_by": "api_key:key_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "created_at": "2026-09-25T10:15:30.123Z"
}

The Template object

Attributes

  • template_id required Type: string
  • name required Type: string
  • boxes required Type: TemplateBox[]
  • blank_type required Type: "png" "pdf"
  • feature_hash required Type: string null
  • created_at required Type: string

Template on its own page

The Template object
{
  "template_id": "benefits-form-v3",
  "name": "Benefits form",
  "boxes": [
    {
      "name": "applicant_signature",
      "x": 400,
      "y": 1860,
      "w": 520,
      "h": 200
    }
  ],
  "blank_type": "png",
  "feature_hash": "sha256:1cf1da50e3f0be0b50197022be0eedf20fa688cf20ca1154b388098a9d2e29e1",
  "created_at": "2026-09-25T10:15:30.123Z"
}

The latest version of each policy

GET /nib/policies

Needs org:read: See org, members, usage

Returns

  • 200
    The policies
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/policies · curl
curl "https://api.unforged.sh/nib/policies" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/policies · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/policies",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/policies · Node.js
const res = await fetch('https://api.unforged.sh/nib/policies', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());

A policy (the latest version, or `?version=N`)

GET /nib/policies/{name}

Needs org:read: See org, members, usage

Parameters

  • name pathrequired Type: Id
  • version queryoptional Type: integer

Returns

  • 200 Type: Policy
    The policy version
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/policies/{name} · curl
curl "https://api.unforged.sh/nib/policies/{name}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/policies/{name} · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/policies/{name}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/policies/{name} · Node.js
const res = await fetch('https://api.unforged.sh/nib/policies/{name}', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "name": "strict",
  "version": 2,
  "id": "strict@2",
  "auto_approve_enabled": false,
  "auto_threshold": 0.7,
  "approve_threshold": 0.85,
  "fail_threshold": 0.3,
  "quality": null,
  "review_rate": null,
  "forgery_rate": null,
  "created_by": "api_key:key_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "created_at": "2026-09-25T10:15:30.123Z"
}

Store a new policy version

PUT /nib/policies/{name}

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

201 with the new version; 200 if unchanged. Checks use the latest version.

Parameters

  • name pathrequired Type: Id

Request body

PolicySpec

  • auto_approve_enabled optional Type: boolean
  • auto_threshold required Type: number

    A check is approved automatically when its score reaches approve_threshold and the low end of its likely range reaches auto_threshold. It can sit below approve_threshold, and must be above fail_threshold.

  • approve_threshold required Type: number
  • fail_threshold required Type: number

    A signature scoring under this fails. With fewer than three references it goes to review instead, unless it scores under 0.01 or is a copy of a reference.

  • quality optional Type: QualityPolicy null
  • review_rate optional Type: number null

    The share of genuine signatures you're prepared to review, for example 0.05. When it's set, the approve bar is chosen for each number of references so that about this share of genuine signatures is flagged or failed, and approve_threshold isn't used. Slow, even strokes and a signature closer than the person's usual variation are then shown as notes rather than holding the check.

  • forgery_rate optional Type: number null

    How often you expect a forgery, for example 0.001 for 1 in 1,000. Each signature then also shows forgery_probability. It doesn't change any decision.

Returns

  • 200 Type: Policy
    Unchanged
  • 201 Type: Policy
    A new version
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 413 Type: Problem
    too_large
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
PUT /nib/policies/{name} · curl
curl -X PUT "https://api.unforged.sh/nib/policies/{name}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14" \
  -H "Content-Type: application/json" \
  -d '{
  "auto_approve_enabled": false,
  "auto_threshold": 0.7,
  "approve_threshold": 0.85,
  "fail_threshold": 0.3
}'
PUT /nib/policies/{name} · Python
import requests

r = requests.put(
    "https://api.unforged.sh/nib/policies/{name}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
    json={
        "auto_approve_enabled": False,
        "auto_threshold": 0.7,
        "approve_threshold": 0.85,
        "fail_threshold": 0.3
    },
)
print(r.json())
PUT /nib/policies/{name} · Node.js
const res = await fetch('https://api.unforged.sh/nib/policies/{name}', {
  method: 'PUT',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "auto_approve_enabled": false,
    "auto_threshold": 0.7,
    "approve_threshold": 0.85,
    "fail_threshold": 0.3
  }),
});
console.log(await res.json());
Response 200
{
  "name": "strict",
  "version": 2,
  "id": "strict@2",
  "auto_approve_enabled": false,
  "auto_threshold": 0.7,
  "approve_threshold": 0.85,
  "fail_threshold": 0.3,
  "quality": null,
  "review_rate": null,
  "forgery_rate": null,
  "created_by": "api_key:key_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "created_at": "2026-09-25T10:15:30.123Z"
}

Form templates

GET /nib/templates

Needs org:read: See org, members, usage

Returns

  • 200
    The templates
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/templates · curl
curl "https://api.unforged.sh/nib/templates" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/templates · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/templates",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/templates · Node.js
const res = await fetch('https://api.unforged.sh/nib/templates', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());

Upload a form template

POST /nib/templates

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

Multipart: a template JSON part and a blank PNG or PDF (at most 20 MB). 409 if the id exists or you have 200 templates.

Parameters

  • Idempotency-Key headerrequired Type: string

    1–255 printable ASCII characters, kept 24 hours.

Returns

  • 201 Type: Template
    Created
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 409 Type: Problem
    conflict, idempotency_conflict, idempotency_in_progress or idempotency_not_replayable
  • 413 Type: Problem
    too_large
  • 415 Type: Problem
    unsupported_media
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • 503 Type: Problem
    busy, not_ready, org_moving or storage_provisioning (your organisation's storage is still being set up); retry after Retry-After
  • default Type: Problem
    internal
POST /nib/templates · curl
curl -X POST "https://api.unforged.sh/nib/templates" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
POST /nib/templates · Python
import requests

r = requests.post(
    "https://api.unforged.sh/nib/templates",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
POST /nib/templates · Node.js
const res = await fetch('https://api.unforged.sh/nib/templates', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 201
{
  "template_id": "benefits-form-v3",
  "name": "Benefits form",
  "boxes": [
    {
      "name": "applicant_signature",
      "x": 400,
      "y": 1860,
      "w": 520,
      "h": 200
    }
  ],
  "blank_type": "png",
  "feature_hash": "sha256:1cf1da50e3f0be0b50197022be0eedf20fa688cf20ca1154b388098a9d2e29e1",
  "created_at": "2026-09-25T10:15:30.123Z"
}

A form template

GET /nib/templates/{template_id}

Needs org:read: See org, members, usage

Parameters

  • template_id pathrequired Type: Id

Returns

  • 200 Type: Template
    The template
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/templates/{template_id} · curl
curl "https://api.unforged.sh/nib/templates/{template_id}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/templates/{template_id} · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/templates/{template_id}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/templates/{template_id} · Node.js
const res = await fetch('https://api.unforged.sh/nib/templates/{template_id}', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "template_id": "benefits-form-v3",
  "name": "Benefits form",
  "boxes": [
    {
      "name": "applicant_signature",
      "x": 400,
      "y": 1860,
      "w": 520,
      "h": 200
    }
  ],
  "blank_type": "png",
  "feature_hash": "sha256:1cf1da50e3f0be0b50197022be0eedf20fa688cf20ca1154b388098a9d2e29e1",
  "created_at": "2026-09-25T10:15:30.123Z"
}

Delete a form template and its files

DELETE /nib/templates/{template_id}

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

Parameters

  • template_id pathrequired Type: Id

Returns

  • 204
    Done
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
DELETE /nib/templates/{template_id} · curl
curl -X DELETE "https://api.unforged.sh/nib/templates/{template_id}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
DELETE /nib/templates/{template_id} · Python
import requests

r = requests.delete(
    "https://api.unforged.sh/nib/templates/{template_id}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
DELETE /nib/templates/{template_id} · Node.js
const res = await fetch('https://api.unforged.sh/nib/templates/{template_id}', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());

Your bucket's access keys

GET /nib/bucket-keys

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

Returns

  • 200 Type: BucketKeyList
    The keys
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • 501 Type: Problem
    not_implemented or not_available_in_dev
  • 503 Type: Problem
    busy, not_ready, org_moving or storage_provisioning (your organisation's storage is still being set up); retry after Retry-After
  • default Type: Problem
    internal
GET /nib/bucket-keys · curl
curl "https://api.unforged.sh/nib/bucket-keys" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/bucket-keys · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/bucket-keys",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/bucket-keys · Node.js
const res = await fetch('https://api.unforged.sh/nib/bucket-keys', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "iam_user": "unf-prod-acme",
  "bucket_keys": [
    {
      "id": "bkt_01j9x3m8v7k2q4r5s6t7u8v9w0",
      "access_key_id": "AKIAIOSFODNN7EXAMPLE",
      "status": "active",
      "created_at": "2026-09-25T10:15:30Z",
      "reissue_required": false
    }
  ]
}

Issue a bucket access key

POST /nib/bucket-keys

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

The secret is shown once. At most 2 active keys (409). The first time, your bucket's access is set up first: the answer is 202 with status setting_up, and the list shows the same until it is ready (usually within a minute); then ask again.

Returns

  • 201 Type: BucketKeyCreated
    Created
  • 202
    Bucket access is being set up; ask again shortly
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 402 Type: Problem
    billing_required
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 409 Type: Problem
    conflict, idempotency_conflict, idempotency_in_progress or idempotency_not_replayable
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • 501 Type: Problem
    not_implemented or not_available_in_dev
  • 503 Type: Problem
    busy, not_ready, org_moving or storage_provisioning (your organisation's storage is still being set up); retry after Retry-After
  • default Type: Problem
    internal
POST /nib/bucket-keys · curl
curl -X POST "https://api.unforged.sh/nib/bucket-keys" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
POST /nib/bucket-keys · Python
import requests

r = requests.post(
    "https://api.unforged.sh/nib/bucket-keys",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
POST /nib/bucket-keys · Node.js
const res = await fetch('https://api.unforged.sh/nib/bucket-keys', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 201
{
  "id": "bkt_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "access_key_id": "AKIAIOSFODNN7EXAMPLE",
  "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "iam_user": "unf-prod-acme",
  "created_at": "2026-09-25T10:15:30Z"
}

Delete a bucket access key

DELETE /nib/bucket-keys/{id}

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

Revokes the key.

Parameters

  • id pathrequired Type: string

    The key's id or access key id.

Returns

  • 204
    Done
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • 501 Type: Problem
    not_implemented or not_available_in_dev
  • 503 Type: Problem
    busy, not_ready, org_moving or storage_provisioning (your organisation's storage is still being set up); retry after Retry-After
  • default Type: Problem
    internal
DELETE /nib/bucket-keys/{id} · curl
curl -X DELETE "https://api.unforged.sh/nib/bucket-keys/{id}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
DELETE /nib/bucket-keys/{id} · Python
import requests

r = requests.delete(
    "https://api.unforged.sh/nib/bucket-keys/{id}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
DELETE /nib/bucket-keys/{id} · Node.js
const res = await fetch('https://api.unforged.sh/nib/bucket-keys/{id}', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());

How long job history is kept

GET /nib/settings/retention

Needs org:read: See org, members, usage

Default 90 days.

Returns

  • 200 Type: Retention
    The retention settings
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/settings/retention · curl
curl "https://api.unforged.sh/nib/settings/retention" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/settings/retention · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/settings/retention",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/settings/retention · Node.js
const res = await fetch('https://api.unforged.sh/nib/settings/retention', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "history_retention": 90,
  "default": true,
  "results_lifecycle_days": 90,
  "audit_log_retention_days": 400
}

Set how long job history is kept

PUT /nib/settings/retention

Needs org:settings:manage: Retention, org-wide settings, the API version pin

Finished jobs and their files are deleted once older than this. Uploaded inputs go sooner, inbox_ttl after the check (24 h by default).

Returns

  • 200 Type: Retention
    The new settings
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 413 Type: Problem
    too_large
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
PUT /nib/settings/retention · curl
curl -X PUT "https://api.unforged.sh/nib/settings/retention" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
PUT /nib/settings/retention · Python
import requests

r = requests.put(
    "https://api.unforged.sh/nib/settings/retention",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
PUT /nib/settings/retention · Node.js
const res = await fetch('https://api.unforged.sh/nib/settings/retention', {
  method: 'PUT',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "history_retention": 90,
  "default": true,
  "results_lifecycle_days": 90,
  "audit_log_retention_days": 400
}

Reference learning settings

GET /nib/settings/learning

Needs org:read: See org, members, usage

Defaults: off, 0.90, 0.95, 10.

Returns

  • 200 Type: LearningView
    The learning settings
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /nib/settings/learning · curl
curl "https://api.unforged.sh/nib/settings/learning" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /nib/settings/learning · Python
import requests

r = requests.get(
    "https://api.unforged.sh/nib/settings/learning",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /nib/settings/learning · Node.js
const res = await fetch('https://api.unforged.sh/nib/settings/learning', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());
Response 200
{
  "reference_learning": "confirmed_only",
  "learn_min_band_lo": 0.9,
  "learn_min_probability": 0.95,
  "max_learned": 10,
  "terms_accepted": {
    "terms_version": "2026-09-27",
    "accepted_by": "user:user_01ABCDEF",
    "accepted_at": "2026-09-27T12:00:00.000Z"
  }
}

Set the reference learning settings

PUT /nib/settings/learning

Needs nib:settings:manage: Policy, learning, templates, webhooks, bucket keys

Replaces the settings; an omitted learn_min_probability is set to its default. Turning learning on needs the terms accepted (409 learning_terms_required).

Request body

LearningSettings

  • reference_learning required Type: "off" "confirmed_only" "confirmed_and_auto"

    off (default), confirmed_only, or confirmed_and_auto (also AUTO_APPROVE items).

  • learn_min_band_lo required Type: number

    The lower bound of the match score a candidate must reach (0.5–1, default 0.90).

  • learn_min_probability optional Type: number

    The match score a candidate must reach (0.5–1, default 0.95). Optional on write; an omitted value is set to its default.

  • max_learned required Type: integer

    Most learned references kept per subject (0–50, default 10).

Returns

  • 200 Type: LearningSettings
    The new settings
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 409 Type: Problem
    conflict, idempotency_conflict, idempotency_in_progress or idempotency_not_replayable
  • 413 Type: Problem
    too_large
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
PUT /nib/settings/learning · curl
curl -X PUT "https://api.unforged.sh/nib/settings/learning" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14" \
  -H "Content-Type: application/json" \
  -d '{
  "reference_learning": "confirmed_only",
  "learn_min_band_lo": 0.99,
  "max_learned": 10
}'
PUT /nib/settings/learning · Python
import requests

r = requests.put(
    "https://api.unforged.sh/nib/settings/learning",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
    json={
        "reference_learning": "confirmed_only",
        "learn_min_band_lo": 0.99,
        "max_learned": 10
    },
)
print(r.json())
PUT /nib/settings/learning · Node.js
const res = await fetch('https://api.unforged.sh/nib/settings/learning', {
  method: 'PUT',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "reference_learning": "confirmed_only",
    "learn_min_band_lo": 0.99,
    "max_learned": 10
  }),
});
console.log(await res.json());
Response 200
{
  "reference_learning": "confirmed_only",
  "learn_min_band_lo": 0.9,
  "learn_min_probability": 0.95,
  "max_learned": 10
}