FAIR PRICES
FOR THE
ENTIRE WORLD.

One API call. Country detection. PPP data. Suggested discount. Local currency. Done.

GET YOUR API KEY READ THE DOCS
INDIA 70% OFF — BRAZIL 50% OFF — NIGERIA 60% OFF — POLAND 40% OFF — JAPAN 10% OFF — SWITZERLAND 0% OFF — EGYPT 80% OFF — MEXICO 50% OFF —  INDIA 70% OFF — BRAZIL 50% OFF — NIGERIA 60% OFF — POLAND 40% OFF — JAPAN 10% OFF — SWITZERLAND 0% OFF — EGYPT 80% OFF — MEXICO 50% OFF — 

TRY IT.

// HIT CALCULATE.

HOW IT WORKS.

01

ADD THE SCRIPT

One script tag on your page. Mark prices with data-parity-price. Visitors instantly see prices in their local currency.

02

ADD THE API CALL

One API call in your checkout backend. Gets the adjusted price and passes it to your payment processor. Works with Stripe, Paddle, LemonSqueezy, anything.

03

CONVERT MORE

Customers see fair prices, get charged fair prices. VPN detection prevents discount abuse. International conversions go up.

TWO STEPS. BOTH REQUIRED.

ParityAPI works in two parts: a client-side script to display adjusted prices, and a server-side API call to charge the correct amount at checkout. You need both.

STEP 1: DISPLAY ADJUSTED PRICES (CLIENT-SIDE)

Add the script to your page. It detects the visitor's country and adjusts all marked prices to local currency. This is what the customer sees.

<!-- Add to your HTML -->
<script src="https://api.getparity.dev/parity.js"
        data-key="parity_live_YOUR_KEY"></script>

<!-- Mark your prices -->
<span data-parity-price="99">$99</span>
<span data-parity-price="29">$29</span>

STEP 2: CHARGE THE RIGHT PRICE (SERVER-SIDE)

When the customer checks out, call the API from your backend to get the adjusted price and pass it to your payment processor (Stripe, Paddle, LemonSqueezy, etc). The script only changes what's displayed — this step enforces the real price.

// Your checkout endpoint (Node.js example)
app.post('/checkout', async (req, res) => {
  // 1. Get PPP-adjusted price from ParityAPI
  const parity = await fetch(
    `https://api.getparity.dev/v1/pricing?base_price=${req.body.price}&token=${req.body.token}`,
    { headers: { 'X-API-Key': process.env.PARITY_KEY } }
  ).then(r => r.json());

  // 2. Create checkout with adjusted price
  const session = await stripe.checkout.sessions.create({
    line_items: [{
      price_data: {
        currency: parity.currency.code.toLowerCase(),
        unit_amount: Math.round(parity.pricing.localPrice * 100),
        product_data: { name: 'Your Product' },
      },
      quantity: 1,
    }],
    mode: 'payment',
  });

  res.json({ url: session.url });
});

The visitor token (from Step 1) is available via the parity:ready event or the /v1/detect endpoint. Pass it to your server to ensure the checkout price matches what was displayed.

API REFERENCE.

Base URL: https://api.getparity.dev/v1
All authenticated endpoints require the X-API-Key header. Hit GET /v1 for machine-readable docs.

GET /v1/pricing AUTH

Calculate PPP-adjusted pricing. Supports a single price or multiple prices in one call (ideal for shops with many products).

PARAMTYPEREQDESCRIPTION
base_pricenumber*Single product price in USD. Use this OR prices.
pricesstring*Comma-separated prices in USD (max 100). Use this OR base_price.
countrystringNOISO 3166 country code (auto-detected from IP if omitted)
tokenstringNOSigned visitor token from /v1/detect (enables server-side calls with accurate VPN detection)
vpn_overridestringNOSet to "true" to flag this request as VPN-detected. Use with your own VPN detection service (e.g. IPinfo).
presetstringNOPreset ID or name for custom discount rules. Uses active preset or defaults if omitted.
// Single price
curl "https://api.getparity.dev/v1/pricing?base_price=99&country=IN" \
     -H "X-API-Key: parity_live_YOUR_KEY"

// Multiple prices (one API call for your entire catalog)
curl "https://api.getparity.dev/v1/pricing?prices=9,29,49&country=IN" \
     -H "X-API-Key: parity_live_YOUR_KEY"
