LLocalPrice DOCS
LOCALPRICE API · v0.7

Ship India-specific pricing
without trusting the browser.

LocalPrice turns a global product price into a deterministic INR recommendation, stores the result as a secure quote, and lets your backend verify the exact amount before creating checkout.

01Your backend$49 · USD · SaaS
→
02LocalPriceRules + seller limits
→
03Verified checkout₹1,499 · INR
Server-side only

Keep lp_test_… and lp_live_… keys on your server. Send only the public quote ID through browser or mobile clients.

PRICING THAT RESPECTS EVERY MARKETprice("$49", "USD").to("INR") → "₹1,499"
verifyBeforeCheckout();

Create your first trusted INR quote

Early access is currently available to selected early users while we are validating the pricing engine.

Request Early Access → organization starts PENDING → operator approves → create a project → generate a project-scoped TEST key → integrate the REST API or Node SDK. Random signups do not receive active API access immediately.

  1. 1

    Install and configure

    Install with npm install @localprice/node. Store the key in your server environment—never in frontend JavaScript.

    .env
    LOCALPRICE_API_KEY="lp_test_your_key_here"
    LOCALPRICE_BASE_URL="https://www.localpriceapi.online"
  2. 2

    Create a quote

    Use a unique idempotency key for each logical pricing operation.

    POST /v1/prices/quote
    curl -X POST "$LOCALPRICE_BASE_URL/v1/prices/quote" \
      -H "Authorization: Bearer $LOCALPRICE_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: product-pro-annual-v1" \
      -d '{
        "amount": 40,
        "currency": "USD",
        "targetMarket": "IN",
        "productType": "saas",
        "pricingMode": "localized"
      }'
    quote.ts
    import { LocalPrice } from '@localprice/node';
    
    const localprice = new LocalPrice({
      apiKey: process.env.LOCALPRICE_API_KEY!,
    });
    
    const quote = await localprice.quotes.create({
      amount: 40,
      currency: 'USD',
      targetMarket: 'IN',
      productType: 'saas',
      pricingMode: 'localized',
    }, { idempotencyKey: 'product-pro-annual-v1' });
  3. 3

    Use the response

    Display localizedAmount to the customer and save quoteId for checkout verification. Money is returned as decimal strings to prevent floating-point loss.

    201 Created
    {
      "data": {
        "quoteId": "quote_kN0cRjTQY0wJ8A6wE5b5FDzQ",
        "status": "ACTIVE",
        "mode": "TEST",
        "pricingMode": "localized",
        "sourceAmount": "49.0000",
        "sourceCurrency": "USD",
        "localizedAmount": "1499.00",
        "localizedCurrency": "INR",
        "targetMarket": "IN",
        "productType": "saas",
        "pricingModelVersion": "v1",
        "expiresAt": "2026-09-01T12:00:00.000Z"
      }
    }

Authentication and environments

Send the API key as a Bearer token on every pricing endpoint.

HTTP
Authorization: Bearer lp_test_your_key_here
TEST

lp_test_…

Development quotes with project-scoped TEST isolation. Approved access is required.

LIVE

lp_live_…

Production quotes, separately keyed and isolated from TEST resources. Approved access is required.

Never expose secret keys

Do not embed a LocalPrice API key in a browser, mobile app, public repository, log line, URL, or analytics event. Route calls through your backend.

1. Create a quote

POST/v1/prices/quoteAuthenticated

Choose localized for an India-optimized recommendation or fx for direct market-rate conversion. Omitting the mode preserves the localized default. Both create the same secure, project-scoped quote.

FX request
{
  "amount": 40,
  "currency": "USD",
  "targetMarket": "IN",
  "pricingMode": "fx"
}
Localized request
{
  "amount": 40,
  "currency": "USD",
  "targetMarket": "IN",
  "pricingMode": "localized",
  "productType": "saas"
}

Request body

FieldTypeDescription
amountnumber · required

Positive source price. Use a JSON number, not a formatted currency string.

currencyenum · required

USD, EUR, JPY, KRW, or AED.

targetMarketenum · required

Must be IN in V1.

pricingModeenum · optional

localized (default) or fx.

productTypeenum · conditional

Required for localized unless the project supplies a default; optional for FX.

sellerConstraintsobject · localized only

FX requests containing constraints return CONSTRAINT_NOT_SUPPORTED_FOR_FX_MODE.

Headers

Authorizationrequired

Bearer lp_test_… or Bearer lp_live_…

