Skip to main content

Deployer Documentation

Build a governance deployer on RANKIGI

Publish canons, define seal types, issue verifiable credentials, and receive webhook notifications. Everything a deployer needs to operate as a third-party authority on the RANKIGI governance layer.

01 Overview

Governance deployers

A governance deployer is a third-party authority that publishes a canon, defines seal types under it, and issues seals to agents. RANKIGI hosts the canon registry, witnesses every issuance into the append-only chain, and exposes a public verification API. The deployer holds the policy judgment and the Ed25519 signing key. RANKIGI holds the evidence.

What you publish is a canon document, a versioned policy artifact with scope, requirements, regulation references, and one or more seal type definitions. Once published, any agent operator can be evaluated against your canon. When they pass, you issue a signed seal. Anyone can verify the seal independently against the chain.

This is for regulators, industry consortia, professional bodies, certification authorities, and anyone whose signature on an agent today carries weight offline.

02 Getting Started

From application to first canon

  1. Apply. Submit your deployer profile at rankigi.com/deployers. Provide organization, jurisdiction, contact, and publisher URL.
  2. Review. The RANKIGI team reviews every application. Approval typically lands within five business days. You will receive a status email at the contact address you registered.
  3. Generate your Ed25519 signing key. Keep the private key offline. Upload only the public key to your deployer profile.
  4. Receive your API key. Once approved, you will be issued a key with the prefix rnk_dep_live_ (production) or rnk_dep_test_ (sandbox). The key is shown once.
  5. Publish your first canon. See section 4 below. Once accepted, the canon is publicly listed.

03 The Canon Format

Anatomy of a canon document

Canons are authored as Markdown with a structured YAML body. Every field is required unless marked optional. Field definitions follow the example.

markdown
# .canon.md
# Canon: EVIDE Financial Witness v1.0
# Deployer: evide
# Version: 1.0.0
# Jurisdiction: US, EU
# Spec: https://github.com/rcr-standard/spec

id:               evide.financial-witness
deployer_id:      evide
version:          1.0.0
title:            Financial Transaction Witness
description:      Witnesses a financial-impact action with regulator-grade evidence.

scope:
  - financial_transaction
  - settlement
  - refund

requirements:
  - signed_invocation
  - counterparty_receipt
  - rfc3161_timestamp

seal_types:
  - id:                       evide.financial-witness.tier-1
    name:                     Financial Witness Tier 1
    description:              Issued when all required evidence is present.
    validity_period_days:     90
    evaluation_criteria:      every required row in evaluation_snapshot must pass.

regulation_refs:
  - SOC 2 CC4.1
  - SOX 404
  - EU AI Act Art. 12

publisher_signature: ed25519:<base64>

Field reference

  • id stable dot-namespaced identifier under your deployer slug.
  • deployer_id must match the slug on your deployer profile.
  • version semver. Republishing the same id with a new version creates a new canon row; old versions remain queryable.
  • title human readable name shown in the public canon registry.
  • description one paragraph. Surfaced in verify pages and the registry.
  • scope array of action labels this canon covers.
  • requirements array of evidence labels every passing evaluation must include.
  • seal_types one or more typed credentials issuable under this canon. Each carries an id, name, description, validity period, and free-text evaluation criteria.
  • regulation_refs optional array of external regulatory citations.
  • publisher_signature Ed25519 signature over the canonical JSON of the canon document with the signature field elided.

04 Publishing a Canon

Submit through the dashboard or the API

In the dashboard, navigate to Deployer → Canons → New canon. Paste the Markdown body, attach the publisher signature hex, and click Publish. The response shows the canon id and an immediate public registry URL.

Or from your shell:

bash
curl -X POST https://rankigi.com/api/v1/canons \
  -H "Authorization: Bearer rnk_dep_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d @canon.json

The response includes the canon id, version, and the recomputed canonical hash that RANKIGI verified against your publisher signature. Mismatch returns HTTP 400.

05 Defining Seal Types

Add or update issuable credentials under a canon

Seal types live inside a canon document. The seal_types array in the canon is the source of truth; the explicit API below lets you append a new seal type without republishing the whole canon.

bash
curl -X POST https://rankigi.com/api/v1/seals \
  -H "Authorization: Bearer rnk_dep_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "canon_id":             "evide.financial-witness",
    "canon_version":        "1.0.0",
    "name":                 "Financial Witness Tier 1",
    "description":          "Issued when all required evidence is present.",
    "validity_period_days": 90,
    "evaluation_criteria":  "every required row in evaluation_snapshot must pass."
  }'

The response returns the assigned seal_type_id that you will pass to the issuance endpoint.

06 Issuing Seals

Bind a seal type to an agent

Issuance takes an evaluation_snapshot, an array of evidence rows you evaluated against the canon requirements. RANKIGI recomputes the canonical SHA-256 of the snapshot and verifies your Ed25519 signature over the hash hex before persisting the row. The deployer is the policy authority; RANKIGI is the witness.

bash
curl -X POST https://rankigi.com/api/v1/seals/<sealTypeId>/issue \
  -H "Authorization: Bearer rnk_dep_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id":       "agent_8f3e2b1a",
    "passport_id":    "RNK-AGENT-9K2M4PQR",
    "evaluation_snapshot": [
      { "label": "signed_invocation",    "passed": true, "required": true },
      { "label": "counterparty_receipt", "passed": true, "required": true },
      { "label": "rfc3161_timestamp",    "passed": true, "required": true }
    ],
    "snapshot_hash":      "sha256:<recomputed_hex>",
    "evaluation_window":  { "from": "2026-05-01T00:00:00Z", "to": "2026-05-31T23:59:59Z" },
    "expires_at":         "2026-08-30T00:00:00Z",
    "issuer_signature":   "ed25519:<base64_signature_over_hash_hex>"
  }'

