Basics
Base URL http://localhost:3000. Sab kuch JSON hai. Har response ka shape fix hai:
{ "ok": true, "data": โฆ } // success
{ "ok": false, "error": "โฆ" } // failure
src/server.js me enforcement block comment out kiya
hua hai, isliye filhaal kisi bhi IP se request aa sakti hai โ sirf passkey wali layer chal rahi hai.
Wapas on karne ke liye us block ko uncomment karo; tab sirf allowlisted IP (default
91.108.105.218, ALLOWED_IPS se badlo) aur localhost chalenge, baaki sab ko
403 Forbidden: IP not allowed milega aur wo attempt ip.blocked ke roop me
log hoga.
GET /health bina passkey ke uptime check deta hai.
Authentication
Har endpoint ko passkey chahiye. Teen jagah se bhej sakte ho โ jo suit kare. GET ke saath bhi JSON body chalti hai, to passkey / id / month sab ek hi payload me bhej sakte ho:
# 1. payload (body) me
curl -X POST http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","rate":5820.5,"effective_from":"2026-04"}'
# 2. query string me
curl "http://localhost:3000/api/rates?passkey=client_xxx"
# 3. header me
curl -H "x-passkey: client_xxx" http://localhost:3000/api/rates
curl -H "Authorization: Bearer client_xxx" http://localhost:3000/api/rates
# GET + body -- sab kuch ek payload me
curl -X GET http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","month":"2026-02"}'
passkeys table me nahi hai use turant
reject kiya jaata hai โ koi guest ya default access nahi. Reject bhi analytics me record hota hai.
| Situation | Response |
|---|---|
| Passkey bheji hi nahi | 401 passkey missing |
| Passkey table me nahi hai | 401 Invalid passkey |
Passkey hai par active = 0 | 403 Passkey is disabled |
| Admin endpoint, normal key se | 403 Admin passkey required |
Key ka scope โ kis key ko kitne rates dikhte hain
Har passkey ka ek scope hota hai. Ye tay karta hai ki wo key kaunse rates
dekh / badal sakti hai. GET /api/me se apna scope check kar sakte ho.
| scope | Kaise banti hai | Kya dikhta hai |
|---|---|---|
all |
Console / admin se โ POST /api/keys |
Saare rates, chahe kisi ne bhi banaye ho. Purani sab keys yahi hain. |
own |
User khud โ POST /api/keys/register |
Sirf apne profile id ke rates โ read-only. Key ki id hi profile id hai, to
us profile ke saare rates aur poori history dikhti hai (panel ke banaye hue bhi).
Doosre profile par 404, aur kuch bhi likhne par 403. |
own key ka filter
rates.id == key.id par lagta hai โ "kisne banaya" par nahi. Isliye
profile_1001 ki key ko profile_1001 ke wo rates bhi dikhte hain
jo panel ne banaye the.
rates.owner_id ab sirf audit ke liye hai (kis key ne row banaya) โ
usse visibility tay nahi hoti.
Profile ids
id tum bhejte ho.
- Type TEXT โ
profile_1001jaisa string bhi,90210jaisa number bhi (andar string ban jaata hai) - Max 120 characters, trim ho jaata hai
/aur control characters allowed nahi โ400 Invalid id- Rate aur passkey dono me wahi profile id use kar sakte ho โ dono tables independent hain
id teen jagah se accept hota hai: URL path, ?id= query, ya payload. Teeno ek hi kaam karte hain:
GET /api/rates/profile_1001?month=2026-03
GET /api/rates?id=profile_1001&month=2026-03
PUT /api/rates {"id":"profile_1001","month":"2026-03","rate":5999.99}
Ek profile ke kai rate rows hote hain โ har period ka apna. Isliye har period ka apna
rate_id hota hai jo server banata hai aur create ke response me wapas
aata hai. Usse kisi ek period ko exactly target karte ho โ rate badalna ho ya month range,
dono ke liye wahi id.
Error codes
| Code | Kab |
|---|---|
| 400 | id / rate / effective_from missing ya invalid, kharab JSON |
| 401 | Passkey missing ya table me nahi |
| 403 | Passkey disabled, admin chahiye, ya IP allowlist me nahi (jab allowlist on ho) |
| 404 | Us month me koi rate lagu nahi, passkey exist nahi karta, ya route galat |
| 409 | Period overlap kar raha hai, ya wahi passkey id pehle se hai |
| 413 | Payload 1 MB se bada |
Apni key khud banao signup secret
User ko admin ke paas jaane ki zarurat nahi โ do call me apni key mil jaati hai.
user_id hi uska profile id hai, aur aise bani key ka scope
own hota hai โ wo sirf apne profile ka rate aur history padh sakta hai.
user_id ka ek bhi rate
humare paas nahi hai, uski key banti hi nahi โ 404 โฆ ka koi rate humare paas nahi hai.
Yaani rate pehle panel se banega, key baad me.
SIGNUP_SECRET chahiye (server ke .env me).
Passkey nahi โ signup secret. Bhejo header x-signup-secret, body
signup_secret, ya query ?signup_secret= me. Server par secret set
nahi hai to dono 503 dete hain (default band). Admin passkey ho to secret ki
zarurat nahi.
Step 1 ยท GET /api/keys/lookup?user_id=:user_id
Pehle ye check karo ki us user ki key pehle se hai ya nahi. Passkey ki value yahan kabhi wapas nahi aati โ sirf "hai ya nahi" pata chalta hai.
curl "http://localhost:3000/api/keys/lookup?user_id=acme" -H "x-signup-secret: $SIGNUP_SECRET"
# key nahi hai, par profile bhi nahi hai -> register nahi hoga
{ "ok": true, "data": { "user_id": "acme", "exists": false,
"profile_exists": false, "can_register": false } }
# key nahi hai aur profile maujood hai -> Step 2 par jao
{ "ok": true, "data": { "user_id": "acme", "exists": false,
"profile_exists": true, "can_register": true } }
# key pehle se hai -> naya register mat karo
{ "ok": true, "data": {
"user_id": "acme", "exists": true, "profile_exists": true, "can_register": false,
"active": true, "label": "Acme Ltd", "scope": "own", "is_admin": false,
"created_at": "2026-09-09 11:45:53" } }
| Field | Matlab |
|---|---|
exists | Us user_id ki passkey pehle se hai ya nahi |
profile_exists | Us profile id ka koi rate humare paas hai ya nahi |
can_register | Dono milakar โ Step 2 chalega ya nahi |
Step 2 ยท POST /api/keys/register
Sirf tab jab Step 1 me can_register: true aaya ho.
| Field | Zaroori? | Matlab |
|---|---|---|
user_id | haan | User ka apna id โ yahi passkeys.id banta hai |
label | nahi | Display naam. Na do to user_id hi lag jaata hai |
new_passkey | nahi | Apni pasand ki passkey. Na do to server strong random banata hai |
curl -X POST http://localhost:3000/api/keys/register -H "x-signup-secret: $SIGNUP_SECRET" -H 'content-type: application/json' -d '{"user_id":"acme","label":"Acme Ltd"}'
{ "ok": true,
"data": { "user_id": "acme",
"passkey": "pk_eaad439def25eccc9cfdcfe120d958e9",
"label": "Acme Ltd",
"scope": "own" },
"note": "Ye passkey ab dobara nahi dikhega -- abhi save kar lo." }
GET /api/keys se dekh sakta hai ya nayi key issue karega.
Apni pasand ki passkey bhejni ho
Server ki generated key yaad rakhne ka jhanjhat na ho to new_passkey me
apni value bhej do โ wahi store hoti hai aur wahi response me echo hoti hai:
curl -X POST http://localhost:3000/api/keys/register -H "x-signup-secret: $SIGNUP_SECRET" -H 'content-type: application/json' -d '{"user_id":"acme","new_passkey":"AcmeSecret2026!x"}'
{ "ok": true,
"data": { "user_id":"acme", "passkey":"AcmeSecret2026!x", "label":"acme", "scope":"own" },
"note": "Ye wahi passkey hai jo tumne bheji thi." }
| Rule | Kyun |
|---|---|
| 6โ200 characters | Ye seedha login credential hai โ utni hi lambi rakho jitni sambhal sako |
| Space / control character nahi | Passkey header aur query string me bhi jaati hai, wahan ye toot jaate hain |
| Pehle se kisi aur ki na ho | Takrayi to 409 โ doosri chuno |
new_passkey field aur yahi rules admin wale
POST /api/keys par bhi lagte hain.
Analytics log me ye value hamesha masked jaati hai (Acme...26!x).
Step 3 ยท us key se apna rate padho
Normal rate API wahi hai โ bas x-passkey me apni key lagao. List me sirf
tumhare profile ke rows aayenge, aur likhne wale endpoints band rahenge.
KEY=pk_eaad439def25eccc9cfdcfe120d958e9
# apne profile ke saare rates
curl http://localhost:3000/api/rates -H "x-passkey: $KEY"
# is month ka rate
curl "http://localhost:3000/api/rates/profile_1001?month=2026-06" -H "x-passkey: $KEY"
# poori history -- saare periods
curl http://localhost:3000/api/rates/profile_1001/history -H "x-passkey: $KEY"
# doosre profile par -> 404
curl http://localhost:3000/api/rates/profile_2002 -H "x-passkey: $KEY"
{ "ok": false, "error": "profile_2002 ka koi rate nahi hai" }
# kuch bhi badalne ki koshish -> 403
curl -X PATCH http://localhost:3000/api/rates/profile_1001 -H "x-passkey: $KEY" -d '{"rate":1}'
{ "ok": false, "error": "Ye key sirf padh sakti hai -- rate banane/badalne ke liye panel wali key chahiye" }
# apna scope check karo
curl http://localhost:3000/api/me -H "x-passkey: $KEY"
{ "ok": true, "data": { "id": "profile_1001", "label": "Acme Ltd", "is_admin": false,
"scope": "own", "sees_all_rates": false, "can_edit_rates": false } }
| Situation | Response |
|---|---|
| Signup secret galat / nahi bheja | 403 Invalid or missing signup secret |
Server par SIGNUP_SECRET set hi nahi | 503 Self-service signup band hai |
Us user_id ki key pehle se hai | 409 โฆ pehle se hai โ lookup se check karo |
| Us profile id ka koi rate hi nahi hai | 404 โฆ ka koi rate humare paas nahi hai |
| Doosre profile par hit kiya | 404 (403 nahi โ doosre ka data exist hi nahi karta) |
own key se create / update / delete | 403 Ye key sirf padh sakti hai |
Rates koi bhi valid passkey ยท scope ke hisaab se
all key ko saare rates aur poora likhne ka haq, own key ko
sirf apne profile id ke rates โ read-only.
all key ?profile_id=profile_1001 laga kar ek profile ke rates alag se dekh sakti hai.
effective_from (kis month se โ required) aur effective_to
(kis month tak โ khaali chhodo to open-ended) hota hai, dono YYYY-MM format me.
Ek profile ke kai period ho sakte hain โ us profile ki rate history. Bas periods
aapas me overlap nahi karne chahiye.
Ek profile ki history kaise banti hai
# January me: Jan se March tak ka rate
curl -X POST http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","name":"gold_22k","rate":5500,
"effective_from":"2026-01","effective_to":"2026-03"}'
# April me: April se December tak ka naya rate (purana waise ka waisa rehta hai)
curl -X POST http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","name":"gold_22k","rate":5820.5,
"effective_from":"2026-04","effective_to":"2026-12"}'
Ab profile_1001 ke do period hain, aur har ek ka apna rate_id:
rate_id 1 2026-01 โ 2026-03 rate 5500
rate_id 2 2026-04 โ 2026-12 rate 5820.5
rate_id server banata hai aur create ke response me wapas deta hai.
Use apne system me store kar lo โ baad me us period ko edit ya delete karne ka wahi
sabse pakka tareeka hai (rate badalna ho ya month range, dono ke liye wahi id).
GET /api/rates/:id?month=YYYY-MM โ us month ka rate
Yahi main lookup hai: month bhejo, us month me jo rate lagu tha wo milega.
month na do to is month ka rate.
curl "http://localhost:3000/api/rates/profile_1001?passkey=client_xxx&month=2026-03"
# -> rate 5500 (2026-01 โ 2026-03 wala period)
curl "http://localhost:3000/api/rates/profile_1001?passkey=client_xxx&month=2026-06"
# -> rate 5820.5 (2026-04 โ 2026-12 wala period)
{
"ok": true,
"data": { "rate_id": 1, "id": "profile_1001", "name": "gold_22k", "rate": 5500,
"effective_from": "2026-01", "effective_to": "2026-03",
"asked_month": "2026-03" }
}
month payload me bhi bhej sakte ho. Us month me koi period na mile to
404 โฆ me koi rate lagu nahi hai.
GET /api/rates/:id/history โ saare periods
curl -H "x-passkey: client_xxx" http://localhost:3000/api/rates/profile_1001/history
GET /api/rates โ sab profiles
# saare periods, saare profiles
curl "http://localhost:3000/api/rates?passkey=client_xxx"
# sirf wo rates jo March me lagu the -- har profile ka ek row
curl "http://localhost:3000/api/rates?passkey=client_xxx&month=2026-03"
POST /api/rates โ naya period
| Field | Required | Format |
|---|---|---|
| id | haan | profile id (TEXT) |
| rate | haan | number |
| effective_from | haan | YYYY-MM โ poori date bheji to month le lete hain |
| effective_to | nahi | YYYY-MM โ na do to open-ended |
| name | nahi | label |
| rate_id | โ | mat bhejo โ server khud banata hai aur response me deta hai |
Response me naye period ka rate_id aata hai โ usi se aage edit/delete karoge:
{
"ok": true,
"data": { "rate_id": 3, "id": "profile_1001", "name": "gold_22k", "rate": 6100,
"effective_from": "2027-01", "effective_to": "2027-06",
"created_at": "โฆ", "updated_at": "โฆ" }
}
409 milega, aur error me
bata diya jaata hai kaunsa period takra raha hai (uske rate_id ke saath).
PUT PATCH /api/rates/:id โ period edit
Kaunsa period edit karna hai wo selector se chunta hai. Selector query me bhi chalega aur payload me bhi โ jo suit kare:
| Selector | Kya chunta hai | Kab use karo |
|---|---|---|
| rate_id | bilkul wahi period | Sabse pakka. Rate ya month range โ kuch bhi badalna ho, yahi use karo |
| month | jo period us month ko cover karta hai | Jab rate_id paas na ho. Sirf rate badalne ke liye theek hai |
| kuch nahi | is month wala period | Aaj chal rahe rate ko chhedna ho |
Dono selector query me bhi chalte hain aur payload me bhi โ ?rate_id=2 ya
{"rate_id":2}, jo suit kare.
rate_id use karo. month
selector se period chunoge aur usi call me uska month range bhi badal doge, to sochna padega
ki kaunsa row chuna gaya tha โ rate_id me ye confusion hai hi nahi.
# 1. rate_id se rate badlo -- sab payload me
curl -X PUT http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","rate_id":1,"rate":5555}'
# 2. rate_id se month range badlo (overlap hua to 409)
curl -X PUT http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","rate_id":1,
"effective_from":"2025-11","effective_to":"2026-02"}'
# 3. rate_id nahi pata? month se dhundo -- Feb jis period me hai uska rate badlega
curl -X PUT http://localhost:3000/api/rates \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","id":"profile_1001","month":"2026-02","rate":5999}'
# 4. period dobara open-ended
curl -X PUT "http://localhost:3000/api/rates/profile_1001?rate_id=2" \
-H 'content-type: application/json' \
-d '{"passkey":"client_xxx","effective_to":null}'
Jo field bhejoge sirf wahi badlega โ baaki waise ke waise rehte hain, aur
updated_at apne aap set hota hai.
effective_to ko null kar sakte ho, par effective_from ko
khaali nahi โ rate hamesha kisi month se lagu hota hai.
DELETE /api/rates/:id โ ek period hatao
Wahi selectors chalte hain (query ya payload). Sirf wo period delete hota hai, baaki history
bachi rehti hai. rate_id doosre profile ka ho to 404 โ ek profile
doosre ka period nahi chhed sakta.
curl -X DELETE "http://localhost:3000/api/rates/profile_1001?passkey=client_xxx&rate_id=1"
{ "ok": true, "deleted": { "id": "profile_1001", "rate_id": 1 } }
GET /api/me
Ye passkey kiski hai โ { id, label, is_admin }.
Passkeys admin only
GET /api/keys
Saari keys โ id, passkey, label, is_admin, scope, active, created_at.
Kisi user ka kho gaya passkey yahin se dobara mil sakta hai.
POST /api/keys โ nayi key issue karo
Body: id (required, profile id) ยท label ยท new_passkey (optional โ na do to secret auto-generate;
diya to 6โ200 chars, bina space) ยท is_admin ยท scope.
all hai โ usse saare rates dikhte hain.
User-jaisi restricted key chahiye to "scope": "own" bhejo (wahi jo
/api/keys/register khud banata hai).
curl -X POST http://localhost:3000/api/keys \
-H 'content-type: application/json' -H 'x-passkey: admin_xxx' \
-d '{"id":"profile_7788","label":"partner-api"}'
{ "ok": true, "data": { "id": "profile_7788", "passkey": "pk_bf97โฆ", "label": "partner-api",
"is_admin": 0, "scope": "all", "active": 1, "created_at": "โฆ" } }
PATCH /api/keys/:id โ enable / disable / rename
curl -X PATCH http://localhost:3000/api/keys/profile_7788 \
-H 'content-type: application/json' -H 'x-passkey: admin_xxx' \
-d '{"active":false}'
Body: active ยท label ยท scope ("all" ya "own") โ
yani kisi user ki key ko baad me full access de sakte ho ya wapas apne rates tak seemit kar sakte ho.
Disable ki hui key ki har call 403 hoti hai, par analytics me auth.disabled ke roop me record hoti rehti hai.
DELETE /api/keys/:id
Apni hi key delete nahi kar sakte. Key delete karne par uske purane analytics events bane rehte hain (passkey_id null ho jaata hai).
Analytics admin only
GET /api/analytics/summary?days=7
Dashboard jo dikhata hai wahi data:
totalsโ total / ok / failed requests, active keys, avg latency, todaybyActionโ kis action ke kitne hitsbyKeyโ per passkey: get / create / update / delete / failed counts + last seendailyโ din-wise hits aur failures (daysse range)hourlyโ pichle 24 ghante ghanta-wisetopRatesโ sabse zyada request hone wale rate records
GET /api/analytics/events
Raw event log. Query: limit (max 500) ยท offset ยท passkey_id ยท action ยท failed=1.
curl -H "x-passkey: admin_xxx" \
"http://localhost:3000/api/analytics/events?passkey_id=profile_1001&limit=50"
{ "ok": true, "data": { "total": 665, "rows": [ โฆ ] } }
clie...0fa1), aur payload me se
passkey / token jaise fields mask karke store hote hain.Dynamic sections โ kaise kaam karta hai
Upar wala /api/rates ek fixed table hai โ uske columns code me likhe hain.
Sections uska ulta hai: tum runtime par table banate ho, uske fields aur unke types
tay karte ho, aur batate ho kaun si passkeys usko kaise use kar sakti hain.
PG_URL). Postgres band ho to
/api/sections aur /api/data 503 dete hain โ baaki API normal chalti rehti hai.
Ek section banane par teen cheezein ek hi transaction me hoti hain:
dyn_sectionsme section ka rowdyn_fieldsme har field ka row โ yahi schema ka record hai- asli
sec_<slug>table, jiska DDL unhi field rows se banta hai
Yaani field definitions sirf documentation nahi hain โ Postgres ke asli columns,
NOT NULL, UNIQUE, DEFAULT aur CHECK unse hi bante hain.
Isliye validation do jagah lagti hai: pehle JS me (saaf error message ke liye), phir DB me (aakhri guarantee).
Ek section, do keys
Access (section, passkey) ka joda hai, aur har jode ke apne teen flags โ
can_read, can_write, can_delete. Ek section ko jitni chaaho
keys se jod sakte ho, aur har key ko alag permission de sakte ho:
invoices โ profile_1001 read โ write โ delete โ
invoices โ profile_1002 read โ write โ delete โ
branches โ profile_1001 read โ write โ delete โ
admin passkey โ har section par sab kuch, hamesha
DELETE /api/sections/:slug/access/:passkey_id se saaf kar do.
Field types
Live list GET /api/types se milti hai (dashboard ka dropdown aur ye table wahi se bante hain).
| type | Postgres column | Kya accept karta hai |
|---|---|---|
| text | TEXT | Koi bhi string. options.max_length se limit |
| number | DOUBLE PRECISION | Decimal number โ 5820.5 |
| int | BIGINT | Poora number. 2.7 reject hoga |
| bool | BOOLEAN | true, 1, "yes", "on" โ sab chalega |
| date | DATE | YYYY-MM-DD |
| datetime | TIMESTAMPTZ | ISO timestamp |
| json | JSONB | Nested object / array |
| uuid | UUID | Standard uuid |
| enum | TEXT + CHECK | options.choices me allowed values โ DB level par bandha hua |
Har field ke saath ye flags de sakte ho:
| Flag | Matlab |
|---|---|
| required | NOT NULL. Rows pehle se hon to default bhi dena padega |
| unique | UNIQUE constraint. Repeat value par 409 |
| indexed | Us column par index โ filter tez. unique ke saath zaroorat nahi |
| default | Column ka DEFAULT. Field ke type se validate hota hai |
| label | Dashboard me dikhne wala naam. DB pe asar nahi |
a-z 0-9 _, max 32 chars.
Field name: wahi rules, max 48 chars. record_id, created_by,
created_at, updated_at reserved hain โ ye columns server khud banata hai.
Section builder admin only
POST /api/sections โ naya section
Fields aur access grants ek hi call me de sakte ho:
curl -X POST http://localhost:3000/api/sections \
-H "x-passkey: $ADMIN" -H "content-type: application/json" -d '{
"slug": "invoices",
"label": "Client invoices",
"description": "Har invoice ek row",
"fields": [
{ "name": "invoice_no", "type": "text", "required": true, "unique": true },
{ "name": "client_name", "type": "text", "indexed": true },
{ "name": "amount", "type": "number", "required": true },
{ "name": "status", "type": "enum", "options": { "choices": ["draft","sent","paid"] },
"default": "draft" },
{ "name": "due_date", "type": "date" },
{ "name": "paid", "type": "bool", "default": "false" },
{ "name": "line_items", "type": "json" }
],
"access": [
{ "passkey_id": "profile_1001", "can_read": true, "can_write": true },
{ "passkey_id": "profile_1002", "can_read": true }
]
}'
Peeche Postgres me ye chalta hai:
CREATE TABLE sec_invoices (
record_id BIGSERIAL PRIMARY KEY,
invoice_no TEXT NOT NULL,
client_name TEXT,
amount DOUBLE PRECISION NOT NULL,
status TEXT DEFAULT 'draft' CONSTRAINT ck_sec_invoices_p3
CHECK (status IN ('draft','sent','paid')),
due_date DATE,
paid BOOLEAN DEFAULT FALSE,
line_items JSONB,
created_by TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
ALTER TABLE sec_invoices ADD CONSTRAINT uq_sec_invoices_p0 UNIQUE (invoice_no);
CREATE INDEX ix_sec_invoices_p1 ON sec_invoices (client_name);
GET /api/sections โ sab sections
Har section ke saath uske fields, access grants aur record count.
GET /api/sections/:slug
PATCH /api/sections/:slug โ label / description
DELETE /api/sections/:slug?confirm=:slug
DROP TABLE karta hai โ section ka saara data chala jaata hai.
Isliye confirm me slug dobara bhejna padta hai, warna 400.
POST /api/sections/:slug/fields โ naya field
curl -X POST .../api/sections/invoices/fields \
-H "x-passkey: $ADMIN" -H "content-type: application/json" \
-d '{ "name": "notes", "type": "text", "label": "Internal notes" }'
ALTER TABLE โฆ ADD COLUMN chalta hai, aur field turant usable ho jaata hai.
required hai to default dena
zaroori hai โ warna purani rows ka wo column khaali reh jaata aur NOT NULL lag hi nahi sakta.
Bina default bhejne par saaf 400 milta hai.
PATCH /api/sections/:slug/fields/:name
label, required, unique, indexed,
default aur options (enum ke choices) badal sakte ho.
Type badalna support nahi hai โ uske liye field delete karke naye type se banao.
DELETE /api/sections/:slug/fields/:name
DROP COLUMN โ us column ka data chala jaata hai. Aakhri field delete nahi ho sakta.
Access grants admin only
GET /api/sections/:slug/access
PUT /api/sections/:slug/access โ grant set / update
Upsert hai โ key pehle se ho to uske flags badal jaate hain, warna naya grant ban jaata hai.
curl -X PUT .../api/sections/invoices/access \
-H "x-passkey: $ADMIN" -H "content-type: application/json" -d '{
"access": [
{ "passkey_id": "profile_1001", "can_read": true, "can_write": true, "can_delete": true },
{ "passkey_id": "profile_1003", "can_read": true }
]
}'
Koi flag na do to sirf can_read โ default hamesha sabse kam permission.
DELETE /api/sections/:slug/access/:passkey_id
GET /api/sections/status
Postgres zinda hai ya nahi, kaun sa database, kitne sections/fields/grants.
Section ka data jis key ko access ho
Ye endpoints admin-only nahi hain. Koi bhi valid passkey chalti hai โ bas us section par
uska grant hona chahiye. Grant na ho to 403, permission na ho to bhi 403.
GET /api/data/:slug/schema โ pehle yahi dekho
Client ko bataata hai ki is section me kaun se fields hain, kis type ke, kya required hai, aur meri key kya kar sakti hai. Isse client bina docs padhe form bana sakta hai.
curl -H "x-passkey: $CLIENT" .../api/data/invoices/schema
GET /api/data/:slug โ list
Response top level par hai (data me lipta hua nahi):
{ "ok": true, "section": "invoices", "total": 42, "limit": 50, "offset": 0,
"rows": [ { "record_id": 1, "invoice_no": "INV-001", ... } ] }
Filters query string me โ field ka naam + optional operator suffix:
| Query | Matlab |
|---|---|
| ?status=paid | barabar |
| ?status__ne=draft | barabar nahi |
| ?amount__gt= __gte= __lt= __lte= | bada / chhota |
| ?client_name__like=acme | case-insensitive match (% khud lag jaata hai) |
| ?status__in=sent,paid | in me se koi ek |
| ?due_date__null=1 | khaali hai (=0 se ulta) |
| ?q=acme | saare text/enum/uuid fields me search |
| ?sort=amount&order=desc | sort โ default record_id desc |
| ?limit=50&offset=0 | paging โ max limit 500 |
Anjaan field par filter lagane par 404 milta hai โ chup-chaap ignore nahi hota.
POST /api/data/:slug โ naya record
curl -X POST .../api/data/invoices \
-H "x-passkey: $CLIENT" -H "content-type: application/json" -d '{
"invoice_no": "INV-2026-001",
"client_name": "Acme Corp",
"amount": 48500.75,
"status": "sent",
"due_date": "2026-09-15",
"line_items": [ { "desc": "design", "qty": 2 } ]
}'
created_by me calling passkey ki id apne aap chali jaati hai.
Fields ko {"data": { โฆ }} me lapet ke bhi bhej sakte ho โ dono chalega.
amont)
uspe 400 milta hai, taki tumhe na lage ki value save ho gayi.
GET /api/data/:slug/:record_id
PATCH /api/data/:slug/:record_id โ partial update
Jo fields bhejo wahi badalte hain, baaki waise hi rehte hain. Optional field ko
null bhej ke khaali kar sakte ho; required field null par 400.
DELETE /api/data/:slug/:record_id
can_delete chahiye.
GET /api/my-sections
Meri key kaun se sections use kar sakti hai, kis permission ke saath. Admin ko sab dikhte hain.
GET /api/types
Saare field types ki live list.
Analytics actions
Har event ka action in me se ek hota hai:
| Action | Matlab |
|---|---|
| rate.list | Poori list maangi |
| rate.get | Kisi month ka rate padha |
| rate.history | Ek profile ke saare periods maange |
| rate.create | Naya period bana |
| rate.update | Period ka rate ya range badli |
| rate.delete | Ek period delete hua |
| auth.missing | Passkey bheji hi nahi |
| auth.invalid | Passkey table me nahi hai |
| auth.disabled | Key disabled hai |
| auth.forbidden | Admin endpoint, normal key se |
| ip.blocked | IP allowlist me nahi (allowlist on hone par hi aata hai) |
| route.missing | Aisa koi endpoint nahi |
| key.create / key.update / key.delete | Admin ne keys chhedin |
| key.list | Admin ne saari keys maangi โ sirf fail hone par log hota hai |
| auth.me | /api/me hit hua โ sirf fail hone par log hota hai |
| rate.readonly | own key ne rate badalne ki koshish ki |
| key.lookup | Kisi ne check kiya ki us user ki key hai ya nahi |
| key.register | User ne khud self-service key banayi |
| signup.disabled | SIGNUP_SECRET server par set hi nahi hai |
| signup.forbidden | Signup secret galat ya bheja hi nahi |
Dynamic sections ke actions
| Action | Matlab |
|---|---|
| section.create / section.update / section.delete | Section bana / badla / gaya |
| section.list / section.get | Schema padha gaya |
| field.create / field.update / field.delete | Field add / patch / drop hua |
| access.set / access.revoke / access.list | Grants chhede gaye |
| data.list / data.get | Section ka data padha |
| data.create / data.update / data.delete | Record bana / badla / gaya |
| data.schema | Client ne section ka schema maanga |
| dyn.forbidden | Key valid thi par us section pe permission nahi |
| dyn.unconfigured | PG_URL set hi nahi hai |
| dyn.unavailable | Postgres se connect nahi hua |
| dyn.types / dyn.status / dyn.mine | Field types, PG health, meri sections list |
target_id section ka slug hota hai (rates me profile id hota hai).
Isliye dashboard ke "Top profiles" table me dono mil ke dikh sakte hain.
Tables
rates -- ek profile ke kai rows (rate history)
rate_id INTEGER PRIMARY KEY -- har period ka apna id, server banata hai
id TEXT -- profile id, caller deta hai (repeat hota hai)
owner_id TEXT -> passkeys.id -- AUDIT: kis key ne banaya (visibility isse tay nahi hoti)
name TEXT
rate REAL
effective_from TEXT -- YYYY-MM, is month se lagu
effective_to TEXT -- YYYY-MM, is month tak (NULL = open-ended)
created_at TEXT
updated_at TEXT
passkeys
id TEXT PRIMARY KEY -- profile id, caller deta hai
passkey TEXT UNIQUE -- secret
label TEXT
is_admin INTEGER
scope TEXT -- 'all' = saare rates + write | 'own' = sirf apni id ke rates, read-only
active INTEGER
created_at TEXT
analytics
id INTEGER PRIMARY KEY -- log row counter
passkey_id TEXT -> passkeys.id
passkey TEXT -- masked
label TEXT
action TEXT
method TEXT
path TEXT
target_id TEXT -- kis rate pe
status INTEGER
ok INTEGER
duration_ms INTEGER
ip TEXT
user_agent TEXT
payload TEXT -- secrets masked
error TEXT
created_at TEXT
Postgres โ dynamic sections (alag database)
dyn_sections -- ek row = ek section
section_id BIGSERIAL PRIMARY KEY
slug TEXT UNIQUE -- api me yahi dikhta hai
table_name TEXT UNIQUE -- sec_<slug>
label TEXT
description TEXT
created_by TEXT -- kis passkey ne banaya
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ
dyn_fields -- section ka schema; DDL isi se banta hai
field_id BIGSERIAL PRIMARY KEY
section_id BIGINT -> dyn_sections.section_id (ON DELETE CASCADE)
name TEXT -- asli column ka naam
label TEXT
type TEXT -- text | number | int | bool | date |
-- datetime | json | uuid | enum
required BOOLEAN -- NOT NULL
is_unique BOOLEAN -- UNIQUE constraint
indexed BOOLEAN -- index
default_value TEXT -- DEFAULT (type se validate hota hai)
options JSONB -- enum choices, text max_length
position INTEGER -- constraint naam isi se bante hain, reuse nahi hote
UNIQUE (section_id, name)
dyn_access -- kaun si key, kaunsa section, kya kar sakti hai
section_id BIGINT -> dyn_sections.section_id (ON DELETE CASCADE)
passkey_id TEXT -- SQLite ki passkeys.id -- doosra db, isliye FK nahi
can_read BOOLEAN
can_write BOOLEAN
can_delete BOOLEAN
granted_by TEXT
PRIMARY KEY (section_id, passkey_id) -- ek section, kitni bhi keys
sec_<slug> -- har section ki apni table
record_id BIGSERIAL PRIMARY KEY
<tumhare fields> -- dyn_fields se generate
created_by TEXT -- kis passkey ne banaya
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