SINGLE PRICE RESPONSE
{
  "country": { "code": "IN", "name": "India", "incomeLevel": "Lower middle income" },
  "currency": { "code": "INR", "name": "Indian Rupee", "symbol": "₹" },
  "ppp": { "priceLevelRatio": 0.255, "dataYear": 2022, "source": "World Bank ICP" },
  "pricing": {
    "originalPrice": 99,
    "discountPercent": 70,
    "adjustedPrice": 29.70,
    "localPrice": 2468.06,
    "localCurrency": "INR"
  },
  "discount": { "percent": 70, "source": "default" },
  "exchange": { "rate": 83.1, "updatedAt": "2025-01-01T00:00:00.000Z" },
  "confidence": { "vpnDetected": false, "vpnConfidence": "none", "vpnSignals": [], "dataFresh": true }
}
SINGLE PRICE WITH CUSTOM PRESET
// GET /v1/pricing?base_price=99&country=IN&preset=aggressive
{
  ...
  "pricing": {
    "originalPrice": 99,
    "discountPercent": 65,
    "adjustedPrice": 34.65,
    "localPrice": 2879.42,
    "localCurrency": "INR"
  },
  "discount": { "percent": 65, "source": "custom", "preset": "aggressive" },
  ...
}
BULK PRICES RESPONSE
{
  "country": { "code": "IN", "name": "India", "incomeLevel": "Lower middle income" },
  "currency": { "code": "INR", "name": "Indian Rupee", "symbol": "₹" },
  "ppp": { "priceLevelRatio": 0.255, "dataYear": 2022, "source": "World Bank ICP" },
  "pricing": [
    { "originalPrice": 9, "discountPercent": 70, "adjustedPrice": 2.70, "localPrice": 224.42, "localCurrency": "INR" },
    { "originalPrice": 29, "discountPercent": 70, "adjustedPrice": 8.70, "localPrice": 723.14, "localCurrency": "INR" },
    { "originalPrice": 49, "discountPercent": 70, "adjustedPrice": 14.70, "localPrice": 1221.86, "localCurrency": "INR" }
  ],
  "discount": { "percent": 70, "source": "default" },
  "exchange": { "rate": 83.1, "updatedAt": "2025-01-01T00:00:00.000Z" },
  "confidence": { "vpnDetected": false, "vpnConfidence": "none", "vpnSignals": [], "dataFresh": true }
}
GET /v1/detect PUBLIC

Get a signed visitor token. Call this from the visitor's browser, then pass the token to /v1/pricing from your server. This gives you server-side API key security with accurate client-side VPN detection.

// Client-side (visitor's browser)
const res = await fetch("https://api.getparity.dev/v1/detect");
const { token } = await res.json();

// Server-side (your backend, API key stays secret)
const pricing = await fetch(
  `https://api.getparity.dev/v1/pricing?base_price=99&token=${token}`,
  { headers: { "X-API-Key": "parity_live_YOUR_KEY" } }
);
EXAMPLE RESPONSE
{
  "token": "eyJjb3VudHJ5IjoiSU4i...",
  "country": "IN",
  "expires_in": 300
}
GET /v1/countries PUBLIC

List all supported countries with currency metadata.

curl "https://api.getparity.dev/v1/countries"
POST /v1/signup PUBLIC

Create a free account and receive an API key.

BODYTYPEREQDESCRIPTION
emailstringYESYour email address
curl -X POST "https://api.getparity.dev/v1/signup" \
     -H "Content-Type: application/json" \
     -d '{"email": "you@example.com"}'
EXAMPLE RESPONSE
{
  "apiKey": "parity_live_abc123...",
  "plan": "free"
}
GET /v1/usage AUTH

Check your current month's request count and limits.

curl "https://api.getparity.dev/v1/usage" \
     -H "X-API-Key: parity_live_YOUR_KEY"
EXAMPLE RESPONSE
{
  "plan": "free",
  "used": 42,
  "limit": 1000,
  "period": "2025-01"
}
POST /v1/checkout AUTH

Create a Stripe checkout session to upgrade to a paid plan.

BODYTYPEREQDESCRIPTION
planstringYES"starter" or "pro"
curl -X POST "https://api.getparity.dev/v1/checkout" \
     -H "X-API-Key: parity_live_YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{"plan": "starter"}'
GET /v1/health PUBLIC

Health check. Returns API status and version.

curl "https://api.getparity.dev/v1/health"
POST /v1/presets AUTH

Create a named discount preset with per-country rules. Starter: 5 presets, Pro: 20 presets. Not available on Free plan.