On success the response carries the persisted seal row, the RANKIGI countersignature, the chain event id, and the resulting public verify URL.

07 Verifying Credentials

Check an issued seal end-to-end

The test endpoint accepts a seal id and a passport id. It reconstructs the snapshot hash, verifies both signatures, walks the chain to confirm the seal_issued event is intact, and returns a structured result.

bash
curl -X POST https://rankigi.com/api/v1/test \
  -H "Authorization: Bearer rnk_dep_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "passport_id": "RNK-AGENT-9K2M4PQR",
    "seal_id":     "agent_seal_uuid_here"
  }'

A successful response:

json
{
  "ok":                true,
  "result":            "pass",
  "passport_id":       "RNK-AGENT-9K2M4PQR",
  "seal": {
    "id":              "agent_seal_uuid_here",
    "canon_id":        "evide.financial-witness",
    "canon_version":   "1.0.0",
    "issued_at":       "2026-05-31T17:42:09Z",
    "expires_at":      "2026-08-30T00:00:00Z",
    "is_valid":        true
  },
  "snapshot_hash":     "sha256:9c1a...",
  "issuer_signature":  "ed25519:...",
  "countersignature":  "ed25519:...",
  "chain_event_id":    "evt_chain_uuid",
  "verified_by":       "RANKIGI Open Agent Governance Standard v1.0"
}

08 Webhooks

Receive event notifications

Register an HTTPS endpoint to receive signed event notifications. RANKIGI POSTs a JSON envelope with a signature header. The HMAC secret is returned exactly once at registration time and is never recoverable from the API. Persist it server-side at the moment of creation.

Register a webhook

bash
curl -X POST https://rankigi.com/api/deployer/webhooks \
  -H "Authorization: Bearer rnk_dep_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://hooks.your-domain.com/rankigi",
    "events": ["canon.agent_registered", "seal.issued", "seal.expired"]
  }'

Response:

json
{
  "id":         "wh_uuid",
  "url":        "https://hooks.your-domain.com/rankigi",
  "secret":     "whsec_<64 hex chars shown once and never again>",
  "events":     ["canon.agent_registered", "seal.issued", "seal.expired"],
  "created_at": "2026-05-31T17:42:09Z"
}

Event types

  • canon.agent_registered An agent has been registered against one of your canons.
  • seal.issued A seal of one of your defined types has been issued to an agent.
  • seal.expired A previously issued seal has passed its expires_at timestamp.

Signature header format

Every delivery includes two headers:

  • X-RNK-Webhook-Signature: t=<unix_seconds>,v1=<hex_hmac>
  • X-RNK-Webhook-Id: <uuid>

The HMAC is HMAC-SHA256(secret, `$${t}.$${body}`). Verify by reconstructing the signed string from the raw request body, recomputing the HMAC with your stored secret, and comparing in constant time.

Node.js verification

typescript
import crypto from "node:crypto";
import express from "express";

const app = express();

// Stash the raw body so we can recompute the signature byte-for-byte.
app.use(express.json({
  verify: (req, _res, buf) => { (req as any).rawBody = buf.toString("utf8"); },
}));

const WEBHOOK_SECRET = process.env.RANKIGI_WEBHOOK_SECRET!;
const TOLERANCE_SECONDS = 300; // reject replays older than 5 minutes

app.post("/rankigi", (req, res) => {
  const header = req.header("X-RNK-Webhook-Signature") ?? "";
  const parts  = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=") as [string, string]),
  );
  const t  = parts.t;
  const v1 = parts.v1;
  if (!t || !v1) return res.status(400).end();

  const ageSec = Math.abs(Math.floor(Date.now() / 1000) - Number(t));
  if (ageSec > TOLERANCE_SECONDS) return res.status(400).end();

  const expected = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(t + "." + (req as any).rawBody)
    .digest("hex");

  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(v1, "hex");
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).end();
  }

  // Signature OK. Handle the event.
  const event = req.body;
  switch (event.type) {
    case "seal.issued":             handleSealIssued(event.data);    break;
    case "seal.expired":            handleSealExpired(event.data);   break;
    case "canon.agent_registered":  handleRegistered(event.data);    break;
  }
  return res.status(204).end();
});

Reject deliveries with a timestamp more than 5 minutes off wall clock and respond 2xx within 5 seconds. Non-2xx responses increment failure_count on the webhook row.

09 API Reference

Endpoint summary

MethodPathAuthDescription
POST/api/v1/canonsBearer rnk_dep_...Publish a canon document. Body is the parsed canon JSON.
POST/api/v1/sealsBearer rnk_dep_...Define a new seal type inside one of your canons.
POST/api/v1/seals/{sealTypeId}/issueBearer rnk_dep_...Issue a seal to a specific agent with an evaluation snapshot.
POST/api/v1/testBearer rnk_dep_...Verify a previously issued seal and its passport binding.
POST/api/deployer/webhooksBearer rnk_dep_...Register a webhook. Secret is returned once in the response.
GET/api/deployer/webhooksBearer rnk_dep_...List every webhook owned by the calling deployer.
GET/api/deployer/webhooks/{webhookId}Bearer rnk_dep_...Fetch detail for a single webhook including delivery stats.
DELETE/api/deployer/webhooks/{webhookId}Bearer rnk_dep_...Soft delete (is_active=false). Audit history is preserved.

10 Getting Help

Contact and community

Email deployers@rankigi.com for application status, API support, canon review questions, and integration help. The RANKIGI team responds within one business day.

For canon authoring conventions and the underlying RCR/1 receipt specification, see the open spec repository at github.com/rcr-standard/spec. File issues and pull requests there.