Türkçe · English

Percentile API

Percentiles and z-scores on your own site, using WHO, CDC and Neyzi references. The calculation is the same as the pediatrirutinleri.com percentile calculator.

Embedded form

No coding: add two lines to your page and the calculator opens on your site. No key is needed; the form works only on your approved domains.

API

For your own interface and server: send measurements from your server and receive JSON results. One measurement or up to 100 per request.

Apply

1. Application and key

  1. Sign in with your Pediatri Rutinleri account (your mobile app account works too; if you have none, register for free) and apply on the Percentile API service page (in Turkish): organisation, website, intended use; your server IP addresses for the API, your domains for the embedded form. The application is linked to your account and the result is sent to your account's email address.
  2. Every application is reviewed by an administrator and you are answered by email. Use is currently free within a daily quota.
  3. If the embedded form is approved, the embed code arrives by email.
  4. If the API is approved, you receive a one-time link (valid for 72 hours). The key is generated when you press “Show key” on that page and is shown only once. The key is never emailed and we do not store it in plain text. If you lose it, a new one is issued.

2. Embedded form

Add the code from the approval email to your page (SITE_ID is the identifier you were given):

<iframe src="https://pediatrirutinleri.com/api/widget/?site=SITE_ID"
        title="Persentil hesaplayıcı" style="width:100%;min-height:720px;border:0"
        loading="lazy" referrerpolicy="strict-origin"></iframe>
<script src="https://pediatrirutinleri.com/api/widget/gomme.js" async></script>

If your site uses a Content-Security-Policy (CSP)

If the form does not appear, your site's security policy is most likely blocking external frames. Add this to your CSP header:

frame-src … https://pediatrirutinleri.com
script-src … https://pediatrirutinleri.com   (optional: only for automatic height)

Without script-src the form still works; only gomme.js is not loaded and the frame keeps the min-height from the code. If you cannot change your CSP, use the API with your own form.

3. API

POST https://pediatrirutinleri.com/api/v1/persentil.php

HeaderValue
AuthorizationBearer prk_live_… (never in the URL)
Content-Typeapplication/json
User-AgentYour application's name. The server protection may reject requests without a User-Agent.

Request

{
  "id": "meas-8812",
  "ref": "who",
  "sex": 1,
  "bday": "2024-03-15",
  "tday": "2026-10-01",
  "height": 89.4,
  "measure": "h",
  "weight": 12.6,
  "hc": 47.5,
  "gaw": 34,
  "gad": 2,
  "mheight": 162,
  "dheight": 178,
  "lang": "en"
}

Batch: {"items": [ {…}, {…} ]} (up to 100 measurements).

FieldRequiredDescription
refyesReference: who, cdc, neyzi
sexyes1 = female, 2 = male
bday + tdayone ofBirth date + measurement date, YYYY-MM-DD; both together
agedaysor thisChronological age in days (0–7305)
height / weight / hcat least oneHeight cm (20–250) / weight kg (0.2–300) / head circumference cm (15–80)
measurenoHow height was measured: l = recumbent (length), h = standing (height). If it differs from what the reference expects, height is adjusted (CDC 0.8 cm, WHO/Neyzi 0.7 cm). If omitted, no adjustment is made.
gaw, gadnoPreterm birth: gestational age in weeks 22–36 and days 0–6 (integers). Corrected age is used up to 24 months chronological age.
mheight, dheightnoMother's and father's height, cm; given together they produce target height
idnoA short technical identifier to match your own record: up to 64 characters, letters, digits and _ . : -. Returned as is.
langnoLanguage of error messages: tr (default) or en. If omitted, the Accept-Language header is used. Field names and codes are language-independent.
graphnotrue: growth curves are included (single requests only, see below)

Numbers may be JSON numbers (89.4) or strings with a decimal point ("89.4"). Unknown fields are ignored.

Response

{
  "success": true,
  "result": {
    "id": "meas-8812", "ref": "who", "sex": 1,
    "age": { "months": 29.3, "chrono": {"total_days": 930, "years": 2, "months": 6, "days": 16}, "corrected": null },
    "preterm": { "applied": false, "reason": "over_24_months", "gaw": 34, "gad": 2, "corr_days": null, "pma_days": null },
    "height": { "measured": 89.4, "used": 90.1,
                "measure_adj": {"measure": "h", "expected": "l", "diff_cm": 0.7},
                "z": 0.12, "p": 54.78, "height_age_m": 28.4, "ideal_weight": 12.9 },
    "weight": { "value": 12.6, "z": -0.05, "p": 47.9, "rel_weight": 98 },
    "hc": { "value": 47.5, "z": 0.3, "p": 61.2 },
    "bmi": { "value": 15.52, "z": …, "p": … },
    "wfh": { "z": …, "p": … },
    "target": { "cm": 163.5, "low": 156.5, "high": 170.5, "z": 0.21 }
  },
  "request_id": "9f2c…"
}
FieldMeaning
age.monthsAge used in the calculation, months (corrected if preterm)
age.chrono / age.correctedChronological / corrected age: total days, years, months, days
pretermPreterm correction (null if gaw was not sent). reason: over_24_months (chronological age is over 24 months), invalid_gaw, invalid_gad. corr_days: days subtracted, pma_days: postmenstrual age in days
height.measured / height.usedHeight sent / height used after the measurement-method adjustment
height.measure_adjMeasurement-method adjustment (null if none): method sent and method the reference expects (l/h), difference in cm
z, pZ-score and percentile
height.height_age_m, height.ideal_weightHeight age (months) and ideal weight (kg)
weight.rel_weightRelative weight, %
wfhWeight for height
targetTarget height (cm) and its range; z against the 18-year reference

