Contents

Nib API

Check signatures against the references you hold.

  • api.unforged.sh
  • Version 2026-10-14
  • nib.yaml

Quickstart

Your first check takes about five minutes. The commands carry your pinned version.

Quickstart

  1. 01Enrol a person’s reference signatures
  2. 02Check one document or a whole batch
  3. 03Read inline, by webhook, or as files
1 · enrol
# 1 · enrol: a reference signature for your customer cust-88
curl -X PUT https://api.unforged.sh/nib/subjects/cust-88/references \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14" \
  -H "Idempotency-Key: enrol-cust-88-1" \
  -F [email protected]
2 · check
# 2 · check: a document, with your own references
curl -X POST https://api.unforged.sh/nib/checks \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14" \
  -H "Idempotency-Key: app-1042" \
  -F 'request={"process":"loan-application","items":[{"file":"q","subject_reference":"cust-88","reference":"APP-1042"}]};type=application/json' \
  -F [email protected]
3 · read
# 3 · read: a queued job's status and results
curl https://api.unforged.sh/nib/checks/app-1042 \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
find by your reference
# find a check again by your reference
curl "https://api.unforged.sh/nib/checks?view=items&reference=APP-1042" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"

Your references

subject_reference
your id for the person · 1–128 of A–Z a–z 0–9 . _ -
reference
your id for the document · 1–128 characters
process
the workflow · 1–64 of a–z 0–9 . _ -
metadata
up to 20 string pairs · keys 1–40, values up to 500

They come back everywhere: the result, the job, the stream, webhooks and bucket files.

Drop files in nib/inbox/<job>/, write manifest.json last. The answer lands in nib/results/<job>/.

bucket drop
# any S3 tool, with your bucket's keys: the files first, the manifest last
aws s3 cp ./batch/ s3://$UNFORGED_BUCKET/nib/inbox/2026-10-batch-07/ --recursive
aws s3 cp manifest.json s3://$UNFORGED_BUCKET/nib/inbox/2026-10-batch-07/manifest.json

# nib/inbox/2026-10-batch-07/manifest.json
{
  "items": [
    {
      "file": "app-1041.pdf",
      "subject_reference": "cust-88",
      "template_id": "benefits-form-v3",
      "reference": "APP-1041"
    },
    {
      "file": "app-1042.jpg",
      "references": [
        "refs/extra-1042.png"
      ],
      "target": {
        "page": 1,
        "box": "applicant_signature"
      },
      "reference": "APP-1042",
      "metadata": {
        "branch": "leeds"
      }
    }
  ],
  "policy": "default",
  "process": "loan-application"
}

# the answer: nib/results/2026-10-batch-07/summary.json
# (one result per line in nib/results/2026-10-batch-07/results.ndjson)
{
  "job_id": "inv-2291",
  "status": "completed",
  "total": 2,
  "completed": 1,
  "failed": 1,
  "counts": {
    "APPROVE": 1
  },
  "errors": [
    {
      "item_index": 1,
      "file": "missing.png",
      "field": null,
      "type": "file_not_found",
      "detail": "missing.png is not in the job folder"
    }
  ],
  "metadata": {
    "batch": "2026-10"
  },
  "versions": {
    "model": "nib-2.6",
    "policy": "default@7",
    "api_version": "2026-09-27"
  },
  "started_at": "2026-09-25T10:15:30.123Z",
  "completed_at": "2026-09-25T10:15:32.456Z"
}

One result per item: the same JSON inline, from GET, streamed, and in your bucket. See CheckResult.