Idempotency-Keyrecommended

Unique per logical quote creation; makes retries safe.

X-Request-Idoptional

Your trace ID: letters, digits, ., _, or -; maximum 64 characters.

2. Display the localized price

Return only display-safe quote data to the frontend. Keep the source input and LocalPrice key server-side.

Browser₹1,499Displays quote
Sends quoteId
HTTPS
Your backendquote_01J…Owns API key
Creates checkout
HTTPS
LocalPriceINR 1499Stores quote
Verifies amount
Treat the browser as untrusted

The displayed amount is presentation data. Never accept an INR amount submitted by the client as the checkout authority.

3. Verify before charging

POST/v1/prices/quotes/:quoteId/verifyAuthenticated

From your backend, verify the quote immediately before creating a payment-provider session. Use the returned checkout.amount and checkout.currency exactly.

checkout.ts
const verified = await localprice.quotes.verify(quoteId);

const checkoutSession = await payments.checkout.create({
  currency: verified.checkout.currency, // "INR"
  amount: verified.checkout.amount,     // 1499
  metadata: { localpriceQuoteId: verified.quoteId },
});

LocalPrice does not process the customer's payment and does not integrate into or control the payment provider. The boundary is: source price → LocalPrice quote → verified INR amount → your backend → your Stripe, Razorpay, PayPal, or other gateway.

✓ Do

Use the stored, verified checkout values returned by LocalPrice.

× Don't

Recalculate, round, convert, or trust an amount supplied by the browser.

Retrieve a quote

GET/v1/prices/quotes/:quoteIdAuthenticated

Retrieve the stored quote for display refreshes or server-side inspection. Quotes remain isolated by project and mode; a quote created with a TEST key is invisible to LIVE keys.

Node.js SDK
const stored = await localprice.quotes.retrieve(quote.id);

Supported values

Source currencies

USDEURJPYKRWAED→INR

Product types

saasai_tooldeveloper_toolonline_coursecreator_toolgaming

Enum values are case-sensitive. The only V1 target market is IN, and target currency is always INR. LocalPrice obtains FX data from Frankfurter; clients configure no FX key and do not call Frankfurter directly.

Pricing modes and seller constraints

localized applies FX, affordability, category, constraints, price-point rounding, and a recommendation range. fx applies only source amount × current FX rate and normal two-decimal INR rounding. Optional constraints keep a localized recommendation inside your commercial boundaries. Precedence is evaluated per field: request value > project default > LocalPrice default.

sellerConstraints
{
  "maximumRegionalDiscountPercent": 70,
  "minimumRevenueRetentionPercent": 30,
  "minimumLocalizedPriceINR": 1299,
  "maximumLocalizedPriceINR": 2999,
  "sellerCostAmount": 8,
  "sellerCostCurrency": "USD",
  "minimumGrossMarginPercent": 40
}
maximumRegionalDiscountPercent0–100

Caps discount relative to direct FX price.

minimumRevenueRetentionPercent0–100

Protects the minimum source-price revenue retained.

minimumLocalizedPriceINRpositive INR

Sets an explicit floor.

maximumLocalizedPriceINRpositive INR

Sets an explicit ceiling.

sellerCostAmount + 2 moreall required together

Cost amount, cost currency, and minimum gross margin form one constraint group.

Conflicts fail closed

An impossible combination returns 422 CONSTRAINT_CONFLICT. LocalPrice never silently ignores a seller limit.

Quote states

ACTIVE

Safe to display and eligible for verification.

expires or invalidates
EXPIRED

Create a fresh quote. Returns 410.

INVALIDATED

Create a fresh quote. Returns 409.

Always check the verification response at checkout time. Do not infer validity from a timestamp cached in the client.

Stable errors you can act on

Branch on error.code and HTTP status—not the human-readable message. Every error includes a request ID for support and tracing.

Error envelope
{
  "requestId": "req_01J…",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {}
  }
}
HTTPCodeWhat your integration should do
400VALIDATION_ERROR

Fix the payload; do not retry unchanged.

401API_KEY_MISSING / API_KEY_INVALID / API_KEY_REVOKED

Fix server credentials or replace the key.

403EARLY_ACCESS_REQUIRED / PROJECT_ARCHIVED

Wait for operator approval or restore permitted access.

404RESOURCE_NOT_FOUND

Check quote ID, project, and TEST/LIVE mode.

409IDEMPOTENCY_KEY_CONFLICT / QUOTE_INVALIDATED

Use the original payload/new key, or create a new quote.

