API reference
The API behind ghazaryantech.com: the JVM it runs on, and the lab's experiments, which run here on the server rather than in the browser. It is public and needs no key.
- Base URL
https://ghazaryantech.com- Version
- 1
- The document
- OpenAPI 3.1.0, as JSON
Before the first call
Versions
Every operation takes the API-Version header. The version of the API to answer with: 1 without the header. Any version but 1 is refused with 400 UNSUPPORTED_API_VERSION.
Limits
The experiments are limited per client address, each by a policy of its own, named in its entry. A response to one says where the client stands, and a refusal, 429, when to come back:
RateLimit-Policy- The operation's policy, per client address: its name, the quota
qand the windowwin seconds, as in"search";q=10;w=60. RateLimit- Where the client stands in the policy:
rrequests left andt, the seconds until one more is allowed, as in"search";r=9;t=6. Sent with refusals too. Retry-After- Seconds to wait before trying again: rounded up, never 0.
Streams
Some experiments report as they go: they answer text/event-stream, named events with JSON data, which each entry lists. A failure after the stream has begun arrives as an error event carrying a problem. A browser's EventSource opens a closed stream again, so close it on the last event.
Errors
An RFC 9457 problem: what went wrong, for a person in detail and for a program in code. Each entry lists its codes by status: a program switches on the code, never on the detail, which is written for people and may change.
typeoptional- stringThe kind of problem. Absent, it is about:blank: the status says it all.
title- stringThe status's reason phrase.
status- integerThe HTTP status.
detail- stringWhat went wrong, for a person.
instanceoptional- stringThe request's path; absent from a stream's error event.
code- stringWhat went wrong, for a program: stable across releases, unlike the detail.
{
"detail": "n must be between 0 and 1000000",
"instance": "/api/lab/fibonacci",
"status": 400,
"title": "Bad Request",
"code": "N_OUT_OF_RANGE"
}Runtime
The JVM this API runs on, and its database.
The database and its migrations
GET/api/database
The PostgreSQL server's version and the Flyway migrations applied: whether the database is there, and up to date. 503 without one.
- Answers with
- DatabaseInfo
- Limit per address
- 30 requests a minute, policy
database - Operation id
getDatabase
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-10-03. The response to GET /api/database. Arrays are cut to their first 4 items.
{
"version": "17.11",
"migrations": [
{
"version": "1",
"description": "lab schema",
"installedOn": "2026-10-03T05:23:22.166415Z",
"success": true
},
{
"version": "2",
"description": "ledger",
"installedOn": "2026-10-03T05:56:28.695017Z",
"success": true
},
{
"version": "3",
"description": "catalogue",
"installedOn": "2026-10-03T07:52:57.560606Z",
"success": true
},
{
"version": "4",
"description": "outbox",
"installedOn": "2026-10-03T16:00:34.010216Z",
"success": true
}
]
}The JVM this API runs on
GET/api/runtime
Java version and vendor, the VM, Spring Boot's version, CPUs, the largest heap, the garbage collectors, start time, uptime, the Cloud Run revision, and how the JVM was started: its collector, its AOT cache, compact object headers, its -XX options (never system properties) and the memory it sees.
- Answers with
- RuntimeInfo
- Limit per address
- None
- Operation id
getRuntime
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-03. The response to GET /api/runtime. Arrays are cut to their first 4 items.
{
"javaVersion": "25.0.4.1",
"javaVendor": "Eclipse Adoptium",
"vm": "OpenJDK 64-Bit Server VM",
"springBootVersion": "4.1.1",
"availableProcessors": 1,
"maxHeapBytes": 389283840,
"garbageCollectors": [
"Copy",
"MarkSweepCompact"
],
"startedAt": "2026-10-03T18:04:10.604Z",
"uptimeMs": 6144,
"revision": null,
"jvm": {
"collector": "Serial",
"aotCache": "api.aot",
"aotCacheInUse": true,
"compactObjectHeaders": true,
"flags": [
"-XX:MaxRAMPercentage=75",
"-XX:InitialRAMPercentage=25",
"-XX:+ExitOnOutOfMemoryError",
"-XX:+UseSerialGC"
],
"memoryLimitBytes": 536870912
}
}One sample of the JVM
GET/api/telemetry
Heap and non-heap memory, collections and their time, threads, CPU load and loaded classes, now.
- Answers with
- TelemetrySample
- Limit per address
- None
- Operation id
getTelemetry
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-03. The response to GET /api/telemetry.
{
"t": 1791050656747,
"uptimeMs": 6203,
"heap": {
"used": 28988208,
"committed": 129761280,
"max": 389283840
},
"nonHeapUsed": 23555400,
"gc": [
{
"name": "Copy",
"count": 4,
"timeMs": 74
},
{
"name": "MarkSweepCompact",
"count": 0,
"timeMs": 0
}
],
"threads": {
"live": 22,
"daemon": 18,
"peak": 22
},
"cpu": {
"process": 0.3,
"system": 0.297
},
"classesLoaded": 11718
}The JVM, every second
GET/api/telemetry/stream
Server-sent events: first history, up to the last 90 samples, oldest first; then sample every second; after 120 s, end with {"reason":"max-duration"}. Streams are capped in number. Close the stream on end: a browser's EventSource would otherwise open it again.
- Answers with
- server-sent events
- Limit per address
- 20 requests a minute, policy
telemetry-stream - Operation id
streamTelemetry
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
TOO_MANY_STREAMSAs many live streams are open as the server serves.
A recorded stream
Recorded on 2026-10-03. The stream that answered GET /api/telemetry/stream. Of its 123 events, the first and the last of each kind.
event:history
data:[{"t":1791050656059,"uptimeMs":5515,"heap":{"used":41680216,"committed":129761280,"max":389283840},"nonHeapUsed":15566672,"gc":[{"name":"Copy","count":3,"timeMs":59},{"name":"MarkSweepCompact","count":0,"timeMs":0}],"threads":{"live":16,"daemon":12,"peak":16},"cpu":{"process":0.975,"system":0.978},"classesLoaded":10568}]
event:sample
data:{"t":1791050656700,"uptimeMs":6157,"heap":{"used":27984808,"committed":129761280,"max":389283840},"nonHeapUsed":23348312,"gc":[{"name":"Copy","count":4,"timeMs":74},{"name":"MarkSweepCompact","count":0,"timeMs":0}],"threads":{"live":22,"daemon":18,"peak":22},"cpu":{"process":1.0,"system":1.0},"classesLoaded":11681}
: 119 events left out
event:sample
data:{"t":1791050776053,"uptimeMs":125515,"heap":{"used":41824256,"committed":129761280,"max":389283840},"nonHeapUsed":41230288,"gc":[{"name":"Copy","count":12,"timeMs":108},{"name":"MarkSweepCompact","count":0,"timeMs":0}],"threads":{"live":24,"daemon":20,"peak":226},"cpu":{"process":0.025,"system":0.003},"classesLoaded":12920}
event:end
data:{"reason":"max-duration"}
Lab: the JVM
Experiments on the server's JVM: each answers with what it measured, on this machine, just now.
Five ways to compute F(n)
GET/api/lab/fibonacci
Naive recursion, memoized recursion, a loop, matrix exponentiation and fast doubling, on BigInteger. Each reports OK with the median of up to five timed runs after warm-up, or SKIPPED with the reason, STACK_OVERFLOW or TIMEOUT. Two races compute at a time; a third waits two seconds, then 429 BUSY.
- Answers with
- FibonacciReport
- Limit per address
- 30 requests a minute, policy
fibonacci - Operation id
runFibonacci
Parameters
nquery, required- integer0 to 1,000,000
- Which Fibonacci number
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.N_OUT_OF_RANGEnis outside 0 to 1,000,000.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/fibonacci?n=90. Arrays are cut to their first 4 items.
{
"n": 90,
"digits": 19,
"leadingDigits": "2880067194370816120",
"trailingDigits": "2880067194370816120",
"value": "2880067194370816120",
"results": [
{
"algorithm": "NAIVE_RECURSION",
"label": "Naive recursion",
"complexity": "O(φⁿ)",
"status": "SKIPPED",
"nanos": null,
"runs": 0,
"operations": null,
"maxDepth": null,
"note": "Skipped above n = 40: would need ≈9.3×10^18 calls"
},
{
"algorithm": "MEMOIZED_RECURSION",
"label": "Memoized recursion",
"complexity": "O(n)",
"status": "OK",
"nanos": 10653,
"runs": 5,
"operations": 179,
"maxDepth": 90,
"note": null
},
{
"algorithm": "ITERATIVE",
"label": "Iterative",
"complexity": "O(n) additions",
"status": "OK",
"nanos": 4695,
"runs": 5,
"operations": 89,
"maxDepth": null,
"note": null
},
{
"algorithm": "MATRIX_POWER",
"label": "Matrix exponentiation",
"complexity": "O(log n) multiplications",
"status": "OK",
"nanos": 16122,
"runs": 5,
"operations": 80,
"maxDepth": null,
"note": null
}
],
"environment": {
"javaVersion": "25.0.4.1",
"availableProcessors": 1
}
}Watch the JIT compile, then deoptimise
GET/api/lab/jit
A cold copy of a small loop, in a class loader of its own, timed in 240 batches as its call site meets one, two, then four receiver types, with the compilations and deoptimisations Flight Recorder reported for it, each placed in its batch. One benchmark at a time on the server.
- Answers with
- JitReport
- Limit per address
- 10 requests a minute, policy
jit - Operation id
runJit
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
JIT_UNAVAILABLEFlight Recorder is not available on this server.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/jit. Arrays are cut to their first 4 items.
{
"completed": true,
"callsPerBatch": 20000,
"batches": [
{
"index": 0,
"shape": "MONOMORPHIC",
"nanos": 487827
},
{
"index": 1,
"shape": "MONOMORPHIC",
"nanos": 301288
},
{
"index": 2,
"shape": "MONOMORPHIC",
"nanos": 323336
},
{
"index": 3,
"shape": "MONOMORPHIC",
"nanos": 292164
}
],
"events": [
{
"batch": 0,
"kind": "COMPILED",
"method": "Shapes.Circle.<init>",
"detail": "c1, tier 2"
},
{
"batch": 0,
"kind": "COMPILED",
"method": "Shapes.Circle.area",
"detail": "c1, tier 2"
},
{
"batch": 3,
"kind": "COMPILED",
"method": "Shapes.totalArea",
"detail": "c1, tier 3, on-stack replacement"
},
{
"batch": 3,
"kind": "COMPILED",
"method": "Shapes.totalArea",
"detail": "c1, tier 3"
}
],
"summary": {
"firstNanos": 487827,
"monomorphicNanos": 66602,
"bimorphicNanos": 71202,
"megamorphicNanos": 54182
}
}A memory leak on a real collector
GET/api/lab/leak/stream
Server-sent events: a JVM of its own, 64 MB of heap, runs the leak or its fix under Serial, G1 or ZGC. start; gc for every collection that reports the heap; stopped for every quarter second in which the application stood still; then end with OUT_OF_MEMORY and when, or SURVIVED after 20 s; or error.
- Answers with
- server-sent events
- Limit per address
- 6 requests a minute, policy
leak - Operation id
streamLeak
Parameters
collectorquery, requiredSERIAL,G1orZ- The garbage collector the child JVM runs
policyquery, requiredLEAKorFIX- LEAK, a map that never lets go; FIX, weak values with a time to live
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
LEAK_UNAVAILABLEThe server cannot start the JVM a run needs.
erroran event, once the stream has begunLEAK_UNAVAILABLEThe server cannot start the JVM a run needs.CANCELLEDThe run was stopped before it finished, as when the server shuts down.TIMEOUTThe run took too long and was stopped.CHILD_FAILEDThe run's JVM ended without finishing it.
A recorded stream
Recorded on 2026-10-03. The stream that answered GET /api/lab/leak/stream?collector=Z&policy=FIX. Of its 130 events, the first and the last of each kind.
event:start
data:{"collector":"Z","policy":"FIX","heapMB":64,"seconds":20}
event:gc
data:{"at":90,"gcId":0,"name":"Major Collection (Warmup)","beforeMB":8,"afterMB":8,"includesOld":true}
: 2 events left out
event:stopped
data:{"from":0,"stopped":{"pauses":15,"pauseMillis":0.128,"longestPauseMillis":0.063,"stalls":0,"stallMillis":0.0}}
: 122 events left out
event:gc
data:{"at":19678,"gcId":70,"name":"Major Collection (Proactive)","beforeMB":32,"afterMB":18,"includesOld":true}
event:stopped
data:{"from":19500,"stopped":{"pauses":8,"pauseMillis":0.058,"longestPauseMillis":0.015,"stalls":0,"stallMillis":0.0}}
event:end
data:{"outcome":"SURVIVED","atMillis":20000,"collections":71,"oldCollections":49,"stopped":{"pauses":311,"pauseMillis":1.971,"longestPauseMillis":0.063,"stalls":0,"stallMillis":0.0}}
Where the time goes, by Flight Recorder
GET/api/lab/profiler
A scenario profiled while it runs: its flame graph, hottest frames, monitor waits, allocation by class and collections, as the problem or as its fix. One benchmark at a time on the server.
- Answers with
- ProfileReport
- Limit per address
- 10 requests a minute, policy
profiler - Operation id
runProfiler
Parameters
scenarioquery, requiredHOT_LOCK,ALLOCATION_CHURNorQUADRATIC_DEDUPE- The workload to profile
variantquery, requiredPROBLEMorFIX- PROBLEM, as written first; FIX, as it should be
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
INTERRUPTEDThe run was interrupted, as when the server shuts down.PROFILER_UNAVAILABLEFlight Recorder is not available on this server.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/profiler?scenario=HOT_LOCK&variant=PROBLEM.
{
"scenario": "HOT_LOCK",
"variant": "PROBLEM",
"completed": true,
"wallMs": 2274,
"threads": 4,
"checksum": "10000000",
"samples": 199,
"tree": {
"name": "all",
"total": 199,
"self": 0,
"children": [
{
"name": "HotLock.incrementUnderMonitor",
"total": 199,
"self": 83,
"children": [
{
"name": "HotLock.Counter.increment",
"total": 116,
"self": 116,
"children": []
}
]
}
]
},
"hottest": [
{
"frame": "HotLock.Counter.increment",
"self": 116,
"share": 0.583
},
{
"frame": "HotLock.incrementUnderMonitor",
"self": 83,
"share": 0.417
}
],
"locks": {
"waits": 8266,
"totalMs": 3187,
"monitor": "HotLock.Counter"
},
"allocations": {
"sampledBytes": 0,
"byClass": []
},
"gc": {
"collections": 1,
"pauseTotalMs": 10,
"longestPauseMs": 10
}
}Platform threads against virtual threads
GET/api/lab/threads/stream
Server-sent events: the same workload on a fixed pool of platform threads, then on virtual threads. start and result for each, progress between, then done. Each result carries pinnedEvents, the virtual phase's pinning count from Flight Recorder. One benchmark at a time on the server.
- Answers with
- server-sent events
- Limit per address
- 6 requests a minute, policy
threads - Operation id
streamThreads
Parameters
tasksquery, required- integer1 to 20,000
- Tasks to run
ioMillisquery, required- integer1 to 1,000
- Milliseconds each task sleeps, or computes
poolSizequery, required- integer1 to 1,000
- Platform threads in the fixed pool
workloadquery, requiredIO,SYNCHRONIZED,NATIVEorCPU- Sleep, sleep holding a monitor, sleep beneath a native frame, or compute
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.TASKS_OUT_OF_RANGEtasksis outside 1 to 20,000.IO_MILLIS_OUT_OF_RANGEioMillisis outside 1 to 1,000.POOL_SIZE_OUT_OF_RANGEpoolSizeis outside 1 to 1,000.CPU_BUDGET_EXCEEDEDThe CPU workload asks for more computation than a run may spend: tasks × ioMillis is capped.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
NATIVE_UNAVAILABLEThe NATIVE workload's native frame could not be linked on this server.
erroran event, once the stream has begunCANCELLEDThe run was stopped before it finished, as when the server shuts down.INTERNAL_ERRORSomething failed on the server's side.
A recorded stream
Recorded on 2026-10-03. The stream that answered GET /api/lab/threads/stream?tasks=2000&ioMillis=20&poolSize=100&workload=IO. Of its 19 events, the first and the last of each kind.
event:start
data:{"executor":"PLATFORM","tasks":2000,"poolSize":100,"workload":"IO","ioMillis":20,"carrierThreads":1}
event:progress
data:{"executor":"PLATFORM","completed":400,"elapsedMs":100}
: 3 events left out
event:result
data:{"executor":"PLATFORM","tasks":2000,"completed":2000,"wallMs":415,"throughputPerSec":4817.5,"waitP50Ms":180,"waitP99Ms":378,"timedOut":false,"peakLiveThreads":128,"pinnedEvents":null}
event:start
data:{"executor":"VIRTUAL","tasks":2000,"poolSize":null,"workload":"IO","ioMillis":20,"carrierThreads":1}
: 9 events left out
event:progress
data:{"executor":"VIRTUAL","completed":2000,"elapsedMs":997}
event:result
data:{"executor":"VIRTUAL","tasks":2000,"completed":2000,"wallMs":25,"throughputPerSec":78456.2,"waitP50Ms":1,"waitP99Ms":3,"timedOut":false,"peakLiveThreads":28,"pinnedEvents":0}
event:done
data:{}
The ThreadLocal trap
GET/api/lab/threads/thread-locals
For each way of getting a date formatter, on each executor, the formatters created, heap allocated per task and wall time: a ThreadLocal cache that works on a pool of platform threads creates one per task on virtual threads.
- Answers with
- ThreadLocalReport
- Limit per address
- 6 requests a minute, policy
threads - Operation id
runThreadLocals
Parameters
tasksquery, required- integer1 to 20,000
- Tasks to run
poolSizequery, required- integer1 to 1,000
- Platform threads in the fixed pool
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.TASKS_OUT_OF_RANGEtasksis outside 1 to 20,000.POOL_SIZE_OUT_OF_RANGEpoolSizeis outside 1 to 1,000.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
INTERRUPTEDThe run was interrupted, as when the server shuts down.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/threads/thread-locals?tasks=10000&poolSize=200. Arrays are cut to their first 4 items.
{
"tasks": 10000,
"poolSize": 200,
"carrierThreads": 1,
"cells": [
{
"source": "THREAD_LOCAL",
"executor": "PLATFORM",
"formattersCreated": 200,
"allocatedBytesPerTask": 706,
"wallMicros": 210484
},
{
"source": "THREAD_LOCAL",
"executor": "VIRTUAL",
"formattersCreated": 10000,
"allocatedBytesPerTask": 2831,
"wallMicros": 116645
},
{
"source": "PER_CALL",
"executor": "PLATFORM",
"formattersCreated": 10000,
"allocatedBytesPerTask": 2394,
"wallMicros": 269622
},
{
"source": "PER_CALL",
"executor": "VIRTUAL",
"formattersCreated": 10000,
"allocatedBytesPerTask": 2700,
"wallMicros": 27316
}
]
}Lab: PostgreSQL
Experiments on a real PostgreSQL: a connection pool, transactions, search and delivery.
Reconcile the ledger
GET/api/lab/ledger/reconciliation
The drift between cached balances and entries, as the last run left it.
- Answers with
- Reconciliation
- Limit per address
- 30 requests a minute, policy
database - Operation id
getReconciliation
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/ledger/reconciliation.
{
"accountsDrifted": 0,
"moneyCreated": 0,
"moneyDestroyed": 0,
"worst": []
}A ledger under concurrent transfers
POST/api/lab/ledger/runs
Resets the ledger, makes the same 1,000 transfers from 16 connections under one strategy, then checks four invariants by SQL and reconciles cached balances against entries. A POST: it rewrites the ledger. The response names the run's traceId.
- Answers with
- LedgerReport
- Limit per address
- 6 requests a minute, policy
ledger - Operation id
runLedger
Parameters
strategyquery, requiredREAD_MODIFY_WRITE,GUARDED_UPDATE,LOCK_UNORDERED,LOCK_ORDERED,OPTIMISTICorSERIALIZABLE- How a transfer moves the money
hotSpotquery, required- integer0 to 100
- The share of transfers between four hot accounts, in per cent
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.HOT_SPOT_OUT_OF_RANGEhotSpotis outside 0 to 100.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.INTERRUPTEDThe run was interrupted, as when the server shuts down.
A recorded response
Recorded on 2026-10-03. The response to POST /api/lab/ledger/runs?strategy=LOCK_ORDERED&hotSpot=20.
{
"strategy": "LOCK_ORDERED",
"hotSpotPercent": 20,
"transfers": 1000,
"workers": 16,
"committed": 1000,
"insufficientFunds": 0,
"gaveUp": 0,
"failed": 0,
"notStarted": 0,
"deadlocks": 0,
"serializationFailures": 0,
"conflicts": 0,
"elapsedMs": 1115,
"throughput": 896.2,
"latencyP50Ms": 4,
"latencyP99Ms": 158,
"invariants": [
{
"name": "Money is neither created nor destroyed",
"holds": true,
"detail": "100,000.00 in all, as at the start"
},
{
"name": "No balance below zero",
"holds": true,
"detail": "every account covers itself"
},
{
"name": "Every transfer’s entries sum to zero",
"holds": true,
"detail": "the database refuses any that do not"
},
{
"name": "Balances agree with the entries",
"holds": true,
"detail": "reconciliation finds nothing"
}
],
"reconciliation": {
"accountsDrifted": 0,
"moneyCreated": 0,
"moneyDestroyed": 0,
"worst": []
},
"traceId": "768f8b85a124217574c2aa423fd75119"
}An outbox under crash injection
POST/api/lab/outbox/runs
Places 500 orders under one of three designs while processes die at chosen moments, then counts on the database what was lost, invented, sent again and done again. A POST: it empties the experiment's tables.
- Answers with
- OutboxReport
- Limit per address
- 6 requests a minute, policy
outbox - Operation id
runOutbox
Parameters
designquery, requiredCOMMIT_THEN_PUBLISH,PUBLISH_THEN_COMMITorOUTBOX- How the service saves and announces an order
crashPercentquery, required- integer0 to 50
- The chance of dying at each crash point, each time one is reached
dedupquery- booleantrue by default
- Whether the consumer acts on each message id once
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.CRASH_PERCENT_OUT_OF_RANGEcrashPercentis outside 0 to 50.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.INTERRUPTEDThe run was interrupted, as when the server shuts down.
A recorded response
Recorded on 2026-10-03. The response to POST /api/lab/outbox/runs?design=OUTBOX&crashPercent=10&dedup=true.
{
"design": "OUTBOX",
"crashPercent": 10,
"dedup": true,
"orders": 500,
"answered": 446,
"committed": 446,
"published": 446,
"duplicatePublishes": 58,
"lost": 0,
"phantoms": 0,
"deliveries": 566,
"effects": 446,
"duplicateEffects": 0,
"missingEffects": 0,
"effectsWithoutOrder": 0,
"crashes": {
"BETWEEN_WRITES": 0,
"RELAY_AFTER_PUBLISH": 58,
"CONSUMER_AFTER_EFFECT": 62,
"BEFORE_COMMIT": 54
},
"restarts": 120,
"elapsedMs": 2602,
"verdicts": [
{
"name": "Every saved order was announced",
"holds": true,
"detail": "the broker has an event for every order"
},
{
"name": "Nothing was announced that did not happen",
"holds": true,
"detail": "every event has its order"
},
{
"name": "Every order was acted on exactly once",
"holds": true,
"detail": "one action per saved order, none for anything else"
}
]
}Ten thousand threads, twenty connections
GET/api/lab/pool/stream
Server-sent events: requests on virtual threads against a PostgreSQL pool of the run's own, for 5 s, under an admission policy. start (with the pool's ceiling by Little's law, and the run's traceId), progress every 200 ms, result, then done; error when the pool cannot be opened.
- Answers with
- server-sent events
- Limit per address
- 6 requests a minute, policy
pool - Operation id
streamPool
Parameters
poolSizequery, required- integer5 to 20
- Connections in the run's pool
holdMillisquery, required- integer10 to 500
- How long each request holds its connection
ratequery, required- integer10 to 1,000
- Requests arriving each second
policyquery, requiredUNBOUNDED,THROTTLEorFAIL_FAST- What a request does when every connection is taken
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.POOL_SIZE_OUT_OF_RANGEpoolSizeis outside 5 to 20.HOLD_MILLIS_OUT_OF_RANGEholdMillisis outside 10 to 500.RATE_OUT_OF_RANGErateis outside 10 to 1,000.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.
erroran event, once the stream has begunDATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.CANCELLEDThe run was stopped before it finished, as when the server shuts down.INTERNAL_ERRORSomething failed on the server's side.
A recorded stream
Recorded on 2026-10-03. The stream that answered GET /api/lab/pool/stream?poolSize=10&holdMillis=50&rate=500&policy=THROTTLE. Of its 67 events, the first and the last of each kind.
event:start
data:{"spec":{"poolSize":10,"holdMillis":50,"ratePerSecond":500,"policy":"THROTTLE"},"requests":2500,"capacityPerSecond":200.0,"connectionTimeoutMs":1000,"traceId":"5fb11f17c661cff72c3895fd7b917c95"}
event:progress
data:{"elapsedMs":201,"arrived":101,"completed":30,"timedOut":0,"rejected":0,"holding":10,"waitingForConnection":0,"waitingAtGate":61}
: 62 events left out
event:progress
data:{"elapsedMs":12683,"arrived":2500,"completed":2500,"timedOut":0,"rejected":0,"holding":0,"waitingForConnection":0,"waitingAtGate":0}
event:result
data:{"requests":2500,"completed":2500,"timedOut":0,"rejected":0,"cutOff":0,"failed":0,"elapsedMs":12683,"throughput":197.1,"capacityPerSecond":200.0,"latencyP50Ms":3861,"latencyP99Ms":7627,"acquireP50Ms":0,"acquireP99Ms":0}
event:done
data:{}
Search a million rows four ways
GET/api/lab/search
The same words in a catalogue of a million products: ILIKE on every row, the same ILIKE on a trigram index, word similarity, full text. Each counts every match, returns ten, and is explained by PostgreSQL.
- Answers with
- SearchReport
- Limit per address
- 10 requests a minute, policy
search - Operation id
runSearch
Parameters
qquery, required- string1 to 60 charactersmatches
^[^\x00-\x1F\x7F]*$ - The words, trimmed: at most 60 characters, no control characters
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.Q_INVALIDqbreaks a constraint its schema gives.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.BUSYThe server is running another benchmark, or its lab workers are all taken.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-10-03. The response to GET /api/lab/search?q=walnut%20desk. Arrays are cut to their first 4 items.
{
"query": "walnut desk",
"catalogue": {
"products": 1000000,
"bytes": 262594560
},
"methods": [
{
"method": "SCAN",
"outcome": "COMPLETED",
"total": 1995,
"top": [
{
"id": 776484,
"title": "Alder & Co Scandinavian walnut desk, charcoal",
"category": "Tables",
"priceCents": 38356,
"score": null
},
{
"id": 386607,
"title": "Alder & Co Scandinavian walnut desk, ivory",
"category": "Tables",
"priceCents": 43950,
"score": null
},
{
"id": 54282,
"title": "Alder & Co Scandinavian walnut desk, ochre",
"category": "Tables",
"priceCents": 95455,
"score": null
},
{
"id": 173738,
"title": "Alder & Co classic walnut desk, terracotta",
"category": "Tables",
"priceCents": 29096,
"score": null
}
],
"plan": {
"access": "EVERY_ROW",
"index": null,
"workers": 2,
"rowsRead": 999999,
"blocksHit": 4163,
"blocksRead": 17396,
"planningMs": 0.126,
"executionMs": 424.019,
"steps": [
{
"depth": 0,
"node": "Limit",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 1,
"node": "WindowAgg",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 2,
"node": "Gather Merge",
"on": null,
"rows": 1995,
"loops": 1
},
{
"depth": 3,
"node": "Sort",
"on": null,
"rows": 665,
"loops": 3
}
]
}
},
{
"method": "TRIGRAM",
"outcome": "COMPLETED",
"total": 1995,
"top": [
{
"id": 776484,
"title": "Alder & Co Scandinavian walnut desk, charcoal",
"category": "Tables",
"priceCents": 38356,
"score": null
},
{
"id": 386607,
"title": "Alder & Co Scandinavian walnut desk, ivory",
"category": "Tables",
"priceCents": 43950,
"score": null
},
{
"id": 54282,
"title": "Alder & Co Scandinavian walnut desk, ochre",
"category": "Tables",
"priceCents": 95455,
"score": null
},
{
"id": 173738,
"title": "Alder & Co classic walnut desk, terracotta",
"category": "Tables",
"priceCents": 29096,
"score": null
}
],
"plan": {
"access": "INDEX",
"index": "products_title_trgm",
"workers": 0,
"rowsRead": 1995,
"blocksHit": 2175,
"blocksRead": 0,
"planningMs": 0.109,
"executionMs": 9.666,
"steps": [
{
"depth": 0,
"node": "Limit",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 1,
"node": "Sort",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 2,
"node": "WindowAgg",
"on": null,
"rows": 1995,
"loops": 1
},
{
"depth": 3,
"node": "Bitmap Heap Scan",
"on": "products",
"rows": 1995,
"loops": 1
}
]
}
},
{
"method": "TYPO",
"outcome": "COMPLETED",
"total": 1995,
"top": [
{
"id": 899,
"title": "Fenwick classic walnut desk, black",
"category": "Tables",
"priceCents": 71261,
"score": 1
},
{
"id": 1245,
"title": "Brume vintage walnut desk, ochre",
"category": "Tables",
"priceCents": 84226,
"score": 1
},
{
"id": 1339,
"title": "Alder & Co curved walnut desk, white",
"category": "Tables",
"priceCents": 91197,
"score": 1
},
{
"id": 1566,
"title": "Ashby tall walnut desk, white",
"category": "Tables",
"priceCents": 38831,
"score": 1
}
],
"plan": {
"access": "INDEX",
"index": "products_title_trgm",
"workers": 0,
"rowsRead": 3597,
"blocksHit": 3707,
"blocksRead": 0,
"planningMs": 0.383,
"executionMs": 37.53,
"steps": [
{
"depth": 0,
"node": "Limit",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 1,
"node": "Sort",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 2,
"node": "WindowAgg",
"on": null,
"rows": 1995,
"loops": 1
},
{
"depth": 3,
"node": "Bitmap Heap Scan",
"on": "products",
"rows": 1995,
"loops": 1
}
]
}
},
{
"method": "FULL_TEXT",
"outcome": "COMPLETED",
"total": 1995,
"top": [
{
"id": 899,
"title": "Fenwick classic walnut desk, black",
"category": "Tables",
"priceCents": 71261,
"score": 0.09910322
},
{
"id": 1245,
"title": "Brume vintage walnut desk, ochre",
"category": "Tables",
"priceCents": 84226,
"score": 0.09910322
},
{
"id": 1339,
"title": "Alder & Co curved walnut desk, white",
"category": "Tables",
"priceCents": 91197,
"score": 0.09910322
},
{
"id": 1566,
"title": "Ashby tall walnut desk, white",
"category": "Tables",
"priceCents": 38831,
"score": 0.09910322
}
],
"plan": {
"access": "INDEX",
"index": "products_search",
"workers": 0,
"rowsRead": 1995,
"blocksHit": 2027,
"blocksRead": 0,
"planningMs": 0.05,
"executionMs": 4.428,
"steps": [
{
"depth": 0,
"node": "Limit",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 1,
"node": "Sort",
"on": null,
"rows": 10,
"loops": 1
},
{
"depth": 2,
"node": "WindowAgg",
"on": null,
"rows": 1995,
"loops": 1
},
{
"depth": 3,
"node": "Bitmap Heap Scan",
"on": "products",
"rows": 1995,
"loops": 1
}
]
}
}
]
}Lab: payments
A simulated 3-D Secure 2 access control server: an AReq checked, weighed against the exemptions from strong customer authentication, and answered, with a challenge where one is due.
Send an AReq to a simulated ACS
POST/api/lab/threeds/authentications
An AReq of EMV 3-D Secure 2.2.0, as a 3DS Server would send it: a JSON object of string elements, a subset of the specification's, flat; at most 80 of them, each at most 4,096 characters. The simulated ACS checks it, answering an invalid one with an Erro; asks its risk rules, among them the exemptions from strong customer authentication; and answers with an ARes: authenticated without friction, a challenge, not authenticated or rejected. Every message on the way, the rules' reasoning and the time each hop takes.
- Answers with
- ThreeDsRun
- Limit per address
- 30 requests a minute, policy
threeds - Operation id
runThreeDsAuthentication
Body
application/jsonrequired- map of stringat most 80 entriesnames up to 64 charactersvalues up to 4,096 characters
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.AREQ_INVALIDareqbreaks a constraint its schema gives.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-04. The response to POST /api/lab/threeds/authentications. Arrays are cut to their first 4 items.
{
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"phase": "CHALLENGED",
"transStatus": null,
"steps": [
{
"from": "3DS Server",
"to": "ACS",
"via": "Directory Server",
"message": "AReq",
"fields": {
"messageType": "AReq",
"messageVersion": "2.2.0",
"deviceChannel": "02",
"messageCategory": "01",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"threeDSServerRefNumber": "3DS-SERVER-EXAMPLE-01",
"threeDSServerURL": "https://3ds-server.example/results",
"threeDSRequestorID": "requestor-0001",
"threeDSRequestorName": "Example Shop",
"threeDSRequestorURL": "https://shop.example",
"threeDSRequestorAuthenticationInd": "01",
"threeDSCompInd": "Y",
"acctNumber": "4111111111111111",
"acquirerBIN": "400551",
"acquirerMerchantID": "merchant-0001",
"mcc": "5732",
"merchantCountryCode": "276",
"merchantName": "Example Shop",
"purchaseAmount": "75000",
"purchaseCurrency": "978",
"purchaseExponent": "2",
"purchaseDate": "20261004120000",
"browserAcceptHeader": "text/html,application/xhtml+xml",
"browserJavaEnabled": "false",
"browserJavascriptEnabled": "true",
"browserLanguage": "en-GB",
"browserColorDepth": "24",
"browserScreenHeight": "900",
"browserScreenWidth": "1440",
"browserTZ": "-240",
"browserUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"notificationURL": "https://shop.example/3ds/notify",
"addrMatch": "Y",
"dsTransID": "6224dbca-ce3e-4e0e-a3c3-5e2be56a98db",
"dsReferenceNumber": "DS-SIMULATED-01",
"dsURL": "https://ds.example/results"
},
"note": "As the 3DS Server sent it, with what the directory server adds on the way: dsTransID, dsReferenceNumber and dsURL."
},
{
"from": "ACS",
"to": "3DS Server",
"via": "Directory Server",
"message": "ARes",
"fields": {
"messageType": "ARes",
"messageVersion": "2.2.0",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"acsReferenceNumber": "ACS-SIMULATED-01",
"dsTransID": "6224dbca-ce3e-4e0e-a3c3-5e2be56a98db",
"dsReferenceNumber": "DS-SIMULATED-01",
"transStatus": "C",
"acsChallengeMandated": "Y",
"authenticationType": "02",
"acsURL": "https://acs.example/challenge"
},
"note": "A challenge: the 3DS Server is to send the cardholder’s browser to the acsURL."
},
{
"from": "3DS Server",
"to": "ACS",
"via": "Browser",
"message": "CReq",
"fields": {
"messageType": "CReq",
"messageVersion": "2.2.0",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"challengeWindowSize": "05"
},
"note": "Posted through the cardholder’s browser to the acsURL."
},
{
"from": "ACS",
"to": "Browser",
"via": null,
"message": "Challenge page",
"fields": {
"page": "Enter the code we sent by text message to •••• 0042."
},
"note": "The ACS’s own page in the cardholder’s browser, not a 3-D Secure message."
}
],
"rules": [
{
"rule": "Card on record",
"decided": false,
"words": "The issuer knows the card."
},
{
"rule": "Not reported stolen",
"decided": false,
"words": "The card is not reported lost or stolen."
},
{
"rule": "Cardholder present",
"decided": false,
"words": "The cardholder is there, in a browser or an app."
},
{
"rule": "Requestor’s mandate",
"decided": false,
"words": "The requestor mandates no challenge."
}
],
"challenge": {
"sentTo": "•••• 0042",
"code": "845323",
"triesLeft": 3
},
"valueCheck": null,
"budget": [
{
"name": "AReq: 3DS Server to directory server",
"millis": 40,
"measured": false
},
{
"name": "AReq: directory server to ACS",
"millis": 40,
"measured": false
},
{
"name": "The ACS: the check and the rules",
"millis": 44.64375,
"measured": true
},
{
"name": "ARes: ACS to directory server",
"millis": 40,
"measured": false
}
]
}Answer a challenge
POST/api/lab/threeds/authentications/{acsTransID}/challenge
The cardholder's code for a transaction the ACS challenged, for five minutes after it did. A right code ends the challenge authenticated, a third wrong one ends it failed; either way with the RReq, the RRes and the final CRes.
- Answers with
- ThreeDsRun
- Limit per address
- 30 requests a minute, policy
threeds - Operation id
runThreeDsChallenge
Parameters
acsTransIDpath, required- stringmatches
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ - The ACS's id for the transaction, from its ARes
Body
application/jsonrequired- ThreeDsLabController.Answer
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.ACS_TRANS_ID_INVALIDacsTransIDbreaks a constraint its schema gives.CODE_INVALIDcodebreaks a constraint its schema gives.
- 404Not Found
CHALLENGE_NOT_FOUNDNo challenge with that id is waiting: it ended, its five minutes passed, or it never began.
- 409Conflict
CHALLENGE_ENDEDAnother answer ended the challenge while this one was on its way.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-04. The response to POST /api/lab/threeds/authentications/4047e5c5-b8d6-4f1f-b971-1dc97734deb3/challenge. Arrays are cut to their first 4 items.
{
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"phase": "AUTHENTICATED",
"transStatus": "Y",
"steps": [
{
"from": "Browser",
"to": "ACS",
"via": null,
"message": "Challenge page",
"fields": {
"code": "845323"
},
"note": "The cardholder’s code, posted to the ACS’s page."
},
{
"from": "ACS",
"to": "3DS Server",
"via": "Directory Server",
"message": "RReq",
"fields": {
"messageType": "RReq",
"messageVersion": "2.2.0",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"dsTransID": "6224dbca-ce3e-4e0e-a3c3-5e2be56a98db",
"messageCategory": "01",
"authenticationType": "02",
"interactionCounter": "01",
"transStatus": "Y",
"eci": "05",
"authenticationValue": "VkF21zQ2iZjlS4gndDrGKNdZ4DM="
},
"note": "How the challenge ended, with the authentication value for the authorisation."
},
{
"from": "3DS Server",
"to": "ACS",
"via": "Directory Server",
"message": "RRes",
"fields": {
"messageType": "RRes",
"messageVersion": "2.2.0",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"dsTransID": "6224dbca-ce3e-4e0e-a3c3-5e2be56a98db",
"resultsStatus": "01"
},
"note": "The 3DS Server has the results."
},
{
"from": "ACS",
"to": "3DS Server",
"via": "Browser",
"message": "CRes",
"fields": {
"messageType": "CRes",
"messageVersion": "2.2.0",
"threeDSServerTransID": "8a880dc0-d2d2-4067-bcb1-b08d1690b26e",
"acsTransID": "4047e5c5-b8d6-4f1f-b971-1dc97734deb3",
"challengeCompletionInd": "Y",
"transStatus": "Y"
},
"note": "The last CRes, posted through the browser to the notificationURL: the cardholder is back at the merchant."
}
],
"rules": [],
"challenge": null,
"valueCheck": {
"amount": "€750.00",
"checks": true,
"otherAmount": "€750.01",
"checksForOther": false
},
"budget": [
{
"name": "The code: browser to ACS",
"millis": 40,
"measured": false
},
{
"name": "The ACS: the code checked",
"millis": 4.411184,
"measured": true
},
{
"name": "RReq: ACS to directory server",
"millis": 40,
"measured": false
},
{
"name": "RReq: directory server to 3DS Server",
"millis": 40,
"measured": false
}
]
}Traces
What OpenTelemetry recorded while a lab run ran: its spans, kept in memory for a while.
A run's trace
GET/api/traces/{traceId}
Every span of a recent pool or ledger run, by the id its result carried: parent, start, duration, attributes. The server keeps the last 8 traces, in memory.
- Answers with
- RunTrace
- Limit per address
- 30 requests a minute, policy
traces - Operation id
getTrace
Parameters
traceIdpath, required- stringmatches
^[0-9a-f]{32}$ - The trace's id, 32 hexadecimal digits
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.TRACE_ID_INVALIDtraceIdbreaks a constraint its schema gives.
- 404Not Found
TRACE_NOT_FOUNDNo trace with that id is kept: the server keeps the last runs' traces only.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-03. The response to GET /api/traces/5fb11f17c661cff72c3895fd7b917c95. Arrays are cut to their first 4 items.
{
"traceId": "5fb11f17c661cff72c3895fd7b917c95",
"durationMs": 13153.35,
"spans": [
{
"id": "2da16a10d34079ee",
"parentId": null,
"name": "http get /api/lab/pool/stream",
"startMs": 0,
"durationMs": 13153.35,
"attributes": {
"exception": "none",
"status": "200",
"http.url": "/api/lab/pool/stream",
"outcome": "SUCCESS",
"method": "GET",
"uri": "/api/lab/pool/stream"
},
"error": false
},
{
"id": "b38c5e8f619bd311",
"parentId": "2da16a10d34079ee",
"name": "lab.pool.run",
"startMs": 5.84,
"durationMs": 13145.49,
"attributes": {
"lab.hold.ms": "50",
"lab.policy": "THROTTLE",
"lab.pool.size": "10",
"lab.rate": "500"
},
"error": false
},
{
"id": "325be140c1f47906",
"parentId": "b38c5e8f619bd311",
"name": "lab.pool.fill",
"startMs": 6.24,
"durationMs": 451.82,
"attributes": {},
"error": false
},
{
"id": "00f28578c45720ce",
"parentId": "b38c5e8f619bd311",
"name": "lab.pool.request",
"startMs": 460.12,
"durationMs": 53.33,
"attributes": {
"request.outcome": "COMPLETED",
"request.index": "0"
},
"error": false
}
],
"dropped": 0
}Site
What the site's pages ask of it: a page view counted without cookies or anyone's address, an introduction taken, and a job posting checked against the record.
What the assistant can do here
GET/api/assistant
Whether an account ready for it could ask a question of its own now and, if not, why; how long a question may be and how many a conversation takes; and the examples, the prepared answers and the gate's demonstrations, which run on replies kept for them whatever the answer.
- Answers with
- PublicAssistant.Status
- Limit per address
- 30 requests a minute, policy
assistant-status - Operation id
getAssistantStatus
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-11-08. The response to GET /api/assistant. Arrays are cut to their first 4 items.
{
"live": true,
"off": null,
"offWords": null,
"questionCharacters": 500,
"questions": 12,
"sections": 69,
"examples": [
{
"name": "who",
"question": "Who is Armen?",
"about": "A question the record answers, from where he works and the areas he goes deep in.",
"source": "SCRIPTED",
"kind": "PREPARED",
"offers": []
},
{
"name": "stack",
"question": "What does he work with now?",
"about": "A question the record answers, from his current role.",
"source": "SCRIPTED",
"kind": "PREPARED",
"offers": []
},
{
"name": "three-d-secure",
"question": "What did he do on 3-D Secure?",
"about": "A question the record answers, from his years at Worldline and the area of expertise they back.",
"source": "SCRIPTED",
"kind": "PREPARED",
"offers": []
},
{
"name": "experience",
"question": "How many years of experience does he have?",
"about": "A question the record answers, from his roles and when Java began for him.",
"source": "SCRIPTED",
"kind": "PREPARED",
"offers": []
}
]
}Ask an example question
POST/api/assistant/examples/{name}/answers
Server-sent events: one of the example questions, answered on the reply kept for it through the same gate. No model is called, and nothing is spent. sentence for each sentence let through, with the sections of the site's record it cites, each with its title and address on the site; withheld for a sentence held back, with why: it named what nothing it cited mentions (and what), it cited nothing, it shared nothing with what it cited, or it spoke in the first person, as the owner; action for each thing the guide shows, in its place among the sentences: a page to open (show_page, with its path), something to point at (point_at), an experiment to run (run_experiment, with its preset and whether on the server), a tour to start (start_tour) or a next step to offer (offer), each with its label; then done, with the refusal and its words when there is no answer from the record, how many sentences were shown and held back, how many actions were taken, and who wrote the answer at what cost, its cache tokens and the time to its first word; error instead if the model fails on the way.
- Answers with
- server-sent events
- Limit per address
- 20 requests a minute, policy
assistant-examples - Operation id
streamAssistantExample
Parameters
namepath, required- stringmatches
^[a-z0-9-]{1,60}$ - The example's name, from the status
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.NAME_INVALIDnamebreaks a constraint its schema gives.
- 404Not Found
EXAMPLE_NOT_FOUNDThere is no example by that name.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
erroran event, once the stream has begunINTERNAL_ERRORSomething failed on the server's side.
A recorded stream
Recorded on 2026-11-08. The stream that answered POST /api/assistant/examples/leading/answers.
event:sentence
data:{"text":"At Picsart, Armen reviews code and mentors mid-level engineers.","citations":[{"id":"practice:reviews-and-mentoring","title":"How I work: Reviews and mentoring","url":"/#working"}]}
: 1 event left out
event:sentence
data:{"text":"He also takes part in CI/CD, observability with Datadog and ELK, and p99 latency and throughput tuning.","citations":[{"id":"practice:production","title":"How I work: Production","url":"/#working"}]}
event:done
data:{"refusal":null,"words":null,"shown":3,"withheld":0,"questionsLeft":null,"drafting":{"model":"scripted","source":"SCRIPTED","inputTokens":null,"outputTokens":null,"costUsd":null,"latencyMillis":10,"cacheReadTokens":null,"cacheWriteTokens":null,"firstTextMillis":null},"actions":0}
Find the prepared answer a question asks for
POST/api/assistant/match
A question typed without an account, matched to a prepared answer by the record's terms, the hiring topics and its words: the example's name to ask for, a refusal by rule (pay, private life) with its words, or neither, when only an account's question could answer it. No model is called, and nothing of the question is kept: what went unmatched is counted by the topics it names.
- Answers with
- PublicAssistant.Matched
- Limit per address
- 30 requests a minute, policy
assistant-match - Operation id
matchAssistantQuestion
Body
application/jsonrequired- AssistantController.Typed
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.QUESTION_INVALIDquestionbreaks a constraint its schema gives.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-11-08. The response to POST /api/assistant/match.
{
"example": "kafka",
"refusal": null,
"words": null
}A proof-of-work challenge for a fit check
GET/api/fit/challenge
A challenge by version 1 of ALTCHA's protocol, as for introductions but ten times the work, good for one fit check and ten minutes. Refused while a posting of one's own cannot run.
- Answers with
- Challenge
- Limit per address
- 10 requests a minute, policy
fit-check-challenges - Operation id
getFitCheckChallenge
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
FIT_CHECK_OFFA posting of one's own cannot be checked here now: the status says why.BUDGET_SPENTToday's budget for this is spent. It starts again at midnight UTC.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-10-03. The response to GET /api/fit/challenge.
{
"algorithm": "SHA-256",
"challenge": "b1e68bc88fb30dd592efa96486346e486f7178c06d3a69d4076bc7b940bd2ef8",
"maxnumber": 1000000,
"salt": "b6dbb258ca6b9cd624863497?expires=1791068410&purpose=fit-check&",
"signature": "c919b488b7dec71173429b88c2841c9a29ca371d03553598f28ba8e751156e52"
}Check an example posting
POST/api/fit/examples/{name}/runs
One of the example postings, run end to end on the replies kept for it: no model is called, and nothing is spent.
- Answers with
- FitResult
- Limit per address
- 20 requests a minute, policy
fit-check-examples - Operation id
runFitCheckExample
Parameters
namepath, required- stringmatches
^[a-z0-9-]{1,60}$ - The example's name, from the status
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.NAME_INVALIDnamebreaks a constraint its schema gives.
- 404Not Found
EXAMPLE_NOT_FOUNDThere is no example by that name.
- 422Unprocessable Content
NO_REQUIREMENTS_FOUNDThe posting asks for nothing a candidate could show.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-11-08. The response to POST /api/fit/examples/payments-tech-lead/runs. Arrays are cut to their first 4 items.
{
"requirements": [
{
"text": "7+ years of backend development in Java, including recent Spring Boot",
"must": true,
"rating": "DIRECT",
"claim": "Java in production since 2017: Synopsys, then Worldline, then Picsart, whose services are Java 21 and Spring Boot.",
"missing": "",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Synopsys: Java Developer (Dec 2017–Jul 2019)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Where I work from, and how",
"kind": "profile",
"url": "/#contact"
}
],
"withheld": false
},
{
"text": "Experience with card payments: 3-D Secure, PCI DSS, issuer or acquirer integrations",
"must": true,
"rating": "DIRECT",
"claim": "Three and a half years on 3-D Secure 2.x at Worldline: integrations with acquirers and issuers, PCI DSS, and the edge cases of the critical transaction path.",
"missing": "",
"evidence": [
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Payment security",
"kind": "expertise",
"url": "/#expertise"
}
],
"withheld": false
},
{
"text": "Production experience with PostgreSQL and Kafka",
"must": true,
"rating": "DIRECT",
"claim": "Event-driven pipelines on Kafka in production at Picsart, and Kafka with PostgreSQL and Oracle at Worldline.",
"missing": "",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
}
],
"withheld": false
},
{
"text": "Kubernetes in production, on AWS or GCP",
"must": true,
"rating": "DIRECT",
"claim": "Services on Kubernetes (GKE) at Picsart and on Kubernetes at Worldline; GCP and AWS are among the CV's cloud skills.",
"missing": "AWS is not described in a role.",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Skills on the CV: Cloud & delivery",
"kind": "skills",
"url": "/#experience"
}
],
"withheld": false
}
],
"withheld": 0,
"drafting": {
"model": "scripted",
"source": "SCRIPTED",
"calls": 2,
"inputTokens": null,
"outputTokens": null,
"costUsd": null,
"latencyMillis": 0
}
}What the fit check can do here
GET/api/fit/public
Whether a posting of your own can be checked now and, if not, why; how long it may be; and the examples, which run on replies kept for them whatever the answer.
- Answers with
- PublicFitChecks.Status
- Limit per address
- 30 requests a minute, policy
fit-check-status - Operation id
getFitCheckStatus
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-11-08. The response to GET /api/fit/public. Arrays are cut to their first 4 items.
{
"live": true,
"off": null,
"offWords": null,
"postingCharacters": 6000,
"examples": [
{
"name": "ai-backend",
"company": "Example Commerce",
"role": "Senior Backend Engineer, AI Features",
"about": "AI on record is generative AI at Picsart and this site’s own assistant; LLM APIs at work, prompt injection, multi-tenant SaaS, Python and retrieval-augmented generation are not.",
"source": "SCRIPTED"
},
{
"name": "hidden-instruction",
"company": "Example Robotics",
"role": "Senior Java Developer, Robotics Backend",
"about": "An attack: the posting tells the model to invent Rust and German, and the scripted reply obeys. The claim check catches every invention: a draft cannot be published until the owner fixes it, and a visitor's result withholds the claim.",
"source": "SCRIPTED"
},
{
"name": "munich-onsite",
"company": "Example Bank",
"role": "Java Developer, Munich",
"about": "The stack fits; German at C2 and five days on site in Munich do not, and the site does not say whether he would relocate.",
"source": "SCRIPTED"
},
{
"name": "payments-tech-lead",
"company": "Example Payments",
"role": "Tech Lead, Payments Platform",
"about": "A close fit on payments, Java and Kafka; mentoring is on record but leading a team is not, and the site says nothing of English or German.",
"source": "SCRIPTED"
}
]
}Check a posting
POST/api/fit/runs
Reads the posting's requirements with a language model, shortlists the evidence on this site for each in code, has the model rate each against its shortlist only, and checks every claim against the evidence it cites. Nothing of the posting is kept, and the result has no link: it is yours alone. A claim the check found naming what its evidence does not is withheld.
- Answers with
- FitResult
- Limit per address
- 3 requests an hour, policy
fit-check-runs - Operation id
runFitCheck
Body
application/jsonrequired- PublicFitCheckController.Posting
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.POSTING_INVALIDpostingbreaks a constraint its schema gives.ALTCHA_INVALIDaltchabreaks a constraint its schema gives.PROOF_OF_WORK_EXPIREDThe challenge expired before it was used: solve a new one.PROOF_OF_WORK_INVALIDThe proof of work does not solve a challenge this server issued for this, or was used already.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 422Unprocessable Content
NO_REQUIREMENTS_FOUNDThe posting asks for nothing a candidate could show.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 502Bad Gateway
MODEL_REFUSEDThe model declined to answer.MODEL_REPLY_CUT_SHORTThe model's reply was cut short.MODEL_REPLY_MALFORMEDThe model's reply could not be read.MODEL_REQUEST_REJECTEDThe model's provider rejected the request.
- 503Service Unavailable
FIT_CHECK_OFFA posting of one's own cannot be checked here now: the status says why.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.MODEL_RATE_LIMITEDThe model's provider is limiting requests; try again in a minute.MODEL_OVERLOADEDThe model's provider is overloaded; try again shortly.MODEL_UNAVAILABLEThe model's provider cannot be reached.BUDGET_SPENTToday's budget for this is spent. It starts again at midnight UTC.MODEL_BUSYAs many calls as this allows are running; try again in a minute.
A recorded response
Recorded on 2026-11-08. The response to POST /api/fit/examples/payments-tech-lead/runs. No visitor's posting is recorded: an example's run, which answers in the same shape, stands in for one. Arrays are cut to their first 4 items.
{
"requirements": [
{
"text": "7+ years of backend development in Java, including recent Spring Boot",
"must": true,
"rating": "DIRECT",
"claim": "Java in production since 2017: Synopsys, then Worldline, then Picsart, whose services are Java 21 and Spring Boot.",
"missing": "",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Synopsys: Java Developer (Dec 2017–Jul 2019)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Where I work from, and how",
"kind": "profile",
"url": "/#contact"
}
],
"withheld": false
},
{
"text": "Experience with card payments: 3-D Secure, PCI DSS, issuer or acquirer integrations",
"must": true,
"rating": "DIRECT",
"claim": "Three and a half years on 3-D Secure 2.x at Worldline: integrations with acquirers and issuers, PCI DSS, and the edge cases of the critical transaction path.",
"missing": "",
"evidence": [
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Payment security",
"kind": "expertise",
"url": "/#expertise"
}
],
"withheld": false
},
{
"text": "Production experience with PostgreSQL and Kafka",
"must": true,
"rating": "DIRECT",
"claim": "Event-driven pipelines on Kafka in production at Picsart, and Kafka with PostgreSQL and Oracle at Worldline.",
"missing": "",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
}
],
"withheld": false
},
{
"text": "Kubernetes in production, on AWS or GCP",
"must": true,
"rating": "DIRECT",
"claim": "Services on Kubernetes (GKE) at Picsart and on Kubernetes at Worldline; GCP and AWS are among the CV's cloud skills.",
"missing": "AWS is not described in a role.",
"evidence": [
{
"title": "Picsart: Senior Software Engineer (Jan 2023–now)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Worldline: Java Developer, Payment Security (3-D Secure) (Jul 2019–Jan 2023)",
"kind": "role",
"url": "/#experience"
},
{
"title": "Skills on the CV: Cloud & delivery",
"kind": "skills",
"url": "/#experience"
}
],
"withheld": false
}
],
"withheld": 0,
"drafting": {
"model": "scripted",
"source": "SCRIPTED",
"calls": 2,
"inputTokens": null,
"outputTokens": null,
"costUsd": null,
"latencyMillis": 0
}
}Say that a tour started or finished
POST/api/guide/events
Tours play in the browser without a model, so the page says when one starts and when one ends, by the tour's id, and the guide's daily counts take it; nothing else in the body is read. A request with Sec-GPC: 1 or DNT: 1, or one another site's page sent, is answered alike and not counted.
- Answers with
- no content, 204
- Limit per address
- 30 requests a minute, policy
guide-events - Operation id
recordGuideEvent
Body
application/jsonrequired- GuideEventController.Event
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.EVENT_INVALIDeventbreaks a constraint its schema gives.TOUR_INVALIDtourbreaks a constraint its schema gives.TOUR_UNKNOWNThere is no tour by that id in the site's manifest.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
Draft an introduction
POST/api/introductions
Who you are and what you want to say, with a solved challenge in altcha, and, if you choose, your conversation with the site's guide in conversation, as text. The draft comes back as it will be kept, with the token that confirms it; it waits 30 minutes for that. Leave website out: it is there for programs that fill in every field.
- Answers with
- Preview
- Limit per address
- 10 requests an hour, policy
introductions - Operation id
draftIntroduction
Body
application/jsonrequired- Draft
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.UNREADABLE_BODYThe body is not the JSON the operation takes.NAME_INVALIDnamebreaks a constraint its schema gives.EMAIL_INVALIDemailbreaks a constraint its schema gives.COMPANY_INVALIDcompanybreaks a constraint its schema gives.ROLE_INVALIDrolebreaks a constraint its schema gives.MESSAGE_INVALIDmessagebreaks a constraint its schema gives.CONVERSATION_INVALIDconversationbreaks a constraint its schema gives.ALTCHA_INVALIDaltchabreaks a constraint its schema gives.TOO_MANY_LINKSThe message carries more links than a few words to a person would.CONVERSATION_TOO_MANY_LINKSThe conversation sent with the introduction carries more links than a conversation with the guide would.PROOF_OF_WORK_EXPIREDThe challenge expired before it was used: solve a new one.PROOF_OF_WORK_INVALIDThe proof of work does not solve a challenge this server issued for this, or was used already.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
A recorded response
Recorded on 2026-10-03. The response to POST /api/introductions.
{
"id": "08804f3c-ec62-450d-81b2-3801ea63419a",
"name": "Alex Example",
"email": "alex@example.com",
"company": "Example GmbH",
"role": "Engineering manager",
"message": "Hello! We are hiring a Java tech lead in Berlin, remote first. Would you like to talk next week?",
"token": "cahlfxIXq4_6oQB3Y7VPmndLRC6logBg3rXpupffM7w",
"confirmBy": "2026-10-03T18:35:01.707971423Z"
}A proof-of-work challenge
GET/api/introductions/challenge
A challenge by version 1 of ALTCHA's protocol, to solve before sending a draft: find the number from 0 to maxnumber whose SHA-256, after the salt, is the challenge. Good for ten minutes and for one draft.
- Answers with
- Challenge
- Limit per address
- 20 requests a minute, policy
introduction-challenges - Operation id
getIntroductionChallenge
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
A recorded response
Recorded on 2026-10-03. The response to GET /api/introductions/challenge.
{
"algorithm": "SHA-256",
"challenge": "7e2c8fc8b6d775d8e0b87adcdd3fccf3762b38d243ea9baccb36b4e55711ba5e",
"maxnumber": 100000,
"salt": "d935dc0d911fea7a18d0f41d?expires=1791061866&purpose=introduction&",
"signature": "126bae74a27bdf4cf812b4a26b237365098e79ed4bc23893f249736bc3d5c6a5"
}Confirm an introduction
POST/api/introductions/{id}/confirmation
Sends the draft on, with the token it came back with. Confirming twice is confirming once.
- Answers with
- no content, 204
- Limit per address
- 10 requests an hour, policy
introductions - Operation id
confirmIntroduction
Parameters
idpath, required- string
- The draft's id
Body
application/jsonrequired- Confirmation
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.UNREADABLE_BODYThe body is not the JSON the operation takes.TOKEN_INVALIDtokenbreaks a constraint its schema gives.
- 404Not Found
INTRODUCTION_NOT_FOUNDNo draft with that id and token is waiting.
- 409Conflict
INTRODUCTION_EXPIREDThe draft was not confirmed in time.
- 413Content Too Large
CONTENT_TOO_LARGEThe body is larger than any operation takes: the API reads 2 MB of JSON at most.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
Count a page view
POST/api/visits
The beacon the site's pages send as they are shown: the path, the tag of a tagged link, the host that referred the visitor and the size of screen, with the day's pseudonym of the visitor, an HMAC of address and user agent under a salt that lasts a day. Neither is stored. A request with Sec-GPC: 1 or DNT: 1, one a browser says another site's page sent (Sec-Fetch-Site), or one from a user agent that says it is a program, is answered the same and leaves nothing.
- Answers with
- no content, 204
- Limit per address
- 60 requests a minute, policy
visits - Operation id
recordVisit
Parameters
pathquery, required- stringmatches
^/[A-Za-z0-9/._~-]{0,199}$ - The page's path, without query or fragment
tagquery- stringmatches
^[a-z0-9][a-z0-9-]{0,39}$ - The tag of the link the visitor came by: acme, from ?r=acme
referrerquery- stringmatches
^[a-z0-9.-]{1,253}$ - The host of the page that linked here, never its path
viewportquery, requiredNARROW,MEDIUMorWIDE- The size of screen: narrower than 640 CSS pixels, narrower than 1,024, or wider
Errors
- 400Bad Request
UNSUPPORTED_API_VERSIONAPI-Versionnames a version the API does not have.MISSING_PARAMETERA required parameter is missing.INVALID_PARAMETERA parameter does not parse: not a number, or not one of its values.PATH_INVALIDpathbreaks a constraint its schema gives.TAG_INVALIDtagbreaks a constraint its schema gives.REFERRER_INVALIDreferrerbreaks a constraint its schema gives.
- 429Too Many Requests
RATE_LIMITEDMore requests from this address than the operation's limit allows.
- 500Internal Server Error
INTERNAL_ERRORSomething failed on the server's side.
- 503Service Unavailable
DATABASE_NOT_CONFIGUREDThe server runs without a database.DATABASE_NOT_MIGRATEDThe database lacks the experiment's tables: its migrations have not run.DATABASE_UNAVAILABLEThe database cannot be reached, or cannot give connections in time.
Schemas
Every field is always present; the ones that can be null say so.
AlgorithmResult
algorithmNAIVE_RECURSION,MEMOIZED_RECURSION,ITERATIVE,MATRIX_POWERorFAST_DOUBLINGlabel- string
complexity- string
statusOK,SKIPPED,STACK_OVERFLOWorTIMEOUTnanos- integer or null
runs- integer
operations- integer or null
maxDepth- integer or null
note- string or null
AssistantController.Typed
question- string
Challenge
algorithm- string
challenge- string
maxnumber- integer
salt- string
signature- string
Confirmation
token- string
DatabaseInfo
version- string
migrations- array of DatabaseInfo.Migration
DatabaseInfo.Migration
version- string
description- string
installedOn- date-time
success- boolean
Draft
name- string
email- string
company- string or null
role- string or null
message- string
conversation- string or null
website- string or null
altcha- string
FibonacciReport
n- integer
digits- integer
leadingDigits- string
trailingDigits- string
value- string or null
results- array of AlgorithmResult
environment- FibonacciReport.Environment
FibonacciReport.Environment
javaVersion- string
availableProcessors- integer
FitChecks.ExampleSummary
name- string
company- string
role- string
about- string
sourceLIVE,RECORDEDorSCRIPTED
FitPage.Cited
title- string
kind- string
url- string
FitPage.Drafting
model- string
sourceLIVE,RECORDEDorSCRIPTEDcalls- integer
inputTokens- integer or null
outputTokens- integer or null
costUsd- number or null
latencyMillis- integer
FitPage.Line
text- string
must- boolean
ratingDIRECT,ADJACENTorNONEclaim- string
missing- string
evidence- array of FitPage.Cited
withheld- boolean
FitResult
requirements- array of FitPage.Line
withheld- integer
drafting- FitPage.Drafting
GuideEventController.Event
event- string
tour- string
Invariant.Verdict
name- string
holds- boolean
detail- string
JitReport
completed- boolean
callsPerBatch- integer
batches- array of JitReport.Batch
events- array of JitReport.Event
summary- JitReport.Summary
JitReport.Batch
index- integer
shapeMONOMORPHIC,BIMORPHICorMEGAMORPHICnanos- integer
JitReport.Event
batch- integer
kindCOMPILEDorDEOPTIMIZEDmethod- string
detail- string
JitReport.Summary
firstNanos- integer
monomorphicNanos- integer
bimorphicNanos- integer
megamorphicNanos- integer
JvmFacts
collector- string
aotCache- string or null
aotCacheInUse- boolean
compactObjectHeaders- boolean or null
flags- array of string
memoryLimitBytes- integer
LedgerReport
strategyREAD_MODIFY_WRITE,GUARDED_UPDATE,LOCK_UNORDERED,LOCK_ORDERED,OPTIMISTICorSERIALIZABLEhotSpotPercent- integer
transfers- integer
workers- integer
committed- integer
insufficientFunds- integer
gaveUp- integer
failed- integer
notStarted- integer
deadlocks- integer
serializationFailures- integer
conflicts- integer
elapsedMs- integer
throughput- number
latencyP50Ms- integer or null
latencyP99Ms- integer or null
invariants- array of Invariant.Verdict
reconciliation- Reconciliation
traceId- string or null
OutboxReport
designCOMMIT_THEN_PUBLISH,PUBLISH_THEN_COMMITorOUTBOXcrashPercent- integer
dedup- boolean
orders- integer
answered- integer
committed- integer
published- integer
duplicatePublishes- integer
lost- integer
phantoms- integer
deliveries- integer
effects- integer
duplicateEffects- integer
missingEffects- integer
effectsWithoutOrder- integer
crashes- map of integer
restarts- integer
elapsedMs- integer
verdicts- array of OutboxReport.Verdict
OutboxReport.Verdict
name- string
holds- boolean
detail- string
PlanSummary
accessEVERY_ROWorINDEXindex- string or null
workers- integer
rowsRead- integer
blocksHit- integer
blocksRead- integer
planningMs- number
executionMs- number
steps- array of PlanSummary.Step
PlanSummary.Step
depth- integer
node- string
on- string or null
rows- integer
loops- integer
Preview
id- string
name- string
email- string
company- string or null
role- string or null
message- string
conversation- string or null
token- string
confirmBy- date-time
ProfileReport
scenarioHOT_LOCK,ALLOCATION_CHURNorQUADRATIC_DEDUPEvariantPROBLEMorFIXcompleted- boolean
wallMs- integer
threads- integer
checksum- string
samples- integer
hottest- array of ProfileReport.HotFrame
locks- ProfileReport.Locks
allocations- ProfileReport.Allocations
ProfileReport.AllocatedClass
type- string
bytes- integer
share- number
ProfileReport.Allocations
sampledBytes- integer
byClass- array of ProfileReport.AllocatedClass
ProfileReport.Frame
name- string
total- integer
self- integer
children- array of ProfileReport.Frame
ProfileReport.Gc
collections- integer
pauseTotalMs- integer
longestPauseMs- integer
ProfileReport.HotFrame
frame- string
self- integer
share- number
ProfileReport.Locks
waits- integer
totalMs- integer
monitor- string or null
PublicAssistant.ExampleSummary
name- string
question- string
about- string
sourceLIVE,RECORDEDorSCRIPTEDor nullkindPREPAREDorDEMOoffers- array of string
PublicAssistant.Matched
example- string or null
refusalPAY,PRIVATE_LIFE,NOT_IN_RECORDorUNGROUNDEDor nullwords- string or null
PublicAssistant.Status
live- boolean
offOFF,NO_MODEL,NO_PRICE,NO_DATABASEorBUDGET_SPENTor nulloffWords- string or null
questionCharacters- integer
questions- integer
sections- integer
examples- array of PublicAssistant.ExampleSummary
PublicFitCheckController.Posting
posting- string
altcha- string
PublicFitChecks.Status
live- boolean
offOFF,NO_MODEL,NO_PRICE,NO_DATABASEorBUDGET_SPENTor nulloffWords- string or null
postingCharacters- integer
examples- array of FitChecks.ExampleSummary
Reconciliation
accountsDrifted- integer
moneyCreated- integer
moneyDestroyed- integer
worst- array of Reconciliation.Drift
Reconciliation.Drift
account- integer
cached- integer
fromEntries- integer
RiskEngine.Asked
rule- string
decided- boolean
words- string
RunTrace
traceId- string
durationMs- number
spans- array of RunTrace.Span
dropped- integer
RunTrace.Span
id- string
parentId- string or null
name- string
startMs- number
durationMs- number
attributes- map of string
error- boolean
RuntimeInfo
javaVersion- string
javaVendor- string
vm- string
springBootVersion- string
availableProcessors- integer
maxHeapBytes- integer
garbageCollectors- array of string
startedAt- date-time
uptimeMs- integer
revision- string or null
jvm- JvmFacts
SearchReport
query- string
catalogue- SearchReport.Catalogue
methods- array of SearchReport.Method
SearchReport.Catalogue
products- integer
bytes- integer
SearchReport.Method
methodSCAN,TRIGRAM,TYPOorFULL_TEXToutcomeCOMPLETEDorTIMED_OUTtotal- integer
top- array of SearchReport.Product
plan- PlanSummary or null
SearchReport.Product
id- integer
title- string
category- string
priceCents- integer
score- number or null
TelemetrySample
t- integer
uptimeMs- integer
nonHeapUsed- integer
gc- array of TelemetrySample.Gc
threads- TelemetrySample.Threads
classesLoaded- integer
TelemetrySample.Cpu
process- number
system- number
TelemetrySample.Gc
name- string
count- integer
timeMs- integer
TelemetrySample.Heap
used- integer
committed- integer
max- integer
TelemetrySample.Threads
live- integer
daemon- integer
peak- integer
ThreadLocalReport
tasks- integer
poolSize- integer
carrierThreads- integer
cells- array of ThreadLocalReport.Cell
ThreadLocalReport.Cell
sourceTHREAD_LOCAL,PER_CALLorSHAREDexecutorPLATFORMorVIRTUALformattersCreated- integer
allocatedBytesPerTask- integer or null
wallMicros- integer
ThreeDsLabController.Answer
code- string
ThreeDsRun
acsTransID- string
phaseINVALID,FRICTIONLESS,CHALLENGED,AUTHENTICATED,FAILED,NOT_AUTHENTICATEDorREJECTEDtransStatus- string or null
steps- array of ThreeDsRun.Step
rules- array of RiskEngine.Asked
challenge- ThreeDsRun.Challenge or null
valueCheck- ThreeDsRun.ValueCheck or null
budget- array of ThreeDsRun.Hop
ThreeDsRun.Challenge
sentTo- string
code- string
triesLeft- integer
ThreeDsRun.Hop
name- string
millis- number
measured- boolean
ThreeDsRun.Step
from- string
to- string
via- string or null
message- string
fields- map of string
note- string or null
ThreeDsRun.ValueCheck
amount- string
checks- boolean
otherAmount- string
checksForOther- boolean