CheckResult
{
  "id": "ver_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "item_index": 0,
  "kind": "check",
  "file": "questioned",
  "subject_reference": "cust-88",
  "reference": "APP-1042",
  "process": "loan-application",
  "metadata": {
    "branch": "leeds"
  },
  "status": "completed",
  "error": null,
  "decision": "APPROVE",
  "input_type": "photo",
  "pages": 1,
  "notes": [],
  "signatures": [
    {
      "index": 0,
      "page": 1,
      "bbox": [
        412,
        1880,
        498,
        160
      ],
      "located_by": "template",
      "quality": {
        "ok": true,
        "effective_dpi": 214,
        "sharpness": 812.5,
        "contrast": 180,
        "issues": []
      },
      "match_probability": 0.94,
      "band": [
        0.88,
        0.97
      ],
      "reference_count": 2,
      "per_reference": [
        {
          "ref": "ref_01j9x3m8v7k2q4r5s6t7u8v9w1",
          "probability": 0.95
        },
        {
          "ref": "ref_01j9x3m8v7k2q4r5s6t7u8v9w2",
          "probability": 0.92
        }
      ],
      "flags": [],
      "decision": "APPROVE",
      "reasons": [
        "Compared against 2 references",
        "Overall appearance is within this writer's usual range",
        "Shape alignment is within this writer's usual range",
        "Approved, not auto-approved: the lowest likely score (88.0%) is under the auto-approve bar (97.0%), and auto-approve is off in policy default@7"
      ],
      "best_match": true
    }
  ],
  "anchor_probability": 0.94,
  "signer_match": null,
  "versions": {
    "model": "nib-2.6",
    "policy": "default@7",
    "api_version": "2026-09-27"
  },
  "input_hashes": {
    "questioned": "sha256:8550d9b6affca27a5645d75b058479d2e081b16a135e2d4255e5e83714ebf987",
    "references": [
      "sha256:070a8e98f85afe04ba05542428664ec3684db24bc356133c11d41f9fab27f135",
      "sha256:1cf1da50e3f0be0b50197022be0eedf20fa688cf20ca1154b388098a9d2e29e1"
    ]
  },
  "timings_ms": {
    "total": 1840
  }
}

Signed with Unforged-Signature, rendered in your pinned version (Unforged-Version). Retried with backoff for 24 hours.

  • job.completed
  • job.failed
  • reference.enrolled
  • reference.rejected
a delivery
POST /your/webhook HTTP/1.1
Content-Type: application/json
Unforged-Signature: t=1790000000,v1=5f2c…
Unforged-Version: 2026-10-14
Unforged-Event-Id: evt_01j9x3m8v7k2q4r5s6t7u8v9w0

{
  "id": "evt_01j9x3m8v7k2q4r5s6t7u8v9w0",
  "type": "job.completed",
  "created_at": "2026-09-25T10:15:30.123Z",
  "data": {
    "job_id": "inv-2291",
    "status": "completed",
    "total": 1,
    "counts": {
      "APPROVE": 1
    },
    "failed": 0,
    "items": [
      {
        "id": "ver_01j9x3m8v7k2q4r5s6t7u8v9w0",
        "item_index": 0,
        "kind": "check",
        "file": "questioned",
        "subject_reference": "cust-88",
        "reference": "APP-1042",
        "process": "loan-application",
        "metadata": {
          "branch": "leeds"
        },
        "status": "completed",
        "error": null,
        "decision": "APPROVE",
        "input_type": "photo",
        "pages": 1,
        "notes": [],
        "signatures": [],
        "anchor_probability": 0.94,
        "signer_match": null,
        "versions": {
          "model": "nib-2.6",
          "policy": "default@7",
          "api_version": "2026-09-27"
        },
        "input_hashes": null,
        "timings_ms": {
          "total": 1840
        }
      }
    ],
    "items_truncated": false,
    "versions": {
      "model": "nib-2.6",
      "policy": "default@7",
      "api_version": "2026-09-27"
    },
    "status_url": "/nib/checks/inv-2291"
  }
}

# verify: HMAC-SHA256 of "<t>.<raw body>" with your whsec_ secret equals v1
  1. 01Add a custom connector with https://api.unforged.sh/mcp
  2. 02Sign in and choose your organisation
  3. 03Ask about your records, checks and queue

With an API key instead of signing in:

Claude Code
claude mcp add --transport http unforged https://api.unforged.sh/mcp \
  --header "Authorization: Bearer $UNFORGED_API_KEY"

The whole integration

The whole integration

  1. PUT /nib/subjects/{subject_reference}/references

    Enrol references, with where each came from.

  2. POST /nib/checks

    One document answers inline. A batch returns a job.

  3. GET /nib/checks/{job_id}

    Status and results, paged or streamed as NDJSON.

  4. Webhooks

    Signed. Retried with backoff for 24 hours.

Resources

All 71 Nib schemas

Webhook events

  • job.completed
  • job.failed
  • reference.enrolled
  • reference.rejected
  • webhook.test