API Reference
Base URL: https://notary-controller.fly.dev
Authentication
No API keys required. Authentication is handled via the x402 payment protocol. Each verification requires payment of 0.001 ETH on Base Sepolia.
TypeScript Interfaces
interface VerificationRequest {
taskType: 'code-execution';
code: string;
expectedHash: string;
inputData?: any;
timeoutSeconds?: number; // 5-60, default: 30
}
interface VerificationResponse {
jobId: string;
status: 'pending_payment' | 'running' | 'completed' | 'error';
result?: 'VALID' | 'INVALID' | 'ERROR';
executionTimeMs?: number;
registryTxHash?: string;
expectedHash?: string;
actualHash?: string;
errorMessage?: string;
refundEligible?: boolean;
}
interface PaymentRequirements {
scheme: 'exact';
network: 'base-sepolia';
amount: string; // wei
payTo: string;
expiry: number;
}
POST /verify
Submit a verification request. Returns 402 Payment Required if no valid payment provided.
Headers
| Header | Required | Description |
|---|---|---|
Content-Type |
Yes | Must be application/json |
X-402-Payment |
No* | Transaction hash of x402 payment (required on retry) |
*First call without payment returns 402 with payment requirements.
Request Body
{
"taskType": "code-execution",
"code": "console.log('hello world')",
"expectedHash": "a8f5f167f44f4964e6c998dee827110c...",
"timeoutSeconds": 30
}
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
taskType |
string | Yes | code-execution (MVP), api-replay, data-transformation |
code |
string | Conditional | Code to execute (required for code-execution) |
expectedHash |
string | Conditional | Expected SHA-256 output hash |
inputData |
any | No | Input data for the task |
timeoutSeconds |
number | No | Max execution time (5-60s, default: 30) |
Responses
402 Payment Required
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending_payment",
"paymentRequirements": {
"scheme": "exact",
"network": "base-sepolia",
"amount": "1000000000000000",
"asset": "0x0000000000000000000000000000000000000000",
"payTo": "0x...",
"expiry": 1740000000
},
"message": "Please submit payment and retry with X-402-Payment header"
}
202 Accepted
Payment verified, verification started:
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"message": "Verification started",
"checkStatusAt": "/verify/550e8400-e29b-41d4-a716-446655440000"
}
200 OK
Verification completed (synchronous response after payment):
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result": "VALID",
"executionTimeMs": 245,
"totalTimeMs": 3210,
"registryTxHash": "0x...",
"expectedHash": "a8f5f167f44f4964e6c998dee827110c...",
"actualHash": "a8f5f167f44f4964e6c998dee827110c...",
"refundEligible": false
}
GET /verify/:id
Retrieve the current status and results of a verification job.
Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string (UUID) | Job ID returned from POST /verify |
Response
Pending Payment 402
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending_payment",
"taskType": "code-execution",
"createdAt": "2026-02-04T14:30:00.000Z",
"updatedAt": "2026-02-04T14:30:00.000Z"
}
Running 202
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"taskType": "code-execution",
"payment": {
"txHash": "0x...",
"amount": "1000000000000000",
"verifiedAt": "2026-02-04T14:30:05.000Z"
}
}
Completed - Valid 200
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"taskType": "code-execution",
"result": "VALID",
"executionTimeMs": 245,
"registryTxHash": "0x...",
"payment": {
"txHash": "0x...",
"amount": "1000000000000000",
"verifiedAt": "2026-02-04T14:30:05.000Z"
}
}
Completed - Invalid 200
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"taskType": "code-execution",
"result": "INVALID",
"expectedHash": "a8f5f167f44f4964e6c998dee827110c...",
"actualHash": "b7e4e056e33e5934d5c8877ed72f0f0f...",
"executionTimeMs": 245,
"registryTxHash": "0x..."
}
Webhooks (Coming Soon)
Real-time notifications for verification completion without polling.
// Register webhook URL
POST /webhooks/register
{
"url": "https://your-api.com/webhooks/workproof",
"events": ["verification.completed", "verification.failed"],
"secret": "whsec_your_secret"
}
// Webhook payload
{
"event": "verification.completed",
"timestamp": "2026-02-04T14:30:10Z",
"data": {
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"result": "VALID",
"expectedHash": "...",
"actualHash": "..."
},
"signature": "sha256=..."
}
Verifying signatures:
const signature = req.headers['x-workproof-signature'];
const payload = JSON.stringify(req.body);
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== `sha256=${expected}`) {
throw new Error('Invalid signature');
}
GET /notary/stats
Returns service statistics and reputation metrics.
Response
{
"totalVerifications": 1523,
"successRate": 94.5,
"averageDurationMs": 320,
"uptimePercentage": 99.9,
"revenueETH": "1.523000",
"activeWorkers": 3,
"verifierAddress": "0x...",
"serviceVersion": "0.1.0",
"network": "base-sepolia"
}
Error Codes
| Status | Code | Description | Refund Eligible |
|---|---|---|---|
| 400 | Bad Request | Invalid request body or parameters | No |
| 402 | Payment Required | No payment header provided | N/A |
| 402 | Payment Failed | Invalid payment (wrong amount, recipient, or already used) | N/A |
| 404 | Not Found | Job ID does not exist | No |
| 413 | Payload Too Large | Code exceeds 100KB limit | No |
| 429 | Rate Limited | Too many requests (100/min per IP) | No |
| 503 | Service Unavailable | Circuit breaker open (too many active VMs) | No |
| 500 | VM Spawn Failed | Infrastructure failure to start worker | Yes |
| 500 | Registry Write Failed | Blockchain attestation failed | Yes |
Rate Limits
- 100 requests per minute per IP (unauthenticated)
- Max 10 concurrent verifications per agent
- Circuit breaker opens after 10 failures in 60 seconds
Refunds
Automatic refunds are issued for infrastructure failures:
Refund Eligible:
- VM spawn failure
- Network error during verification
- Registry write failure
- Timeout (>60s)
NOT Refunded:
- INVALID result (we did the work, result is valuable info)
- Invalid code (validation failed)
- Wrong expected hash (user error)
Last updated: February 5, 2026