Files
timmy-tower/lib/api-spec/openapi.yaml
alexpaynex dfc9ecdc7b Add honest accounting and automatic refund mechanism for completed jobs
Implement honest accounting post-job completion, calculating actual costs, adding margin, and enabling automatic refunds for overpayments via a new endpoint.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 418bf6f8-212b-4bb0-a7a5-8231a061da4e
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: c6386de2-d5f4-47cc-a557-73416f09e118
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9f85e954-647c-46a5-90a7-396e495a805a/418bf6f8-212b-4bb0-a7a5-8231a061da4e/sPDHkg8
Replit-Helium-Checkpoint-Created: true
2026-03-18 19:32:34 +00:00

343 lines
9.6 KiB
YAML

openapi: 3.1.0
info:
# Do not change the title, if the title changes, the import paths will be broken
title: Api
version: 0.1.0
description: API specification
servers:
- url: /api
description: Base API path
tags:
- name: health
description: Health operations
- name: jobs
description: Payment-gated agent job operations
- name: demo
description: Free demo endpoint (rate-limited)
paths:
/healthz:
get:
operationId: healthCheck
tags: [health]
summary: Health check
description: Returns server health status
responses:
"200":
description: Healthy
content:
application/json:
schema:
$ref: "#/components/schemas/HealthStatus"
/jobs:
post:
operationId: createJob
tags: [jobs]
summary: Create a new agent job
description: Accepts a request, creates a job row, and issues an eval fee Lightning invoice.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateJobRequest"
responses:
"201":
description: Job created successfully
content:
application/json:
schema:
$ref: "#/components/schemas/CreateJobResponse"
"400":
description: Invalid request body
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/jobs/{id}:
get:
operationId: getJob
tags: [jobs]
summary: Get job status
description: Returns current job state. Automatically advances the state machine when a pending invoice is found to be paid.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: Job status
content:
application/json:
schema:
$ref: "#/components/schemas/JobStatusResponse"
"404":
description: Job not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/jobs/{id}/refund:
post:
operationId: claimRefund
tags: [jobs]
summary: Claim a refund for overpayment
description: |
After a job completes, if the actual cost (tokens used + infra + margin) was
less than the work invoice amount, the difference is owed back to the user.
Submit a BOLT11 invoice for exactly `refundAmountSats` to receive the payment.
Idempotent: returns 409 if already paid or if no refund is owed.
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ClaimRefundRequest"
responses:
"200":
description: Refund sent
content:
application/json:
schema:
$ref: "#/components/schemas/ClaimRefundResponse"
"400":
description: Missing invoice, wrong amount, or invalid BOLT11
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Job not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"409":
description: Job not complete, refund already paid, or no refund owed
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Server error (e.g. Lightning payment failure)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/demo:
get:
operationId: runDemo
tags: [demo]
summary: Free demo (rate-limited)
description: Runs the agent without payment. Limited to 5 requests per IP per hour.
parameters:
- name: request
in: query
required: true
schema:
type: string
responses:
"200":
description: Demo result
content:
application/json:
schema:
$ref: "#/components/schemas/DemoResponse"
"400":
description: Missing or invalid request param
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"429":
description: Rate limit exceeded
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Server error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
components:
schemas:
HealthStatus:
type: object
properties:
status:
type: string
required:
- status
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
InvoiceInfo:
type: object
required:
- paymentRequest
- amountSats
properties:
paymentRequest:
type: string
amountSats:
type: integer
CreateJobRequest:
type: object
required:
- request
properties:
request:
type: string
minLength: 1
CreateJobResponse:
type: object
required:
- jobId
- evalInvoice
properties:
jobId:
type: string
evalInvoice:
$ref: "#/components/schemas/InvoiceInfo"
JobState:
type: string
enum:
- awaiting_eval_payment
- evaluating
- rejected
- awaiting_work_payment
- executing
- complete
- failed
PricingBreakdown:
type: object
description: Cost breakdown shown with the work invoice (estimations at invoice-creation time)
properties:
estimatedCostUsd:
type: number
description: Total estimated cost in USD (token cost + DO infra + margin)
marginPct:
type: number
description: Originator margin percentage applied
btcPriceUsd:
type: number
description: BTC/USD spot price used to convert the invoice to sats
CostLedger:
type: object
description: Honest post-work accounting stored after the job completes
properties:
actualInputTokens:
type: integer
actualOutputTokens:
type: integer
totalTokens:
type: integer
description: Sum of actualInputTokens + actualOutputTokens
actualCostUsd:
type: number
description: Raw Anthropic token cost (no infra, no margin)
actualChargeUsd:
type: number
description: What we honestly charged in USD (actual token cost + DO infra + margin)
estimatedCostUsd:
type: number
description: Original estimate used to create the work invoice
actualAmountSats:
type: integer
description: Honest sats charge (actual cost converted at the locked BTC price)
workAmountSats:
type: integer
description: Amount the user originally paid in sats
refundAmountSats:
type: integer
description: Sats owed back to the user (workAmountSats - actualAmountSats, >= 0)
refundState:
type: string
enum: [not_applicable, pending, paid]
description: Lifecycle of the refund for this job
marginPct:
type: number
btcPriceUsd:
type: number
description: BTC/USD price locked at invoice creation time
JobStatusResponse:
type: object
required:
- jobId
- state
properties:
jobId:
type: string
state:
$ref: "#/components/schemas/JobState"
evalInvoice:
$ref: "#/components/schemas/InvoiceInfo"
workInvoice:
$ref: "#/components/schemas/InvoiceInfo"
pricingBreakdown:
$ref: "#/components/schemas/PricingBreakdown"
reason:
type: string
result:
type: string
costLedger:
$ref: "#/components/schemas/CostLedger"
errorMessage:
type: string
ClaimRefundRequest:
type: object
required:
- invoice
properties:
invoice:
type: string
description: BOLT11 invoice for exactly refundAmountSats
ClaimRefundResponse:
type: object
required:
- ok
- refundAmountSats
- paymentHash
- message
properties:
ok:
type: boolean
refundAmountSats:
type: integer
paymentHash:
type: string
message:
type: string
DemoResponse:
type: object
required:
- result
properties:
result:
type: string