DILS SDK

מדריך אינטגרציה לשותפי TEKUNA / DILS

@tekuna/sdk-node — מדריך התחלה מהירה

English summary: Hebrew quickstart for the official @tekuna/sdk-node SDK. Install, provision a partner API key, mint your first DILS on Chain 2027, and call every module method. Scroll down for code samples.


1. מה זה ה-SDK?

@tekuna/sdk-node היא ספריית ה-Node.js הרשמית לאינטגרציה עם תשתית הסליקה הריבונית של TEKUNA / DILS. עם ה-SDK תוכל:

הכלל הבסיסי: 1 DILS = 1 ש"ח = 100 אגורות. כל הסכומים ב-SDK מועברים באגורות (שלמים) כדי למנוע בעיות עיגול.


2. דרישות


3. התקנה

npm install @tekuna/sdk-node

4. השגת מפתח API (provisioning)

מפתח השותף נוצר באמצעות בקשת POST ל-/api/sdk/provision עם פרטי KYB:

curl -X POST https://api.dils.co.il/api/sdk/provision \
  -H 'Content-Type: application/json' \
  -d '{
    "kyb": {
      "legalEntityId": "514123456",
      "name": "חברת הדגמה בע\"מ",
      "email": "ceo@demo.co.il",
      "address": "רוטשילד 1, תל אביב"
    },
    "tier": "starter",
    "chain": "testnet"
  }'

תשובה לדוגמה:

{
  "apiKey": "sk_test_dils_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "clubId": "uuid-…",
  "customerCardId": "uuid-…",
  "walletAddress": "0xabc…",
  "chain": "testnet",
  "tier": "starter",
  "modules": ["clubs", "payments"]
}

⚠️ שמור את ה-apiKey בצורה מאובטחת (Secret Manager / Vault). המערכת שומרת רק את ה-hash שלו; אין דרך לשחזר אותו.


5. הקוד הראשון — הנפקת DILS

import { Tekuna } from '@tekuna/sdk-node';

const tekuna = new Tekuna({
  apiKey: process.env.TEKUNA_API_KEY!,
});

const tx = await tekuna.dils.mint({ amount_agorot: 10000 });
//                                  ^^^^^^^^^^^^^^^^^^^^^^
//                                  100 ש"ח (10,000 אגורות)

console.log('Tx hash:', tx.tx_hash);
console.log('Chain:',   tx.chain_id);   // 2026 לסנדבוקס, 2027 לפרודקשן
console.log('Block:',   tx.block_number);

ה-tx_hash מוחזר זהו hash אמיתי על Chain 2027 (או 2026 בסנדבוקס) שניתן לאמת ב-RPC.


6. תיעוד מלא של המודולים

הקונסטרקטור:

const tekuna = new Tekuna({
  apiKey: 'sk_test_dils_…',     // חובה
  baseUrl: 'https://api.dils.co.il'  // אופציונלי; ברירת המחדל זו
});

tekuna.dils

mint({ amount_agorot, idempotency_key? })

הנפקת DILS לארנק מועדון השותף.

const tx = await tekuna.dils.mint({
  amount_agorot: 50000,            // 500 ש"ח
  idempotency_key: 'order-12345',  // אופציונלי, 24 שעות
});
// → { tx_hash, amount_agorot, amount_dils, chain_id, block_number, status }