BODYTYPEREQDESCRIPTION
namestringYESPreset name (max 64 chars, unique per account)
rulesobjectYESCountry code to discount % map. E.g. {"IN": 65, "BR": 45}
curl -X POST "https://api.getparity.dev/v1/presets" \
     -H "X-API-Key: parity_live_YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{"name": "aggressive", "rules": {"IN": 65, "BR": 45, "NG": 80}}'
EXAMPLE RESPONSE
{
  "id": "abc123",
  "name": "aggressive",
  "isActive": false,
  "rules": { "IN": 65, "BR": 45, "NG": 80 },
  "createdAt": "2026-03-15T00:00:00.000Z",
  "updatedAt": "2026-03-15T00:00:00.000Z"
}
GET /v1/presets AUTH

List all your discount presets.

curl "https://api.getparity.dev/v1/presets" \
     -H "X-API-Key: parity_live_YOUR_KEY"
GET /v1/presets/:id AUTH

Get a single preset with its rules.

curl "https://api.getparity.dev/v1/presets/abc123" \
     -H "X-API-Key: parity_live_YOUR_KEY"
PUT /v1/presets/:id AUTH

Update a preset. Full replace of name and rules.

BODYTYPEREQDESCRIPTION
namestringYESPreset name (max 64 chars, unique per account)
rulesobjectYESCountry code to discount % map. E.g. {"IN": 65, "BR": 45}
curl -X PUT "https://api.getparity.dev/v1/presets/abc123" \
     -H "X-API-Key: parity_live_YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{"name": "conservative", "rules": {"IN": 40, "BR": 30}}'
DELETE /v1/presets/:id AUTH

Delete a preset and its rules. If the preset was active, discounts revert to defaults.

curl -X DELETE "https://api.getparity.dev/v1/presets/abc123" \
     -H "X-API-Key: parity_live_YOUR_KEY"
POST /v1/presets/:id/activate AUTH

Set a preset as active. All future pricing calls will use its discount rules automatically. Countries not in the preset fall back to PPP defaults.

curl -X POST "https://api.getparity.dev/v1/presets/abc123/activate" \
     -H "X-API-Key: parity_live_YOUR_KEY"
POST /v1/presets/deactivate AUTH

Deactivate all presets, reverting to default PPP-based discounts.

curl -X POST "https://api.getparity.dev/v1/presets/deactivate" \
     -H "X-API-Key: parity_live_YOUR_KEY"

ERRORS

All errors return { "error": "message", "code": "ERROR_CODE" }

CODEMEANING
MISSING_PARAMA required parameter is missing
INVALID_PARAMA parameter value is invalid
MISSING_API_KEYX-API-Key header not provided
INVALID_API_KEYAPI key is not valid
RATE_LIMIT_EXCEEDEDMonthly request limit reached
IP_LIMIT_EXCEEDEDToo many distinct IPs for this API key
INVALID_TOKENVisitor token is invalid or expired
COUNTRY_NOT_FOUNDNo PPP data for the requested country
PRESET_NOT_FOUNDPreset ID or name not found
PLAN_LIMITFeature not available on current plan
PRESET_LIMIT_EXCEEDEDMaximum presets reached for plan

VPN DETECTION

Every pricing response includes a confidence object with VPN detection signals:

FIELDTYPEDESCRIPTION
vpnDetectedbooleanWhether any VPN signal was detected
vpnConfidencestring"high", "medium", "low", "none", or "external"
vpnSignalsarraySignals triggered: "asn_match", "timezone_mismatch", "external_override"
dataFreshbooleanWhether exchange rate data is current

BRING YOUR OWN VPN DETECTION

Need more accurate VPN detection? Use your own provider (e.g. IPinfo, ipgeolocation.io) and pass the result to ParityAPI via the vpn_override parameter.

// Your server — check VPN with your preferred provider
const ipinfo = await fetch(`https://ipinfo.io/${visitorIp}?token=YOUR_IPINFO_TOKEN`);
const { privacy } = await ipinfo.json();

// Pass the result to ParityAPI
const parity = await fetch(
  `https://api.getparity.dev/v1/pricing?base_price=99&token=${token}&vpn_override=${privacy.vpn}`,
  { headers: { "X-API-Key": process.env.PARITY_KEY } }
);

// Response will have vpnConfidence: "external" and vpnSignals: ["external_override"]

PICK A PLAN.

ALL CORE FEATURES INCLUDED ON EVERY PLAN. CUSTOM PRESETS ON STARTER+. NO CREDIT CARD FOR FREE TIER.

GET YOUR KEY.