{"openapi":"3.1.0","info":{"title":"LienFi API","version":"1.0.0","description":"Tokenized US tax lien certificates and redeemable tax deeds on Base.\n\nThe lien read endpoints are public and need no credential — `GET /liens`,\n`GET /liens/{id}`, `GET /liens/facets`, `GET /liens/map` and\n`GET /market/activity` are all callable server-to-server.\n\nMoney conventions, because they are not guessable from the field names:\n\n- Every yield this API returns is **gross**. `calculated.apy` compounds;\n  it has no consumer in our own UI and you probably do not want it.\n- A buyer pays `listing_price`. At redemption the vault charges\n  `interest_fee_bps` of the **gain over that purchase price** — not of the\n  redemption value — floored at zero, so a lien that redeems below what\n  the buyer paid is charged nothing. At the default 1000 bps, a $1,000\n  lien redeeming at $1,100 is charged $10 and the buyer keeps $1,090.\n  Read the live rate rather than assuming 1000: `GET /liens` carries it at\n  `meta.fee_config`, `GET /liens/{id}` on the lien object as `fee_config`.\n  It is read from the chain when the lien redeems, so it can change.\n- `redemptive_value`, `accrued_interest` and `listing_price` on the raw row\n  are frozen snapshots and are stale on essentially every row. The\n  `calculated` block on each lien is recomputed live — read that instead.\n- Per-year rates shown on our own surfaces annualize **simply**\n  (`return * 365 / days`), because a certificate pays once at redemption\n  and there is nothing to reinvest.","contact":{"name":"LienFi","url":"https://lienfi.com"}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Privy access token for end-user routes, or a Supabase session JWT for admin routes. The lien read endpoints need none."}},"schemas":{}},"paths":{"/api/v1/health":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/api/v1/openapi.json":{"get":{"summary":"This API description, as OpenAPI 3.1","tags":["Docs"],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/verify-early-access":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/api/v1/lead":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/api/v1/send-otp":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/api/v1/link-wallet-address":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/api/v1/users/create":{"post":{"summary":"Create the caller’s user record (Bearer required)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/users/exists":{"get":{"summary":"Whether the caller’s user record exists (Bearer required)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/users/email-merge/start":{"post":{"summary":"Authorize absorbing an empty duplicate account (Bearer required)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/users/email-merge/confirm":{"post":{"summary":"Redeem a merge ticket from the absorbed account (Bearer required)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens":{"get":{"summary":"List liens with filters","tags":["Liens"],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false,"description":"Page number"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Items per page"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_price","required":false,"description":"Minimum listing price (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_price","required":false,"description":"Maximum listing price (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_interest","required":false,"description":"Minimum interest rate (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_interest","required":false,"description":"Maximum interest rate (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_face_value","required":false,"description":"Minimum face value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_face_value","required":false,"description":"Maximum face value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_assessed_value","required":false,"description":"Minimum assessed value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_assessed_value","required":false,"description":"Maximum assessed value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_ltv","required":false,"description":"Minimum loan-to-value (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_ltv","required":false,"description":"Maximum loan-to-value (%)"},{"schema":{"type":"string","enum":["listed","relisted","active","purchased","redeemed","foreclosure_eligible","foreclosure_initiated","foreclosed","expired"],"default":"listed"},"in":"query","name":"status","required":false,"description":"Filter by lien status. 'listed' also matches 'relisted'"},{"schema":{"type":"string"},"in":"query","name":"statuses","required":false,"description":"Statuses — overrides status. Comma-separated: pending_review, available, listed, relisted, active, purchased, redeemed, cancelled, foreclosure_eligible, foreclosure_initiated, foreclosed, expired, rejected"},{"schema":{"type":"string","maxLength":2},"in":"query","name":"state","required":false,"description":"State code (FL, TX, NJ)"},{"schema":{"type":"string"},"in":"query","name":"states","required":false,"description":"State codes"},{"schema":{"type":"string"},"in":"query","name":"county","required":false,"description":"Filter by county"},{"schema":{"type":"string"},"in":"query","name":"counties","required":false,"description":"Counties"},{"schema":{"type":"string","maxLength":100},"in":"query","name":"municipality","required":false,"description":"Filter by municipality"},{"schema":{"type":"string"},"in":"query","name":"municipalities","required":false,"description":"Municipalities"},{"schema":{"type":"string","enum":["fixed","par","discount","premium"]},"in":"query","name":"deal_type","required":false,"description":"Filter by deal type"},{"schema":{"type":"string"},"in":"query","name":"deal_types","required":false,"description":"Deal types. Comma-separated: fixed, par, discount, premium"},{"schema":{"type":"string","enum":["residential","industrial","vacant_land","vacant_commercial","commercial","agricultural","residential_homestead","other"]},"in":"query","name":"property_type","required":false,"description":"Filter by property type"},{"schema":{"type":"string"},"in":"query","name":"property_types","required":false,"description":"Property types. Comma-separated: residential, industrial, vacant_land, vacant_commercial, commercial, agricultural, residential_homestead, other"},{"schema":{"type":"string","enum":["lien","redeemable_deed"]},"in":"query","name":"lien_type","required":false,"description":"Filter by lien type"},{"schema":{"type":"string"},"in":"query","name":"lien_types","required":false,"description":"Lien types. Comma-separated: lien, redeemable_deed"},{"schema":{"type":"string"},"in":"query","name":"property_quality_grades","required":false,"description":"Property quality grades. Comma-separated: A, B, C, D"},{"schema":{"type":"string"},"in":"query","name":"acquisition_sources","required":false,"description":"Acquisition sources. Comma-separated: secondary, auction"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"maturity_after","required":false,"description":"Maturity (expiration_date) on or after this date"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"maturity_before","required":false,"description":"Maturity (expiration_date) on or before this date"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"search","required":false,"description":"Search by address, parcel ID, certificate number, or county"},{"schema":{"type":"string","enum":["newest_first","price_low_high","price_high_low","listing_price_low_high","listing_price_high_low","discount_low_high","discount_high_low","apy_low_high","apy_high_low","maturity_soonest","maturity_latest"],"default":"newest_first"},"in":"query","name":"sort_by","required":false,"description":"Sort order"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/map":{"get":{"summary":"Get all filter-matching liens as slim map locations (no pagination)","tags":["Liens"],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false,"description":"Page number"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Items per page"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_price","required":false,"description":"Minimum listing price (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_price","required":false,"description":"Maximum listing price (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_interest","required":false,"description":"Minimum interest rate (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_interest","required":false,"description":"Maximum interest rate (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_face_value","required":false,"description":"Minimum face value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_face_value","required":false,"description":"Maximum face value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_assessed_value","required":false,"description":"Minimum assessed value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_assessed_value","required":false,"description":"Maximum assessed value (USD)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"min_ltv","required":false,"description":"Minimum loan-to-value (%)"},{"schema":{"type":"number","minimum":0},"in":"query","name":"max_ltv","required":false,"description":"Maximum loan-to-value (%)"},{"schema":{"type":"string","enum":["listed","relisted","active","purchased","redeemed","foreclosure_eligible","foreclosure_initiated","foreclosed","expired"],"default":"listed"},"in":"query","name":"status","required":false,"description":"Filter by lien status. 'listed' also matches 'relisted'"},{"schema":{"type":"string"},"in":"query","name":"statuses","required":false,"description":"Statuses — overrides status. Comma-separated: pending_review, available, listed, relisted, active, purchased, redeemed, cancelled, foreclosure_eligible, foreclosure_initiated, foreclosed, expired, rejected"},{"schema":{"type":"string","maxLength":2},"in":"query","name":"state","required":false,"description":"State code (FL, TX, NJ)"},{"schema":{"type":"string"},"in":"query","name":"states","required":false,"description":"State codes"},{"schema":{"type":"string"},"in":"query","name":"county","required":false,"description":"Filter by county"},{"schema":{"type":"string"},"in":"query","name":"counties","required":false,"description":"Counties"},{"schema":{"type":"string","maxLength":100},"in":"query","name":"municipality","required":false,"description":"Filter by municipality"},{"schema":{"type":"string"},"in":"query","name":"municipalities","required":false,"description":"Municipalities"},{"schema":{"type":"string","enum":["fixed","par","discount","premium"]},"in":"query","name":"deal_type","required":false,"description":"Filter by deal type"},{"schema":{"type":"string"},"in":"query","name":"deal_types","required":false,"description":"Deal types. Comma-separated: fixed, par, discount, premium"},{"schema":{"type":"string","enum":["residential","industrial","vacant_land","vacant_commercial","commercial","agricultural","residential_homestead","other"]},"in":"query","name":"property_type","required":false,"description":"Filter by property type"},{"schema":{"type":"string"},"in":"query","name":"property_types","required":false,"description":"Property types. Comma-separated: residential, industrial, vacant_land, vacant_commercial, commercial, agricultural, residential_homestead, other"},{"schema":{"type":"string","enum":["lien","redeemable_deed"]},"in":"query","name":"lien_type","required":false,"description":"Filter by lien type"},{"schema":{"type":"string"},"in":"query","name":"lien_types","required":false,"description":"Lien types. Comma-separated: lien, redeemable_deed"},{"schema":{"type":"string"},"in":"query","name":"property_quality_grades","required":false,"description":"Property quality grades. Comma-separated: A, B, C, D"},{"schema":{"type":"string"},"in":"query","name":"acquisition_sources","required":false,"description":"Acquisition sources. Comma-separated: secondary, auction"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"maturity_after","required":false,"description":"Maturity (expiration_date) on or after this date"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"maturity_before","required":false,"description":"Maturity (expiration_date) on or before this date"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"search","required":false,"description":"Search by address, parcel ID, certificate number, or county"},{"schema":{"type":"string","enum":["newest_first","price_low_high","price_high_low","listing_price_low_high","listing_price_high_low","discount_low_high","discount_high_low","apy_low_high","apy_high_low","maturity_soonest","maturity_latest"],"default":"newest_first"},"in":"query","name":"sort_by","required":false,"description":"Sort order"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/facets":{"get":{"summary":"Distinct filter values and real numeric bounds for live inventory","tags":["Liens"],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}":{"get":{"summary":"Get lien by ID","tags":["Liens"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}/street-view":{"get":{"summary":"Get a cached Street View image URL for a lien property","tags":["Liens"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}/static-map":{"get":{"summary":"Get a cached aerial map image URL for a lien property","tags":["Liens"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}/buy-price":{"get":{"summary":"Get signed buy price for a lien","tags":["Liens"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"buyer","required":true,"description":"Buyer wallet address (0x...)"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}/cancel-listing":{"post":{"summary":"Cancel a lien listing","tags":["Liens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["activeWalletAddress"],"properties":{"activeWalletAddress":{"type":"string","description":"Active wallet address of the owner"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/liens/{id}/relist":{"post":{"summary":"Relist a lien with new pricing","tags":["Liens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["listingPrice","activeWalletAddress"],"properties":{"listingPrice":{"type":"number","minimum":0.01,"description":"New listing price (USD)"},"dealType":{"type":"string","enum":["fixed","par","discount","premium"],"description":"Pricing structure"},"percentage":{"type":"number","minimum":0,"maximum":100,"description":"Discount or premium percentage"},"activeWalletAddress":{"type":"string","description":"Active wallet address of the owner"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/portfolio":{"post":{"summary":"Get lien portfolio for the authenticated user","tags":["Portfolio"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["all_linked","active_only"],"default":"all_linked","description":"all_linked — all wallets linked to Privy; active_only — current active wallet only"},"activeWalletAddress":{"type":"string","description":"Filter to a specific wallet address"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/portfolio/history":{"post":{"summary":"Portfolio value over time for the authenticated user","tags":["Portfolio"],"description":"Monthly net position value from first acquisition through the last maturity, including positions since sold or redeemed over the window they were held. Derived from each lien’s redemptive-value curve on every request — there is no stored history, so a correction to a lien’s inputs restates its past.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/activity":{"post":{"summary":"Get transaction activity for the authenticated user","tags":["Activity"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["purchase","sell","redeem","all"],"default":"all","description":"Filter by transaction type"},"page":{"type":"integer","minimum":1,"default":1,"description":"Page number"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":10,"description":"Items per page"},"sort_by":{"type":"string","enum":["tx_date","amount"],"default":"tx_date","description":"Sort field"},"sort_order":{"type":"string","enum":["asc","desc"],"default":"desc","description":"Sort direction"},"search":{"type":"string","default":"","description":"Search term"},"activeWalletAddress":{"type":"string","description":"Filter by wallet address"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/market/activity":{"get":{"summary":"Recent public marketplace sale results","tags":["Activity"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":25,"default":10},"in":"query","name":"limit","required":false,"description":"Number of events to return"},{"schema":{"type":"boolean","default":false},"in":"query","name":"include_summary","required":false,"description":"Include lifetime sale totals in meta"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/legal":{"get":{"summary":"Get legal documents or check consent status","tags":["Legal"],"parameters":[{"schema":{"type":"string","enum":["check"]},"in":"query","name":"action","required":false,"description":"check — requires Bearer token; returns consent status for the user"},{"schema":{"type":"string"},"in":"query","name":"type","required":false,"description":"Document type (e.g. terms_of_service, privacy_policy)"},{"schema":{"type":"string","pattern":"^\\d+$"},"in":"query","name":"version","required":false,"description":"Specific document version number"},{"schema":{"type":"string"},"in":"query","name":"list","required":false,"description":"Set to true to list available document versions"},{"schema":{"type":"string"},"in":"query","name":"history","required":false,"description":"Set to true to return consent history"}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Log consent or update consent transaction status (Bearer required)","tags":["Legal"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["log_consent","update_consent_tx"],"description":"log_consent — record consent for the authenticated user; update_consent_tx — mark one of your own consent rows failed"},"type":{"type":"string","description":"Document type"},"version":{"type":"integer","description":"Document version consented to"},"wallet_address":{"type":"string","description":"Wallet the user consented from. Recorded on the row, not used to identify them — it is checked against the wallets the caller owns."},"browser_fingerprint":{"type":"string","description":"Browser fingerprint"},"metadata":{"type":"object","description":"Additional metadata"},"consent_id":{"type":"string","description":"Consent record ID (for update_consent_tx)"},"tx_status":{"type":"string","description":"Onchain transaction status"},"tx_error_reason":{"type":"string","description":"Reason for transaction failure"},"signature":{"type":"string","description":"EIP-712 consent signature. Evidence, never an identity input — a signature that fails to verify is recorded as invalid, not rejected."},"signature_spec_version":{"type":"string","description":"Frozen attestation spec the signature was produced under (e.g. consent-v1). The agreement text and domain are rebuilt from it server-side."},"signature_timestamp":{"type":"integer","description":"Unix seconds signed into the payload; must be within 10 minutes."},"signature_chain_id":{"type":"integer","description":"domain.chainId the signature was produced under (8453 or 84532)."}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/agents/register":{"post":{"summary":"Authorize an agent wallet to purchase on an operator behalf (no Bearer)","tags":["Agents"],"description":"Signature-authenticated: the operator signs an EIP-712 AgentAuthorization in the browser, and the agent signs a key proof bound to that authorization digest. No Bearer token is involved — the recovered signatures are the identity. Idempotent for the same operator (200); a different operator claiming the same wallet is a 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["operatorAuthorization","agentKeyProof"],"properties":{"operatorAuthorization":{"type":"object","required":["specVersion","signature","message"],"properties":{"specVersion":{"type":"string","description":"Frozen spec id from @lienfi/shared/agent-authorization"},"signature":{"type":"string","description":"EIP-712 signature over the rebuilt envelope"},"message":{"type":"object","required":["operatorWallet","agentWallet","documentType","version","issuedAt","expiresAt"],"properties":{"operatorWallet":{"type":"string","description":"Address that signed (0x...)"},"agentWallet":{"type":"string","description":"Address being authorized (0x...)"},"documentType":{"type":"string","description":"Must be 'agent-authorization'"},"version":{"type":"integer","description":"legal_documents.version shown"},"issuedAt":{"type":"integer","description":"Unix seconds"},"expiresAt":{"type":"integer","description":"Unix seconds, <= 90 days after issue"},"maxPerPurchaseUsdc":{"type":"string","description":"v2 only. USDC base units (6dp), decimal string."},"maxTotalUsdc":{"type":"string","description":"v2 only. USDC base units (6dp), decimal string."}}}}},"agentKeyProof":{"type":"object","required":["specVersion","signature","timestamp"],"properties":{"specVersion":{"type":"string"},"signature":{"type":"string"},"timestamp":{"type":"integer","description":"Unix seconds, fresh within 600s"}}},"label":{"type":"string","description":"Optional operator-facing name, <=120 chars"}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/api/v1/agents":{"get":{"summary":"The authenticated operator’s own agent bindings","tags":["Agents"],"description":"The one Bearer-authenticated route on this path. Returns the caller’s bindings with labels and expiries, including revoked ones — an operator most needs to see a revocation right after making it. Identity is the session, not a signature, because the caller is a browser rather than an agent.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/agents/{wallet}":{"get":{"summary":"Whether an agent wallet is currently authorized","tags":["Agents"],"description":"Public and deliberately thin: registration state only. No operator identity, no user id, no consent id — anyone may call this for any address, so it must not become a way to ask who owns a wallet. Scoped to this deployment chain, so a binding created against the other network reads as unregistered here.","parameters":[{"schema":{"type":"string"},"in":"path","name":"wallet","required":true,"description":"Agent wallet address (0x...)"}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/agents/revoke":{"post":{"summary":"Revoke an agent authorization (no Bearer)","tags":["Agents"],"description":"Operator-signed. Ends consent coverage, makes GET /agents/:wallet report unregistered, and makes the MCP refuse to buy. It does NOT stop the wallet transacting: the marketplace is permissionless and the wallet still holds its key, so the remediation for a leaked key is to move its funds. It also does NOT remove already-purchased liens from the operator portfolio — holdings and authorization are separate questions. Unlike the grant, issuedAt must be fresh within 600s: a revocation is a point-in-time act and replaying an old one must not undo a deliberate re-authorization.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["revocation"],"properties":{"revocation":{"type":"object","required":["specVersion","signature","message"],"properties":{"specVersion":{"type":"string","description":"Frozen spec id from @lienfi/shared/agent-authorization"},"signature":{"type":"string","description":"EIP-712 signature over the rebuilt envelope"},"message":{"type":"object","required":["operatorWallet","agentWallet","issuedAt"],"properties":{"operatorWallet":{"type":"string"},"agentWallet":{"type":"string"},"issuedAt":{"type":"integer","description":"Unix seconds, fresh within 600s"}}}}}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/api/v1/agents/purchase-consent":{"post":{"summary":"Record the per-purchase investment acknowledgment for an agent buy (no Bearer)","tags":["Agents"],"description":"Agent-signed. The equivalent of what PurchaseLienDialog writes on the human path, which the agent path would otherwise skip — leaving agent trades as the only ones with no per-trade record. Authority comes from an active binding for the signing wallet, not from the signature alone. action=log writes the row as tx_status pending with metadata.lienId, which is the join key the indexer promotes to confirmed; action=fail marks it failed when the transaction reverts before settlement.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agentPurchaseConsent"],"properties":{"agentPurchaseConsent":{"type":"object","required":["specVersion","signature","message"],"properties":{"specVersion":{"type":"string","description":"Frozen spec id from @lienfi/shared/agent-authorization"},"signature":{"type":"string","description":"EIP-712 signature over the rebuilt envelope"},"message":{"type":"object","required":["agentWallet","lienId","action","timestamp"],"properties":{"agentWallet":{"type":"string"},"lienId":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["log","fail"]},"timestamp":{"type":"integer","description":"Unix seconds, fresh within 600s"}}}}},"consentId":{"type":"string","format":"uuid","description":"Required when action=fail"},"txErrorReason":{"type":"string"}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/api/v1/paymaster":{"post":{"summary":"ERC-7677 paymaster proxy for the authenticated user","tags":["Paymaster"],"description":"Relays a JSON-RPC request to the configured bundler+paymaster after checking that the userOperation belongs to the caller, installs only our pinned account delegate, and calls only sponsored contracts and functions.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"id":{},"method":{"type":"string"},"params":{"type":"array"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/mcp":{"post":{"summary":"Model Context Protocol endpoint (stateless streamable HTTP)","tags":["MCP"],"description":"JSON-RPC 2.0 over HTTP, no credential required. READ-ONLY: the three tools are market_overview, search_liens and get_lien. This deployment exposes no purchase, quote or wallet-scoped tool, and nothing here signs or submits anything. Call `tools/list` for the live set.","responses":{"200":{"description":"Default Response"}}}},"/api/v1/newsletter/subscribe-me":{"post":{"summary":"Subscribe the signed-in user","tags":["Newsletter"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/unsubscribe":{"get":{"summary":"Unsubscribe with a token (RFC 8058 one-click target)","tags":["Newsletter"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"token","required":true}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Unsubscribe with a token (RFC 8058 one-click target)","tags":["Newsletter"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"token","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/public/liens/{id}":{"get":{"summary":"One lien as flat, uncredentialed JSON","tags":["Public"],"description":"A curated public projection of a single lien: the investment facts only.\n\nYields: `blendedApyGrossPercent` and `yieldToMaturityGrossPercent` are GROSS.\nA buyer pays `listingPrice` and, at redemption, the vault charges\n`feeConfig.interest_fee_bps` of the GAIN OVER THAT PRICE — floored at zero, so\na loss is never scaled. `netPerYearPercent` is that net gain restated per year,\nannualized SIMPLY (`r * 365/days`), and is the number a buyer keeps. It is null\nfor a lien with under 30 days remaining, no cost basis, or an unpriceable row —\nnever 0.\n\n`redemptionPremiumPercent` and `statutoryInterestRatePercent` are mutually\nexclusive: a Texas redeemable deed has no interest rate, only a statutory\n§ 34.21 premium, and every other state has the reverse.\n\nEvery figure is recomputed on read. This response carries no wallet addresses,\nno transaction history and no operator cost fields; `GET /api/v1/liens/:id` is\nthe complete record if you need more.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Lien ID"}],"responses":{"200":{"description":"Default Response"}}}}},"servers":[{"url":"https://api.lienfi.com"}],"tags":[{"name":"Liens","description":"Public lien inventory, filters and per-lien detail."},{"name":"Legal","description":"Public legal documents (terms, risk disclosure)."},{"name":"Portfolio","description":"Wallet-scoped holdings. Requires a user token."},{"name":"Activity","description":"Wallet-scoped transaction history. Requires a user token."},{"name":"Agents","description":"Agent registration and authorization, signature-authenticated."},{"name":"Newsletter","description":"Subscription opt-in and one-click unsubscribe."},{"name":"Paymaster","description":"Gas-sponsorship proxy used by our own frontend."},{"name":"Users","description":"Account creation and lookup. Requires a user token."},{"name":"MCP","description":"Model Context Protocol endpoint. JSON-RPC 2.0 over stateless HTTP, no credential. Three read tools: market_overview, search_liens, get_lien. Prefer search_liens over GET /liens when ranking — it sorts on net yield using the same arithmetic this site displays."},{"name":"Public","description":"Curated, uncredentialed JSON for non-browser consumers, outside the /api/v1 tree. Flat camelCase, no response envelope, and an explicit field allowlist — no wallet addresses, no transaction history, no operator cost fields. Yields are named for what they are: prefer netPerYearPercent over either …GrossPercent field, and note they are different quantities rather than the same one before and after a fee. The Liens tag above is the complete record if you need more than the listing terms."},{"name":"Docs","description":"This API description."}]}