One API call. Country detection. PPP data. Suggested discount. Local currency. Done.
GET YOUR API KEY READ THE DOCS// HIT CALCULATE.
One script tag on your page. Mark prices with data-parity-price. Visitors instantly see prices in their local currency.
One API call in your checkout backend. Gets the adjusted price and passes it to your payment processor. Works with Stripe, Paddle, LemonSqueezy, anything.
Customers see fair prices, get charged fair prices. VPN detection prevents discount abuse. International conversions go up.
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.
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>
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.
Base URL: https://api.getparity.dev/v1
All authenticated endpoints require the X-API-Key header. Hit GET /v1 for machine-readable docs.
Calculate PPP-adjusted pricing. Supports a single price or multiple prices in one call (ideal for shops with many products).
| PARAM | TYPE | REQ | DESCRIPTION |
|---|---|---|---|
| base_price | number | * | Single product price in USD. Use this OR prices. |
| prices | string | * | Comma-separated prices in USD (max 100). Use this OR base_price. |
| country | string | NO | ISO 3166 country code (auto-detected from IP if omitted) |
| token | string | NO | Signed visitor token from /v1/detect (enables server-side calls with accurate VPN detection) |
| vpn_override | string | NO | Set to "true" to flag this request as VPN-detected. Use with your own VPN detection service (e.g. IPinfo). |
| preset | string | NO | Preset 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"
{
"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 }
}
// 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" },
...
}
{
"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 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" } }
);
{
"token": "eyJjb3VudHJ5IjoiSU4i...",
"country": "IN",
"expires_in": 300
}
List all supported countries with currency metadata.
curl "https://api.getparity.dev/v1/countries"
Create a free account and receive an API key.
| BODY | TYPE | REQ | DESCRIPTION |
|---|---|---|---|
| string | YES | Your email address |
curl -X POST "https://api.getparity.dev/v1/signup" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'
{
"apiKey": "parity_live_abc123...",
"plan": "free"
}
Check your current month's request count and limits.
curl "https://api.getparity.dev/v1/usage" \
-H "X-API-Key: parity_live_YOUR_KEY"
{
"plan": "free",
"used": 42,
"limit": 1000,
"period": "2025-01"
}
Create a Stripe checkout session to upgrade to a paid plan.
| BODY | TYPE | REQ | DESCRIPTION |
|---|---|---|---|
| plan | string | YES | "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"}'
Health check. Returns API status and version.
curl "https://api.getparity.dev/v1/health"
Create a named discount preset with per-country rules. Starter: 5 presets, Pro: 20 presets. Not available on Free plan.
| BODY | TYPE | REQ | DESCRIPTION |
|---|---|---|---|
| name | string | YES | Preset name (max 64 chars, unique per account) |
| rules | object | YES | Country 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}}'
{
"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"
}
List all your discount presets.
curl "https://api.getparity.dev/v1/presets" \
-H "X-API-Key: parity_live_YOUR_KEY"
Get a single preset with its rules.
curl "https://api.getparity.dev/v1/presets/abc123" \
-H "X-API-Key: parity_live_YOUR_KEY"
Update a preset. Full replace of name and rules.
| BODY | TYPE | REQ | DESCRIPTION |
|---|---|---|---|
| name | string | YES | Preset name (max 64 chars, unique per account) |
| rules | object | YES | Country 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 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"
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"
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"
All errors return { "error": "message", "code": "ERROR_CODE" }
| CODE | MEANING |
|---|---|
| MISSING_PARAM | A required parameter is missing |
| INVALID_PARAM | A parameter value is invalid |
| MISSING_API_KEY | X-API-Key header not provided |
| INVALID_API_KEY | API key is not valid |
| RATE_LIMIT_EXCEEDED | Monthly request limit reached |
| IP_LIMIT_EXCEEDED | Too many distinct IPs for this API key |
| INVALID_TOKEN | Visitor token is invalid or expired |
| COUNTRY_NOT_FOUND | No PPP data for the requested country |
| PRESET_NOT_FOUND | Preset ID or name not found |
| PLAN_LIMIT | Feature not available on current plan |
| PRESET_LIMIT_EXCEEDED | Maximum presets reached for plan |
Every pricing response includes a confidence object with VPN detection signals:
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
| vpnDetected | boolean | Whether any VPN signal was detected |
| vpnConfidence | string | "high", "medium", "low", "none", or "external" |
| vpnSignals | array | Signals triggered: "asn_match", "timezone_mismatch", "external_override" |
| dataFresh | boolean | Whether exchange rate data is current |
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"]
ALL CORE FEATURES INCLUDED ON EVERY PLAN. CUSTOM PRESETS ON STARTER+. NO CREDIT CARD FOR FREE TIER.