# LocalPrice API — AI integration context > LocalPrice creates deterministic INR quotes in two modes: direct FX conversion and India-specific localized recommendations. It stores secure quotes and lets a trusted backend verify the stored checkout amount. LocalPrice does not process payments and does not use AI for production pricing requests. Canonical schema: /docs/openapi.yaml Human documentation: /docs/ ## Non-negotiable security contract - API keys are secret and server-side only. Never put `lp_test_...` or `lp_live_...` keys in browser or mobile code. - The browser may receive and return a public `quoteId`; it must never be trusted to provide the checkout amount. - Immediately before creating payment checkout, the client backend must call quote verification. - Use `verified.checkout.amount` and `verified.checkout.currency` exactly. Do not recalculate, convert, or round them. - Never place real credentials, customer data, or payment secrets in AI prompts or generated examples. ## Authentication and isolation Pricing endpoints use `Authorization: Bearer `. TEST keys start with `lp_test_`; LIVE keys start with `lp_live_`. Projects, quotes, usage, and idempotency records are isolated by project and TEST/LIVE mode. ## Core server-side workflow 1. POST `/v1/prices/quote` with a unique `Idempotency-Key`. 2. Display the response's localized INR price and retain its `id`. 3. Send only the quote ID from the browser to the client's checkout backend. 4. POST `/v1/prices/quotes/{quoteId}/verify` from the backend. 5. Create payment checkout using the returned `checkout.amount` and `checkout.currency` exactly. ## Endpoints - GET `/health` — public liveness check. - GET `/ready` — public PostgreSQL and Redis readiness check. - POST `/v1/prices/quote` — authenticated quote creation; idempotency recommended. - GET `/v1/prices/quotes/{quoteId}` — authenticated quote retrieval. - POST `/v1/prices/quotes/{quoteId}/verify` — authenticated checkout verification. ## Create quote request ```json { "amount": 49, "currency": "USD", "targetMarket": "IN", "productType": "saas", "pricingMode": "localized", "sellerConstraints": { "maximumRegionalDiscountPercent": 70, "minimumRevenueRetentionPercent": 30, "minimumLocalizedPriceINR": 1299, "maximumLocalizedPriceINR": 2999 } } ``` Required: positive numeric `amount`; source `currency`; targetMarket `IN`. `pricingMode` is `localized` (default) or `fx`. Localized mode requires a supported `productType` unless project defaults provide it, and applies affordability, category, seller constraints, psychological rounding, and a range. FX mode needs no `productType`; it performs `roundHalfUp(amount × currentRate, 2)` only. It rejects `sellerConstraints` with `CONSTRAINT_NOT_SUPPORTED_FOR_FX_MODE`. Source currencies: USD, EUR, JPY, KRW, AED. Localized currency: INR. Product types: saas, ai_tool, developer_tool, online_course, creator_tool, gaming. Percent values use 0–100, not 0–1. Gross-margin constraints `sellerCostAmount`, `sellerCostCurrency`, and `minimumGrossMarginPercent` must be supplied together. Constraint precedence per field: request value > project default > global LocalPrice default. Impossible constraint combinations return `422 CONSTRAINT_CONFLICT`; constraints are not silently ignored. ## Reliability contract - Send one unique `Idempotency-Key` per logical quote creation. - Same key + normalized payload replays the original response and sets `Idempotency-Replayed: true`. - Same key + different payload returns `409 IDEMPOTENCY_KEY_CONFLICT`. - Completed idempotency responses commit in PostgreSQL with the quote and quota and do not expire automatically. Redis is an optional response cache only; its default TTL is 24 hours. Redis cache failure cannot invalidate a committed quote. - Inspect `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset`. - Respect `Retry-After` on HTTP 429. - Log `X-Request-Id` from every response. A caller-supplied request ID can contain letters, digits, `.`, `_`, `-` and be at most 64 characters. - Retry only network failures, timeouts, 429, and temporary 5xx responses with bounded exponential backoff and jitter. - On a quote-creation retry, reuse the original idempotency key and payload. - Never retry authentication, validation, expiry, or idempotency-conflict errors unchanged. ## Stable error envelope ```json { "requestId": "req_...", "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "details": {} } } ``` Branch on HTTP status and `error.code`, never on `error.message`. 400 VALIDATION_ERROR: fix request. 400 CONSTRAINT_NOT_SUPPORTED_FOR_FX_MODE: remove localized seller constraints or use localized mode. 401 API_KEY_MISSING, API_KEY_INVALID, API_KEY_REVOKED: fix credentials. 403 EARLY_ACCESS_REQUIRED: operator approval is required. 429 QUOTA_EXCEEDED: monthly quota exhausted; use reset date, not immediate retry. 404 RESOURCE_NOT_FOUND: check quote ID, project, and TEST/LIVE mode. 409 IDEMPOTENCY_KEY_CONFLICT or QUOTE_INVALIDATED: use original payload/new key, or create new quote. 410 QUOTE_EXPIRED: create a new quote. 413 REQUEST_TOO_LARGE: reduce request body. 422 CONSTRAINT_CONFLICT: fix seller constraints. 429 RATE_LIMIT_EXCEEDED: wait for Retry-After. 502 FX_PROVIDER_UNAVAILABLE: retry later with same idempotency key. 503 REDIS_UNAVAILABLE, IDEMPOTENCY_RECOVERY_REQUIRED, DATABASE_UNAVAILABLE: retry later where safe. ## Node.js SDK Package: `@localprice/node` ```ts import { LocalPrice, generateIdempotencyKey } from '@localprice/node'; const localprice = new LocalPrice({ apiKey: process.env.LOCALPRICE_API_KEY! }); const quote = await localprice.quotes.create({ amount: 49, currency: 'USD', targetMarket: 'IN', productType: 'saas', pricingMode: 'localized', }, { idempotencyKey: generateIdempotencyKey('pricing-page') }); const verified = await localprice.quotes.verify(quote.id); // Pass verified.checkout.amount and verified.checkout.currency to payment provider. ``` ## Usage semantics Successful creations and verifications atomically consume organization and project quotas (default 10,000/month each), shared by TEST/LIVE. Quotas reset each UTC calendar month. Replay, retrieval, failures, health, readiness, docs, and dashboard traffic do not consume quota. New organizations are PENDING; an operator must approve access. No subscription is required. ## Implementation acceptance criteria - No API key appears in a client bundle. - Quote creation includes a per-operation idempotency key. - Client-to-server checkout input contains quote ID, not authoritative amount/currency. - Backend verification occurs before payment checkout creation. - Payment provider receives the exact verified checkout values. - Expired/invalid quotes result in a fresh quote flow. - Stable error codes, Retry-After, rate-limit headers, and X-Request-Id are handled/logged.