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
343 lines
9.6 KiB
YAML
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
|