feat(public): add GET /api/core/public/rate?currency=usd

Exposes the WOW→fiat spot rate the invoice path already uses
internally (Nonlogs WOW-BTC × Kraken BTC-USD, 60s cache). No auth.

Allows downstream services (Medusa storefront) to display a live
USD reference price for WOW-denominated products without hard-coding
a third-party rate provider on the storefront side.
This commit is contained in:
jwinterm
2026-05-26 15:04:46 -04:00
parent 083a51d3b7
commit 0aa19ca6bf
+33
View File
@@ -627,6 +627,39 @@ def get_public_system_status(db: Session = Depends(get_db)):
return _load_public_system_status(db) return _load_public_system_status(db)
@router.get("/api/core/public/rate")
def get_public_rate(currency: str = "usd"):
"""
Public WOW→fiat spot rate. Returns the same QuoteResult that the
invoice-creation paths use internally (60s in-process cache, sourced
from Nonlogs WOW-BTC × Kraken BTC-USD).
No auth — this is the same data the marketing storefront would
otherwise have to scrape from Nonlogs directly. Exposing it lets
downstream consumers (Medusa) get an authoritative-on-our-side
rate without hard-coding a third-party API.
"""
try:
quote = get_wow_rate(currency)
except ValueError as exc:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(exc),
) from exc
except (RequestException, RuntimeError) as exc:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Rate temporarily unavailable: {exc}",
) from exc
return {
"rate": str(quote.rate),
"currency": quote.currency,
"source": quote.source,
"quoted_at": quote.quoted_at.isoformat(),
"base": "WOW",
}
@router.post("/api/core/webhooks", response_model=WebhookResponse) @router.post("/api/core/webhooks", response_model=WebhookResponse)
def register_webhook( def register_webhook(
payload: WebhookCreate, payload: WebhookCreate,