When an agent calls your API, knowing whether it has been seen before can help your application provide continuity. This tutorial shows how to resolve an agent proof and handle the result in a server-side endpoint.
Resolve an incoming agent proof and handle recognized, unknown, and unavailable identity evidence.
What you will build
Add a server-side endpoint that resolves an incoming agent proof and returns a different response for recognized agents, unknown visitors, and unavailable identity evidence. Attribution provides evidence for your application's access policy; recognition alone does not authorize an action.
You need Node.js or Python, a Chitmark workspace with Attribution enabled, a Test key with attribution:read, and your site's exact public HTTPS origin. To test recognition, you also need an enrolled agent and a fresh proof for that site. The two-website example walks through enrollment and signing.
Install the SDK and configure your site
Use SDK version 0.9.0 or later for network proofs. Create a Test API key with attribution:read in your site's workspace. Set CHITMARK_API_KEY on the server and set CHITMARK_SITE to your exact public HTTPS origin, for example https://app.example.com without a trailing slash. The SDK uses https://api.chitmark.com by default.
Give the visiting agent your workspace ID, recipient key record ID, origin, environment, purpose and data mode. Keep the bearer credential on your server. The agent sends a fresh Chitmark-Agent-Proof header for those values. The defaults are identity_attribution and hashed.
Node.js
npm install @chitmark/sdk Python
python -m pip install chitmark flask Add an endpoint
Set CHITMARK_API_KEY to your Test read key and CHITMARK_SITE to your public HTTPS origin, such as https://app.example.com. Save the Node.js example as attribution.mjs or the Python example as attribution.py. The server listens on 127.0.0.1:3000. Its configured site is used for resolution, not a client-supplied Host header.
Run node attribution.mjs or python attribution.py. Then run curl http://127.0.0.1:3000/agent-task without a proof. You should see Unknown visitor.
Node.js
import { createServer } from "node:http"; import { Chitmark, ChitmarkError } from "@chitmark/sdk"; const site = process.env.CHITMARK_SITE; const apiKey = process.env.CHITMARK_API_KEY; if (!site || !apiKey) throw new Error("Configure CHITMARK_SITE and CHITMARK_API_KEY"); const piiMode = process.env.CHITMARK_ATTRIBUTION_PII_MODE === "raw" ? "raw" : "hashed"; const chitmark = new Chitmark({ apiKey, piiMode }); createServer(async (incoming, response) => { if (incoming.url !== "/agent-task") { response.writeHead(404).end(); return; } response.setHeader("Cache-Control", "no-store"); try { const result = await chitmark.attribution.resolve({ site, request: { url: incoming.url ?? "/", headers: incoming.headers, }, }); if (process.env.CHITMARK_FIXTURE_LOG === "1") { console.log(result.identity.recognized); console.log(result.principal.email); } if (!result.identity.recognized) { response.end("Unknown visitor"); return; } if (result.principal.status === "previously_verified") { const email = result.principal.email; response.end( email === null ? "Recognized agent; verified principal; email unavailable" : "Recognized agent; verified principal; email authorized", ); return; } response.end("Recognized agent; principal unavailable"); } catch (error) { if (!(error instanceof ChitmarkError)) throw error; response.writeHead(503).end("Identity evidence unavailable"); } }).listen(3000, "127.0.0.1"); Python
import os from flask import Flask, request from chitmark import Chitmark, ChitmarkError app = Flask(__name__) site = os.environ["CHITMARK_SITE"] pii_mode = "raw" if os.getenv("CHITMARK_ATTRIBUTION_PII_MODE") == "raw" else "hashed" client = Chitmark(api_key=os.environ["CHITMARK_API_KEY"], pii_mode=pii_mode) @app.get("/agent-task") def agent_task(): headers = {"Cache-Control": "no-store"} try: result = client.attribution.resolve(request=request, site=site) except ChitmarkError: return "Identity evidence unavailable", 503, headers identity = result["identity"] principal = result["principal"] if not identity["recognized"]: return "Unknown visitor", 200, headers if principal["status"] == "previously_verified": email = principal["email"] message = ( "Recognized agent; verified principal; email unavailable" if email is None else "Recognized agent; verified principal; email authorized" ) return message, 200, headers return "Recognized agent; principal unavailable", 200, headers if __name__ == "__main__": app.run(port=3000) Exercise each result
| Test | Expected behavior |
|---|---|
| No proof and no separate session evidence | The endpoint returns Unknown visitor. |
| Fresh proof for this site from an enrolled agent | The agent is recognized. Principal details can still be withheld. |
| Recognized agent with a disclosure grant | The principal can be previously verified; email can still be unavailable. |
| Attribution service unavailable | The endpoint returns 503; do not treat the failure as recognition. |
Use the two-website example to generate a fresh proof for the exact recipient, environment, purpose, and data mode, then include it in the Chitmark-Agent-Proof header. Repeat with a proof for another site or a revoked binding and check the unknown path. Test failures by temporarily making the service unreachable in a test environment.
Use the site's scoped identity.subject_id for continuity, and apply your own authorization before protected work. Keep API keys, proof headers, and personal data out of logs. Email disclosure requires the appropriate grant, consent, plan, scope, and raw mode; see the quickstart.
Read the full guide on Chitmark.