תקרה: 10,000,000 אגורות (100,000 ש"ח) לכל קריאה.

tekuna.endUsers

list({ limit?, offset?, kyc_status? })

מחזיר את רשימת משתמשי הקצה השייכים לשותף המאומת.

const { users, total } = await tekuna.endUsers.list({
  limit: 100,
  offset: 0,
  kyc_status: 'verified',  // 'pending' | 'in_review' | 'verified' | 'rejected'
});
console.log(`${users.length} מתוך ${total} משתמשים`);

get(id)

מחזיר משתמש קצה יחיד לפי מזהה.

const user = await tekuna.endUsers.get('user-uuid');
// → { id, email, full_name, phone, wallet_address, kyc_status, kyc_level, created_at }

זורק TekunaApiError עם סטטוס 404 אם המשתמש לא קיים או לא שייך לשותף.

tekuna.wallet

balance()

תמונת מצב של יתרת DILS + TKN על השרשרת.

const bal = await tekuna.wallet.balance();
// → { club_id, wallet_address, dils_balance: "123.45",
//     dils_balance_agorot: 12345, tkn_balance: "0",
//     chain_id, block_number }

dils_balance_agorot הוא היחידה השלמה הקנונית — השתמש בו לחישובים פנימיים.

tekuna.transactions

list({ limit?, offset?, from_date?, to_date?, status? })

מחזיר את העסקאות של מועדון השותף, החדשות ביותר ראשונות.

const { transactions, total } = await tekuna.transactions.list({
  limit: 50,
  from_date: '2026-05-01T00:00:00Z',
  to_date:   '2026-05-25T00:00:00Z',
  status:    'confirmed',
});
for (const tx of transactions) {
  console.log(tx.tx_hash, tx.amount_dils, tx.snp_nature);
}

tekuna.auth

me()

זהות השותף המאומת.

const me = await tekuna.auth.me();
// → { club_id, club_name, wallet_address, tier, chain, modules, provisioned_at }
if (me.tier === 'starter') { /* … */ }

7. טיפול בשגיאות

כל קריאה זורקת TekunaApiError במקרה של תגובה שאינה 2xx (או שגיאת רשת לפני שהבקשה הגיעה לשרת):

import { Tekuna, TekunaApiError } from '@tekuna/sdk-node';

try {
  await tekuna.dils.mint({ amount_agorot: 10000 });
} catch (err) {
  if (err instanceof TekunaApiError) {
    console.error(`[${err.status}] ${err.code}: ${err.message}`);
    console.error('Raw body:', err.details);

    if (err.status === 401) {
      // מפתח לא תקין או שפג תוקפו → רענן מ-Secret Manager
    } else if (err.code === 'WALLET_NOT_DEPLOYED') {
      // הפרובוז'נינג לא הושלם → חכה או הרץ מחדש
    } else if (err.code === 'RPC_UNAVAILABLE') {
      // הרשת לא זמינה זמנית → נסה שוב עם backoff אקספוננציאלי
    }
  }
  throw err;
}

קודי שגיאה מרכזיים:

Code סטטוס משמעות
SDK_KEY_REQUIRED 401 חסר Authorization Bearer header
INVALID_SDK_KEY_FORMAT 401 פורמט מפתח לא תקין
SDK_KEY_INVALID 401 מפתח לא מוכר או שבוטל
INVALID_BODY 400 body לא עובר Zod validation בצד השרת
WALLET_NOT_DEPLOYED 409 ארנק המועדון עוד לא נפרס על השרשרת
CONTRACT_PAUSED 503 חוזה DILSMasterToken במצב pause
RPC_UNAVAILABLE 503 חיבור ל-Chain 2027/2026 נכשל זמנית
MINT_FAILED 500 טרנזקציית ה-mint נכשלה (revert, gas)
NETWORK_ERROR 0 שגיאת רשת לפני הגעה לשרת (DNS/socket)

8. סנדבוקס מול פרודקשן

סנדבוקס (testnet) פרודקשן (live)
תחילית המפתח sk_test_dils_… sk_live_dils_…
Chain ID 2026 2027
גישת RPC דרך ה-proxy המורשה בלבד: api.dils.co.il/api/rpc (14 מתודות מורשות). אין גישת RPC ישירה לשותפים.
DILS אמיתי? לא — בדיקה בלבד כן — 1:1 לש"ח
מקבל כסף אמיתי? לא כן — עם REGULATOR_ROLE

המעבר מסנדבוקס לפרודקשן דורש סבב אישור (KYB מלא + סקירת אבטחה). ה-SDK עצמו זהה — רק המפתח משתנה.


9. דוגמה מלאה — שילוב POS

תרחיש: עסק קולט תשלום של 49 ש"ח, מנפיק DILS למועדון, ושומר לקוח רישום עם SNP.

import { Tekuna, TekunaApiError } from '@tekuna/sdk-node';

const tekuna = new Tekuna({ apiKey: process.env.TEKUNA_API_KEY! });

async function settlePosCharge(orderId: string, ils: number, merchantId: string): Promise<string> {
  const amount_agorot = Math.round(ils * 100);

  try {
    const tx = await tekuna.dils.mint({
      amount_agorot,
      idempotency_key: `pos:${orderId}`,
    });

    console.log(`✓ Order ${orderId} settled: ${tx.tx_hash}`);
    return tx.tx_hash;

  } catch (err) {
    if (err instanceof TekunaApiError && err.code === 'WALLET_NOT_DEPLOYED') {
      throw new Error('המתן לסיום הפרוביז\'נינג של המועדון');
    }
    throw err;
  }
}

await settlePosCharge('ord-7891', 49.00, 'rest-001');

10. חיוב סוחר (מפתחות dils_) — מפתח + PIN לקוח + חיוב

English summary: A second, separate credential/route family from the SDK above — dils_test_… / dils_live_… keys (table tekuna_partner_api_keys), used to redeem a customer's 4-digit PIN and charge the customer's DILS balance to your merchant card. This is the real clearing path (used by ANIKAN/LiBi in production) — separate from sk_ above, which only mints DILS to your own club wallet.

⚠️ שני מערכי מפתחות נפרדים, אל תערבב ביניהם:

sk_ (סעיף 4 למעלה)dils_ (הסעיף הזה)
מטרההנפקת DILS לארנק המועדון שלךגביית תשלום מלקוח קצה לכרטיס הסוחר שלך
טבלהsdk_api_keystekuna_partner_api_keys
HeaderAuthorization: Bearer sk_…x-partner-api-key (או x-api-key, ראה 10.3)

10.1 קבלת מפתח dils_test_/dils_live_

מפתח סוחר מונפק דרך ops.dils.co.il (פאנל ה-Operator Portal, /sdk) לכרטיס העסק שלך, או ע"י super_admin. לא ניתן להנפיק אותו דרך /api/sdk/provision (זה מנפיק רק sk_). המפתח מוצג פעם אחת בלבד — שמור אותו מיד.

10.2 זרימת סנדבוקס — PIN + חיוב (מאומת חי, ₪100 נטענים אוטומטית)

כל הקריאות הבאות עם x-partner-api-key: dils_test_… אל https://api.dils.co.il/functions/partner-settlement-api:

שלב א — הלקוח (בעל הכרטיס) מייצר קוד בן 4 ספרות ומוסר לך אותו (במציאות — האפליקציה של הלקוח; בסנדבוקס אתה יכול לבחור קוד לצורך בדיקה):

curl -X POST https://api.dils.co.il/functions/partner-settlement-api/sandbox/create-session \
  -H 'x-partner-api-key: dils_test_XXXXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"amount": 25, "customer_card_id": "<כרטיס-הסוחר-שלך-uuid>", "pin_code": "1234"}'
# → 200 {"success":true,"pin_code":"1234","ttl_seconds":180,"expires_at":"…","amount":25,"customer_card_id":"…"}

שלב ב — בדוק יתרת סנדבוקס (נטענת אוטומטית ל-₪100 בקריאה הראשונה — אין צורך "להטעין" ידנית):

curl -X POST https://api.dils.co.il/functions/partner-settlement-api/sandbox/balance \
  -H 'x-partner-api-key: dils_test_XXXXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"customer_card_id": "<כרטיס-הסוחר-שלך-uuid>"}'
# → 200 {"success":true,"balance_credits":10000,"balance_ils":100}

שלב ג — בבית העסק: מימוש ה-PIN (נועל את הסכום)ה-PIN הוא כל מה שצריך:

curl -X POST https://api.dils.co.il/functions/partner-settlement-api/escrow \
  -H 'x-partner-api-key: dils_test_XXXXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"pin_code": "1234"}'
# → 200 {"success":true,"escrow_id":"esc_…","status":"HELD","amount_locked":2500,"available_balance":75}

הסכום והכרטיס נגזרים בשרת — הסכום מגיע מרשומת ה-PIN עצמה (הוא נקבע כשהקוד נוצר), והכרטיס נגזר מהמפתח שלך (או מ-terminal_id אם שלחת אחד). אינך צריך לשלוח אותם, וגם לא כל פרמטר אחר.

תאימות לאחור מלאה: אם האינטגרציה שלך כבר שולחת amount ו/או customer_card_id — הם עדיין מתקבלים ונבדקים מול רשומת ה-PIN, ואי-התאמה עדיין מוחזרת כ-AMOUNT_MISMATCH / CUSTOMER_CARD_MISMATCH בדיוק כמו קודם. שום אינטגרציה קיימת אינה נשברת; פשוט כבר אין חובה לשלוח אותם. גם terminal_id, channel ו-items נשארים אופציונליים.

אם השותף מחזיק יותר מכרטיס אחד ולא נשלח terminal_id, השרת לא מנחש — הוא מחזיר שגיאה מפורשת שמבקשת customer_card_id או terminal_id.

שלב ד — סיום החיוב (עם ה-escrow_id משלב ג׳):

curl -X POST https://api.dils.co.il/functions/partner-settlement-api/finalize-charge \
  -H 'x-partner-api-key: dils_test_XXXXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"escrow_id": "esc_…"}'

לביטול לפני סיום: POST /functions/partner-settlement-api/cancel עם אותו escrow_id. לאיפוס יתרת הסנדבוקס בחזרה ל-₪100: POST /functions/partner-settlement-api/sandbox/reset.

10.3 מסלול חלופי — /api/merchant/:card_id (אותו מפתח dils_, header שונה)

קיים גם endpoint סוחר נפרד (זה שבו ANIKAN/LiBi משתמשים בפרודקשן), עם x-api-keyלא x-partner-api-key:

curl https://api.dils.co.il/api/merchant/<כרטיס-הסוחר-שלך-uuid>/info \
  -H 'x-api-key: dils_test_XXXXXXXXXXXX'
# → 200 { id, business_name, card_status, environment, kyb_status,
#         merchant_payment_endpoint, payment_code_endpoint }

ה-payment_code_endpoint המוחזר (/api/user/generate-payment-code) הוא הדרך שבה הלקוח (לא הסוחר) מייצר קוד תשלום אמיתי מהאפליקציה שלו; ה-merchant_payment_endpoint (/api/merchant/:card_id/charge) הוא זה שהסוחר קורא לו עם הקוד כדי לגבות.

10.4 פרודקשן

אותם endpoints בדיוק, עם מפתח dils_live_… — הכרטיס שלך חייב להיות בסביבת PROD ו-KYB מאושר (נבדק אוטומטית בשרת). הבדל מהותי: אין "טעינה אוטומטית" — יתרת ה-DILS על הכרטיס בפרודקשן היא כסף אמיתי שמגיע מהלקוחות שמשלמים דרכך, לא מ-seed.

אין שום הבדל באימות בין סנדבוקס לפרודקשן: מפתח API בלבד. אין חתימת HMAC, אין secret נוסף, ואין header נוסף — בדיוק כמו בסנדבוקס. הקוד שעבד לך בסנדבוקס עובד בפרודקשן ללא שינוי; מחליפים את המפתח וזהו.

אם האינטגרציה שלך כבר שולחת header של חתימה (x-tekuna-signature) — היא ממשיכה לעבוד. חתימה תקינה מתקבלת; חתימה שגויה נדחית. פשוט אין יותר חובה לשלוח אחת.

10.5 בידוד סנדבוקס ↔ פרודקשן (חשוב)

לכל מפתח יש סביבה משלו הרשומה במסד הנתונים (לא נגזרת משם המפתח), ו-CHECK ברמת המסד מוודא שהסביבה הרשומה תואמת את המפתח עצמו. הגבול הוא המסלול:

מפתחמותרנחסם
dils_test_… (סנדבוקס)נתיבי /sandbox/* וטבלאות הסנדבוקס המבודדותמסלול הסליקה האמיתי
dils_live_… (פרודקשן)מסלול הסליקה האמיתינתיבי /sandbox/*

מותר ורצוי לבדוק בסנדבוקס כרטיס שכבר מוגדר PROD — זו בדיוק דרך ההצטרפות: בודקים עם מפתח סנדבוקס, מאשרים KYB, מעבירים את הכרטיס ל-PROD, מנפיקים מפתח פרודקשן, ומריצים את אותה קריאה בדיוק. מה שמבודד הוא המסלול והנתונים — לא הכרטיס.


11. Faucet קרדיטים לבדיקה — מימון עצמי של כרטיס סנדבוקס

English summary: A self-serve faucet for sandbox test credit — POST /api/client/faucet/claim and GET /api/client/faucet/status. Works with either key lane (sk_test_dils_… or dils_test_…). Grants 5 DILS by default (max 25/claim, 100/24h, 60s cooldown) into partner_sandbox_balances — sandbox only, is_real=false, never touches the real DILS supply or sovereign_ledger.

עד 02.08.2026, שותף שקיבל מפתח SDK דרך admin.dils.co.il/sdk לא היה יכול לקבל ולו DILS אחד לבדיקה — הפורטל הנפיק מפתח, הראה צעד "קריאה ראשונה", ואז ציפה מהשותף להריץ חיוב על כרטיס עם יתרה אפסית. הדרך היחידה שהייתה קיימת — POST /functions/partner-settlement-api/sandbox/reset — היא הרסנית: מאפסת את כל הכרטיסים תחת המפתח בחזרה ל-₪100 קבוע ומוחקת את כל ה-PINs וה-escrows של אותו מפתח. עכשיו יש faucet אמיתי.


11.1 מה מקבלים

קרדיטים לסליקת סנדבוקס על Chain 2026, נכתבים ל-partner_sandbox_balances — אותה יתרה בדיוק ש-POST /functions/partner-settlement-api/finalize-charge מחייב ממנה. זה מה שמאפשר לחיוב סנדבוקס מקצה-לקצה להצליח בפועל.

זה לא כסף אמיתי:

רשת2026 (סנדבוקס) — לעולם לא Chain 2027
is_realfalse, נאכף ע"י DB CHECK constraint, לא רק מוסכמה
נספר כהכנסה?לא
נוגע באספקת DILS / trust account?לא

קרדיט פרודקשן הוא כסף אמיתי מגובה בנק. הוא לעולם לא ניתן אוטומטית — ראה 11.6 למטה.


11.2 מדיניות

כללערך
הענקה כברירת מחדל5 DILS
מקסימום לקריאה25 DILS
מקסימום ל-24 שעות (per API key)100 DILS
Cooldown בין קריאות60 שניות
מפתחות זכאיםסנדבוקס בלבד (sk_test_dils_…, tk_test_…, dils_test_…)

אותה מדיניות מוחזרת גם ע"י GET /api/client/faucet/status, כך שהאינטגרציה שלך לא צריכה hard-code.


11.3 Endpoints

שני ה-endpoints מקבלים כל אחד ממערכי המפתחות — אין צורך לדעת איזו משתי מערכות המפתחות (סעיף 4 מול סעיף 10 למעלה) הנפיקה את המפתח שלך:

POST /api/client/faucet/claim

curl -X POST https://api.dils.co.il/api/client/faucet/claim \
  -H "Authorization: Bearer $DILS_SANDBOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount_dils": 5 }'

amount_dils אופציונלי (ברירת מחדל 5). customer_card_id אופציונלי אם המפתח שלך משויך לכרטיס יחיד, וחובה אם לא.

{
  "success": true,
  "granted_dils": 5,
  "customer_card_id": "00000000-0000-0000-0000-000000000000",
  "balance_before_dils": 0,
  "balance_dils": 5,
  "network": 2026,
  "environment": "sandbox",
  "is_real": false,
  "allowance": { "remaining_24h_dils": 95, "cooldown_seconds": 60 },
  "request_id": "…"
}

GET /api/client/faucet/status

curl https://api.dils.co.il/api/client/faucet/status \
  -H "Authorization: Bearer $DILS_SANDBOX_KEY"

מחזיר זכאות, את המדיניות המלאה, כמה המפתח הזה כבר משך ב-24 השעות האחרונות, כמה שניות נשארו ל-cooldown, ואת יתרת הסנדבוקס הנוכחית של כל כרטיס תחת המפתח.


11.4 שגיאות

HTTPerrorמשמעות
401API_KEY_REQUIREDאין מפתח, או מפתח שאיננו מזהים.
403PRODUCTION_KEY_NOT_ELIGIBLEשלחת מפתח פרודקשן. ה-faucet משרת סנדבוקס בלבד.
403CARD_NOT_IN_SCOPEהכרטיס הזה לא שלך. (בכוונה זהה בין אם הכרטיס קיים או לא — אין existence oracle.)
400CUSTOMER_CARD_REQUIREDהמפתח שלך מכסה יותר מכרטיס אחד; ציין איזה לזכות.
400INVALID_BODYamount_dils חסר, לא חיובי, או מעל 25.
429COOLDOWN_ACTIVEפחות מ-60 שניות מהקריאה האחרונה — retry_after_seconds אומר כמה זמן.
429DAILY_LIMIT_REACHEDהמפתח הזה משך את ה-100 DILS שלו ל-24 השעות המתגלגלות.

11.5 מעגל בדיקה מלא (סנדבוקס)

export BASE=https://api.dils.co.il
export KEY=sk_test_dils_…          # מ-biz.dils.co.il/sdk
export CARD=…                      # ה-Customer Card ID שלך

# 1. וידוא שהמפתח עובד
curl -s $BASE/api/client/status -H "Authorization: Bearer $KEY"

# 2. מימון כרטיס הסנדבוקס
curl -s -X POST $BASE/api/client/faucet/claim \
     -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
     -d '{"amount_dils": 5}'

# 3. בעל הכרטיס מייצר קוד 4 ספרות ב-iam.dils.co.il, ואז אתה מחייב אותו
curl -s -X POST $BASE/api/merchant/$CARD/charge \
     -H "x-api-key: $KEY" -H 'Content-Type: application/json' \
     -d '{"user_code": "1234", "amount_dils": 1.5}'

# 4. בדיקה מה נשאר
curl -s $BASE/api/client/faucet/status -H "Authorization: Bearer $KEY"

11.6 DILS על השרשרת בסנדבוקס (דבר אחר) וקבלת קרדיט פרודקשן

ה-faucet מעניק קרדיטי סליקה. אם אתה צריך ספציפית יתרת ERC-20 על השרשרת בסנדבוקס Chain 2026, זה POST /api/client/dils/mint עם מפתח testnet — הוא מנפיק לארנק המועדון שלך על השרשרת. החל מ-02.08.2026 ה-route הזה דוחה מפתחות פרודקשן (403 PRODUCTION_MINT_NOT_SELF_SERVE) — הנפקת DILS אמיתי על Chain 2027 היא פעולת Treasury מדרגה 3 (Tier-3) ולעולם לא קורית דרך מפתח API.

קרדיט פרודקשן הוא DILS אמיתי מגובה 1:1 בשקלים אמיתיים המוחזקים ב-trust. הוא מונפק רק דרך תהליך treasury מאושר אנושית:

  1. השלמת KYB (biz.dils.co.ilאימות עסקי · KYB).
  2. בקשת מפתח פרודקשן דרך ה-Operator Portal — מפתחות פרודקשן אינם self-serve.
  3. מימון הכרטיס דרך חשבון ה-trust; מנהל החשבון שלך מבצע את ההנפקה.

יומן ביקורת: כל בקשת claim כותבת שורה append-only אחת ל-public.sdk_faucet_disbursements (network=2026, environment='sandbox', is_real=false — נאכף ב-CHECK), ושורת sdk.faucet.claim אחת ליומן ביקורת האבטחה. שום דבר לא נכתב ל-sovereign_ledger — קרדיט בדיקה לעולם לא נכנס לספר האמיתי (Iron Rule #2).


12. סופ"ש מצוין

תיעוד מלא של ה-REST API: https://api.dils.co.il/health (מחזיר 200 + מטא-דאטה). לתמיכה: support@dils.co.il. לבעיות באבטחה (הסביבה בהתאמה ל-SOC 2 ולדרישות NIMBUS 01-2022; אין היום תעודת הסמכה בתוקף): security@dils.co.il.


עודכן: 2026-08-20 · גרסת SDK: 0.1.0 · בהתאמה ל-NIMBUS 01-2022 · me-west1