Skip to content

HTTP and error behavior

This reference describes the application routes and signer routes in the checked-out source. Payment terms are deployment configuration; no live payment material is included. Example destinations and responses below are illustrative, not captured output.

Method and path Successful response Failure or alternative response
GET / 200, {"service":"url-shortener","status":"configured"}. Does not check database, Redis, signer, or facilitator.
GET /livez 200, {"status":"alive"}. Process-only; dependency failure does not change this handler.
GET /ready 200, {"status":"ready"}. 503 with database not ready; before first successful readiness also cache not ready.
POST /shorten 201 with a newly persisted code. Existing destination: 200; invalid body: 422; payment cases below; database/allocation availability: 503.
GET /{code} 302 with destination in Location. Unknown code: 404, short code not found; required database lookup unavailable: 503, database unavailable.
GET /metrics Prometheus exposition text. Excluded from OpenAPI and business HTTP instrumentation.

FastAPI also supplies framework-generated /docs, /redoc, and /openapi.json using its defaults. These are documentation helpers rather than additional release verification or application business operations.

{"url":"https://example.invalid/article"}

The destination is stripped of surrounding whitespace, must have an HTTP or HTTPS scheme and nonempty network location, and cannot contain a username or password. The validator does not implement a public-network allowlist, DNS resolution check, or destination reachability check. The application stores and redirects to the destination rather than fetching it.

A successful illustrative response has this shape:

{
"code": "aB3dE7gH",
"short_url": "http://localhost:8000/aB3dE7gH",
"original_url": "https://example.invalid/article"
}

short_url uses configured BASE_URL, with trailing slashes removed, rather than deriving its host from the incoming request. Codes use random ASCII letters and digits; default length is eight and allowed configured length is four through sixteen. The same validated destination string reuses its mapping with 200 and the same response fields.

There is no delete, update, refund, reconcile-payment, or operator fault-injection endpoint. Database insertion retries are bounded to three code attempts; exhaustion returns 503 with could not allocate a short code.

Payment is enabled only when FACILITATOR_URL, SERVICE_WALLET_ADDRESS, and SBC_CONTRACT_ADDRESS are all nonempty. Existing destinations return before payment parsing.

Condition Implemented response Header/body detail
Missing PAYMENT-SIGNATURE in payment mode. 402. PAYMENT-REQUIRED contains standard-base64 JSON x402 v2 terms; body is {}.
Invalid base64/JSON-object header, rejected verification, rejected settlement, or structurally invalid response object. 402. {"detail":"payment was not accepted"}. A fresh challenge header is not attached on this route branch.
Facilitator transport/HTTP failure, malformed JSON, non-object body, or uninitialized payment client. 503. {"detail":"payment facilitator unavailable"}.
Validated settlement identifier already associated with a different destination. 409. {"detail":"payment settlement has already been used"}.
Validated settlement and successful persistence. 201. Creation response; no transaction identifier or payment receipt header is returned.
Database fails after settlement but before insertion. 503. {"detail":"database unavailable"}; settlement may already have occurred.

The first row offers server-owned exact/permit2 requirements with atomic-unit amount, configured network/asset/recipient, and maxTimeoutSeconds: 300. Facilitator requests carry x402Version, paymentPayload, and separate paymentRequirements. The server does not replace its requirements with client accepted fields.

There is a documented contract discrepancy: the payment design describes malformed facilitator responses broadly as availability 5xx, while invalid object fields in the adapter become invalid_response and the route returns 402. Malformed JSON and non-object bodies instead become unavailable 503. This reference preserves the implemented distinction.

The signer is a separate service, normally listening on port 8080. It is an authorization/key boundary for the paid client; the application does not call it directly.

Method and path Response
GET /livez 200, {"status":"alive"}, regardless of bootstrap readiness.
GET /health 200 if at least one wallet bootstrapped; otherwise 503. Reports status/state, chain/network, wallet counts, configured contract/recipient fields, and configuration reason.
GET /wallets 200 if the service is ready; otherwise 503. Reports slot indices, boot-cached balance/allowance, addresses, and bootstrap flags. Do not publish raw responses as public evidence.
POST /sign-permit2 200 with exactly signature and permit2Authorization. Does not perform settlement or request-time RPC.
GET /metrics Prometheus exposition supplied by the instrumentation adapter. Wallet metrics contain addresses in source; publication must exclude that raw material.

The signing request contains required nonnegative wallet_index, optional positive integer amount, and optional positive integer deadline_seconds. Omitting amount/deadline uses signer defaults. Amount must equal the configured payment amount, and deadline must be within the configured maximum.

Pydantic validation failures such as a negative index or nonpositive amount return 422. A nonnegative index outside configured slots returns 400; a positive but different amount or excessive deadline returns 400. No available bootstrapped wallet, or an unbootstrapped selected slot, returns 503. Unexpected signing failures return 500 with Permit2 signing failed.

Health and wallet inspection use cached bootstrap state. They do not freshly query RPC, confirm current balance after payments, or guarantee that every configured slot is usable. Read signer failure for the consequences.

Creation tests, paid creation tests, redirect tests, health tests, replay tests, and signer API tests exercise these boundaries without live facilitator or cloud access. The paid request narrative explains their operational limits and the settlement/persistence gap.

Maintained by Satyam Agnihotri · DevOps & Cloud Engineer