iChek Address API
Make sure every customer gives you a delivery address that actually works. iChek fills in city and state from the PIN code, catches wrong or incomplete addresses while the customer is still typing, and returns a clean, standardized address you can ship to.
Create a free accountTry the live demoQuick start
- Create an account. The free plan includes 1,000 checks a month.
- Open Install & settings in your dashboard. You get two keys:
pk_…is the publishable key. It's safe to put in web pages and is used by the widget.sk_…is the secret key. It's for your server only. Never put it in a web page or app.
- Pick how you connect:
You have… Use Coding needed Any website checkout (custom, Magento, OpenCart…) Checkout widget: one script tag Paste one line WooCommerce WordPress plugin None Your own backend or mobile app REST API A few lines A spreadsheet of existing addresses Bulk upload in the dashboard None - Before going live, add your website domain under Allowed website domains so your publishable key only works on your site.
Checkout widget
Paste this on your checkout or address page, just before </body>. Use your own publishable key:
<script src="https://api.isectrain.com/widget.js" data-key="pk_YOUR_KEY" async></script>
That's all. The widget finds the address fields on the page by itself, including forms that appear later, like WooCommerce's. Then it:
- fills city and state as soon as a valid PIN code is typed (it works with text boxes and state drop-downs)
- checks the address when the customer leaves a field, and shows hints right under the address box
- offers a "Use this address" button with the cleaned-up version
- adds hidden fields to your form so your server receives the result:
ichek_status,ichek_score,ichek_check_id
Options
| Attribute | What it does |
|---|---|
data-block-invalid="true" | If the address is INVALID, the customer must fix it or click "Continue anyway" before the form submits. |
data-lang="hi" | Shows the widget's own labels in Hindi. |
data-auto="false" | Turns off auto-detection. Tell the widget your fields yourself (below). |
Point it at your fields (optional)
<script src="https://api.isectrain.com/widget.js" data-key="pk_YOUR_KEY" data-auto="false"></script>
<script>
iChek.attach({
pincode: '#zip', city: '#city', state: '#state',
line1: '#address1', line2: '#address2', landmark: '#landmark', phone: '#phone',
onResult: function (r) { console.log(r.status, r.score, r.standardized.full); }
});
</script>
Every check also fires an ichek:result event on the form, with the result in event.detail.
WooCommerce plugin
- Download ichek-woocommerce.zip.
- In WordPress, go to Plugins → Add New → Upload Plugin, choose the zip, then Install and Activate.
- Go to WooCommerce → iChek and paste your publishable key. The iChek URL is already filled in. Click Save.
The widget now runs on your checkout and cart pages. Each order stores the address check result, which shows in the order screen under the shipping address.
REST API
| Base URL | https://api.isectrain.com/api/v1 |
|---|---|
| Authentication | Header X-API-Key: sk_YOUR_SECRET_KEY |
| Format | JSON in, JSON out (UTF-8) |
| Interactive reference | https://api.isectrain.com/docs (try calls in the browser) |
POST/address/verify
Checks one address and returns a score, the problems found, hints to show the customer and a standardized address.
| Field | Required | Description |
|---|---|---|
line1 | yes | House / flat number, building, street |
line2 | Area / locality | |
landmark | Nearby landmark | |
city | City / town (filled from the PIN if empty) | |
state | State name or code (KA, Karnataka…). Filled from the PIN if empty. | |
pincode | yes (India) | 6-digit PIN code |
phone | Mobile number. +91 and spaces are fine. | |
country | ISO code. Defaults to IN. Other countries get basic checks only. |
curl -X POST https://api.isectrain.com/api/v1/address/verify \
-H "X-API-Key: sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"line1":"flat 204 lotus towers, 5th cross","line2":"indiranagar",
"city":"Bangalore","state":"KA","pincode":"560038","phone":"+91 98765 43210"}'
<?php
$ch = curl_init('https://api.isectrain.com/api/v1/address/verify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: sk_YOUR_SECRET_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'line1' => 'flat 204 lotus towers, 5th cross', 'line2' => 'indiranagar',
'city' => 'Bangalore', 'state' => 'KA', 'pincode' => '560038', 'phone' => '+91 98765 43210',
]),
]);
$r = json_decode(curl_exec($ch), true);
if ($r['status'] === 'INVALID') {
// ask the customer to fix: implode("\n", $r['suggestions'])
}
echo $r['standardized']['full'];
import requests
r = requests.post(
"https://api.isectrain.com/api/v1/address/verify",
headers={"X-API-Key": "sk_YOUR_SECRET_KEY"},
json={"line1": "flat 204 lotus towers, 5th cross", "line2": "indiranagar",
"city": "Bangalore", "state": "KA", "pincode": "560038", "phone": "+91 98765 43210"},
timeout=10,
).json()
print(r["status"], r["score"], r["standardized"]["full"])
for hint in r["suggestions"]:
print("-", hint)
// Node 18+ (server side; never expose sk_ keys in the browser)
const res = await fetch("https://api.isectrain.com/api/v1/address/verify", {
method: "POST",
headers: { "X-API-Key": "sk_YOUR_SECRET_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ line1: "flat 204 lotus towers, 5th cross", line2: "indiranagar",
city: "Bangalore", state: "KA", pincode: "560038", phone: "+91 98765 43210" }),
});
const r = await res.json();
console.log(r.status, r.score, r.standardized.full);
Response: a good address
{
"score": 95,
"status": "VERIFIED",
"standardized": {
"line1": "Flat 204 Lotus Towers, 5th Cross",
"line2": "Indiranagar",
"landmark": "",
"city": "Bangalore",
"state": "Karnataka",
"pincode": "560038",
"country": "IN",
"full": "Flat 204 Lotus Towers, 5th Cross, Indiranagar, Bangalore, Karnataka 560038"
},
"issues": [
{ "code": "NO_LANDMARK", "severity": "info", "message": "No landmark given", "penalty": 5 }
],
"suggestions": [ "Add a nearby landmark (helps the courier)" ],
"pincode_info": { "pin": "560038", "found": true, "state": "Karnataka",
"districts": ["Bengaluru"], "offices": ["HAL II Stage", "Indiranagar"] },
"location": null,
"phone": "9876543210",
"phone_valid": true,
"country": "IN"
}
Response: an address that needs fixing ("line1": "near temple", "state": "Bihar", "pincode": "560038")
{
"score": 40,
"status": "INVALID",
"issues": [
{ "code": "STATE_PIN_MISMATCH", "severity": "error", "message": "PIN 560038 belongs to Karnataka, not Bihar", "penalty": 25 },
{ "code": "LINE_SHORT", "severity": "warn", "message": "Address is very short", "penalty": 20 },
{ "code": "NO_HOUSE_NO", "severity": "warn", "message": "No house / flat / plot number", "penalty": 15 }
],
"suggestions": [
"PIN and state don't match — is the PIN or the state wrong? (Karnataka)",
"Add building, street and area",
"Add house or flat number"
],
...
}
GET/pincode/{pin}
Looks up a PIN code and returns its state, districts and post offices. Useful for building your own auto-fill.
curl https://api.isectrain.com/api/v1/pincode/560038 -H "X-API-Key: sk_YOUR_SECRET_KEY"
{ "pin": "560038", "valid_format": true, "found": true, "state": "Karnataka",
"districts": ["Bengaluru"], "offices": ["HAL II Stage", "Indiranagar"], "source": "api" }
found is false when the PIN doesn't exist. It is null when only the PIN's range could be checked, because the lookup service was unreachable.
Response fields
| Field | Meaning |
|---|---|
score | 0–100. Starts at 100, and each problem subtracts its penalty. |
status | VERIFIED (80+): ship it · NEEDS_REVIEW (50–79): show the hints · INVALID (<50): ask the customer to fix it |
standardized | The cleaned address: proper capitalization, abbreviations expanded (opp → Opposite, rd → Road), canonical state name, city/state filled from the PIN, and full as one line. |
issues[] | Each problem: code, severity (error / warn / info), message, penalty |
suggestions[] | Short, customer-friendly hints, ready to show on screen. |
pincode_info | What we know about the PIN code (state, districts, post offices). |
location | {lat, lon, precision} when available, otherwise null. |
phone, phone_valid | The normalized 10-digit mobile number, and whether it's a valid Indian mobile. |
Issue codes
| Code | Severity | Meaning |
|---|---|---|
PIN_MISSING / PIN_FORMAT | error | No PIN, or not 6 digits |
PIN_NOT_FOUND | error | The PIN doesn't exist in India Post records |
STATE_PIN_MISMATCH | error | The state doesn't match the PIN code |
JUNK_TEXT | error | Test or placeholder text ("test", "asdf", "xyz"…) |
LINE_MISSING | error | No street address |
CITY_PIN_MISMATCH | warn | The city isn't in the PIN code's area |
LINE_SHORT / LINE_FEW_WORDS | warn | The address is too short to find |
NO_HOUSE_NO | warn | No house / flat / plot number |
STATE_UNKNOWN, CITY_MISSING, PHONE_INVALID | warn | Unrecognized state, empty city, or invalid mobile |
NO_LANDMARK, STATE_FILLED, CITY_FILLED, PIN_UNVERIFIED | info | Hints and auto-fills |
Bulk CSV / Excel
In the dashboard, go to Bulk upload → Addresses and upload a .csv or .xlsx file of up to 5,000 rows. Column names are matched flexibly ("Pin Code", "Mobile", "Address 1", Shopify/WooCommerce exports…). You get a score, status, standardized address and hints for every row, and can download the results as CSV.
From code: POST /api/v1/bulk/verify with multipart fields file and mode=addresses.
Errors & limits
| HTTP | Meaning | What to do |
|---|---|---|
| 401 | Missing or wrong key | Check X-API-Key (server) or data-key (widget) |
| 402 | Monthly quota used up | Upgrade your plan, or wait for next month |
| 403 | Domain not allowed, or Pro feature | Add your domain in Settings, or upgrade to Pro |
| 429 | Too many requests from one IP (widget: 60 per minute) | Slow down and retry |
| 400 / 422 | Bad input | The response body says which field |
RTO risk scoring PRO
For COD-heavy stores. Every order gets a risk level (LOW / REVIEW / HIGH) with reasons. The score uses address quality, COD vs prepaid, order value, the customer's past RTOs and failed deliveries, one phone used with many addresses (or one address with many phones), the PIN code's RTO rate and bursts of orders. Your team works a review queue (call, then Verify or Reject) before dispatch. Courier outcomes flow back, so the rules can be tuned from real results.
| Endpoint | Use |
|---|---|
POST/order/score | Address fields plus order_id, customer_name, payment_method (COD/PREPAID) and order_value. Returns risk_level, risk_score and risk_reasons. |
POST/order/outcome | {"order_id":"1001","outcome":"delivered | ndr | rto | cancelled"} |
POST/order/verify | {"order_id":"1001","action":"verified | rejected","note":"called customer"} |
GET/orders/risk | Orders waiting for a decision, highest risk first |
| Shopify / WooCommerce | No code: paste the webhook URL from your dashboard into your store's webhook settings, and every new order is scored automatically. |
| Alerts | Set a callback URL. REVIEW/HIGH orders are POSTed to it and signed with X-iChek-Signature (HMAC-SHA256 of the body using your secret key). |
Downloads
- WooCommerce plugin (zip)
- OpenAPI specification (import into Postman, Insomnia, or code generators)
- Sample addresses CSV for trying bulk upload
- widget.js (source, no dependencies)
PIN code data: India Post. Questions? Contact us through ichek.info.