410QUOTE_EXPIRED

Create and display a new quote.

422CONSTRAINT_CONFLICT

Correct incompatible seller constraints.

429QUOTA_EXCEEDED

Wait until the returned reset time or contact the operator.

429RATE_LIMIT_EXCEEDED

Wait for Retry-After; this is separate from quota.

502/503*_UNAVAILABLE

Retry later; preserve the same idempotency key.

Retry safely and trace everything

01

Idempotency

Reuse the same key and normalized payload after a timeout. A replay returns the original response with Idempotency-Replayed: true. Completed responses are stored durably in PostgreSQL with the quote and quota. Durable identities do not expire automatically.

02

Rate limits

Inspect RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. Respect Retry-After on 429.

03

Request IDs

Log X-Request-Id from every response and include it in support requests. You may supply your own safe trace identifier.

Database-backed retry safety

A Redis cache failure after commit does not invalidate your quote: retry with the same key to recover the original response. Redis remains required for the separate short-term rate limiter. Use a new key for a new quote after expiry.

Access and monthly quota

Early access is currently available to selected early users while we are validating the pricing engine.

New organizations start PENDING. Only a LocalPrice operator can approve project-scoped TEST and LIVE key creation and API access.

Organization and project limits default to 10,000 successful creations and verifications per UTC calendar month. TEST and LIVE share both limits. Retrievals, failed validation/authentication, dashboard traffic, and idempotent replays do not consume quota. A new UTC calendar-month counter is used automatically; unused quota does not roll over.

Check remaining quota and reset date in Usage & Analytics. Exhaustion returns HTTP 429 QUOTA_EXCEEDED. The separate default short-term limit is 100 requests per 60 seconds per project and mode; it returns RATE_LIMIT_EXCEEDED with Retry-After.

Production checklist

  • Use a LIVE key only in the production server environment.
  • Create one idempotency key per cart or pricing operation.
  • Send only quoteId through the browser.
  • Verify on your backend immediately before checkout creation.
  • Use verified.checkout.amount and .currency without recalculation.
  • Handle expired and invalidated quotes by creating a fresh quote.
  • Implement bounded retry with jitter for 429, network failures, and temporary 5xx errors.
  • Record X-Request-Id and configure quota alerts.
  • Use GET /health for liveness and GET /ready for dependency readiness.

Node.js SDK

npm install @localprice/node

The TypeScript-first client supports apiKey, baseUrl, timeout, requestId, and conservative maxRetries. Quote creation is retried only when you provide an idempotency key; retrieval and verification are safe to retry.

complete-flow.ts
import { LocalPrice, generateIdempotencyKey } from '@localprice/node';

const localprice = new LocalPrice({
  apiKey: process.env.LOCALPRICE_API_KEY!,
  timeout: 5_000,
  maxRetries: 2,
});

const quote = await localprice.quotes.create({
  amount: 40,
  currency: 'USD',
  targetMarket: 'IN',
  productType: 'saas',
  pricingMode: 'localized',
}, {
  idempotencyKey: generateIdempotencyKey('pricing-page'),
});

// Send quote.id and display-safe fields to the browser.
// Later, on your checkout route:
const stored = await localprice.quotes.retrieve(quote.id);
const verified = await localprice.quotes.verify(stored.id);
console.log(verified.checkout.amount, verified.checkout.currency);

The production API base URL is https://www.localpriceapi.online. SDK errors expose name, message, code, status, requestId, and optional retryAfter.

Give coding agents reliable context

LocalPrice publishes concise machine-readable context alongside the full API schema. Give both files to your coding assistant before asking it to build an integration.

Copy this implementation brief

Prompt for an AI coding assistant
Implement LocalPrice using the contract in /docs/llms.txt and
/docs/openapi.yaml. Keep the API key server-side. Create quotes with a
unique Idempotency-Key, return only display-safe quote data to the client,
and pass only quoteId back at checkout. Verify the quote on the server and
use verified.checkout.amount and verified.checkout.currency exactly when
creating payment checkout. Handle stable error.code values, respect
Retry-After, and log X-Request-Id. Do not recalculate or trust client prices.
AI safety boundary

Never paste a real LocalPrice key, customer data, or payment-provider secret into an AI prompt. Use environment-variable placeholders and TEST keys in generated examples.

Endpoint index

Need every schema and response?Open the canonical OpenAPI 3.1 specification.View OpenAPI →
⌕Esc

Type to search sections. Press Enter to open.