Growth curves (optional)

Send "graph": true in a single request and result.graphs is added: for each measurement sent that lies within the reference range (height, weight, hc, bmi), the P3, P10, P25, P50, P75, P90 and P97 curves and the child's point. You can draw your own chart from it. Batch requests return no curves.

"graphs": {
  "height": {
    "unit": "cm", "x_unit": "month", "x_range": [0, 23.984],
    "centiles": [3, 10, 25, 50, 75, 90, 97],
    "x": [0, 0.493, …],                       // age (months)
    "p": { "3": [45.6, …], "50": [49.1, …], "97": [52.7, …], … },
    "point": [13.142, 76.0]                   // [age used (months), value used]
  }
}

The window follows the child's age: 0–24 months up to age 2, 0–60 months up to age 5, otherwise 60–240 months (as far as the reference table covers). Corrected age is used for preterm children and adjusted height after a measurement-method adjustment.

Example: PHP

$key = getenv('PR_PERCENTILE_API_KEY'); // never hard-code it
$ch = curl_init('https://pediatrirutinleri.com/api/v1/persentil.php');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_USERAGENT      => 'ExampleClinic/1.0',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode([
        'ref' => 'who', 'sex' => 2,
        'bday' => '2025-01-10', 'tday' => '2026-10-01',
        'height' => 82.0, 'weight' => 11.2, 'lang' => 'en',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);

Example: Node.js (18+)

const res = await fetch('https://pediatrirutinleri.com/api/v1/persentil.php', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PR_PERCENTILE_API_KEY}`,
    'Content-Type': 'application/json',
    'User-Agent': 'ExampleClinic/1.0',
  },
  body: JSON.stringify({ ref: 'cdc', sex: 1, agedays: 1500, height: 101.2, weight: 15.8, lang: 'en' }),
});
const data = await res.json();

4. Proxy file for forms your visitors fill in

If your site's visitors enter the measurements, the browser must not call the API directly (the key would be visible in the page source and stolen). The flow should be:

Visitor's browser  →  your server (proxy file)  →  pediatrirutinleri.com API

Important: your proxy file is public. Without protection, anyone can call it in a loop and use up your daily quota. Take at least these three measures: accept requests only from your own page, limit each visitor, allow only single measurements. If your form is public, we also recommend a CAPTCHA.

Example proxy file (PHP with APCu; without APCu, keep the counter in a database or Redis):

<?php
// https://your-site.com/percentile.php
const SITE_ORIGIN  = 'https://your-site.com';
const MINUTE_LIMIT = 20; // per visitor IP

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); exit; }

// 1) Only from your own page
if (($_SERVER['HTTP_ORIGIN'] ?? '') !== SITE_ORIGIN) { http_response_code(403); exit; }

// 2) Per-visitor limit per minute
$counter = 'prp_' . hash('sha256', $_SERVER['REMOTE_ADDR']);
apcu_add($counter, 0, 60);
if (apcu_inc($counter) > MINUTE_LIMIT) { http_response_code(429); exit; }

// 3) Single measurement and known fields only (batch "items" is not passed on)
$input   = json_decode(file_get_contents('php://input', false, null, 0, 4096), true);
$allowed = ['ref', 'sex', 'bday', 'tday', 'agedays', 'height', 'weight', 'hc',
            'measure', 'gaw', 'gad', 'mheight', 'dheight', 'lang'];
$item    = is_array($input) ? array_intersect_key($input, array_flip($allowed)) : [];

// 4) Call the API from your server, key from an environment variable
$ch = curl_init('https://pediatrirutinleri.com/api/v1/persentil.php');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_USERAGENT      => 'YourSite/1.0',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . getenv('PR_PERCENTILE_API_KEY'),
                               'Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode($item ?: new stdClass()),
]);
$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($body === false || $status >= 500) {
    http_response_code(502);
    echo json_encode(['success' => false, 'error' => ['code' => 'server_error', 'message' => 'Calculation is unavailable right now.']]);
    exit;
}
http_response_code($status);
echo $body; // API response as is

The JavaScript on your page calls this file with fetch('/percentile.php', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(item)}). If you prefer not to write code, use the embedded form.

5. Errors and limits

{ "success": false, "error": { "code": "invalid_input", "message": "…", "field": "height" }, "request_id": "…" }

code and field are language-independent; base your program on them. message is in Turkish or English according to lang.

HTTPcodeWhat to do
400invalid_input, invalid_body, too_many_itemsFix the input; field tells you which field.
401unauthorizedKey missing, wrong or revoked.
403ip_not_allowed, https_requiredCall from an allowed IP, over HTTPS.
405 / 413 / 415method_not_allowed / body_too_large / unsupported_media_typePOST only / body at most 64 KB / Content-Type: application/json
429rate_limited, quota_exceededRespect the Retry-After header; the quota resets at midnight Istanbul time.
5xxserver_errorTry again later.

When the general per-IP limit is exceeded, the 429 body has the form {"success": false, "error": "…"}; act on the HTTP status.

Response headers: X-RateLimit-Limit, X-RateLimit-Remaining (requests per minute), X-Quota-Limit, X-Quota-Remaining (measurements per day), X-Request-Id (quote it when asking for support).

6. Security and personal data

Results are for clinical decision support; diagnosis and treatment decisions belong to the physician.

Pediatri Rutinleri · Privacy (Turkish) · Terms of use (Turkish)