הבעיה: שילוב amoCRM עם אפליקציה ניידת
כל פרויקט שילוב נייד של amoCRM נתקל באותה בעיה: זרימת OAuth קשורה לתת-הדומיין של החשבון. אם לא שומרים את subdomain עם הטוקנים, שחזור סשן לאחר התקנה מחדש של האפליקציה הופך לסיוט. לקוחות מקבלים באופן קבוע שגיאות 401 לאחר רענון טוקנים כי הם עושים שימוש חוזר ב-refresh_token הישן. אנחנו פותרים זאת על ידי שמירת כל refresh_token חדש מיד לאחר ההחלפה ושימוש באחסון מאובטח — Keychain ב-iOS ו-EncryptedSharedPreferences באנדרואיד. במשך למעלה מ-5 שנים, השלמנו למעלה מ-30 שילובי CRM, כל אחד דורש גישה מותאמת אישית ל-OAuth, פגינציית cursor, webhooks ורישום שיחות. אבטחה היא מעל הכל: כל התקשורת דרך HTTPS, טוקנים מוצפנים במכשיר, ו-webhooks מעובדים עם אספקה מובטחת דרך תורי הודעות.
OAuth 2.0 וריבוי חשבונות
amoCRM משתמש ב-OAuth 2.0 Authorization Code Flow עם טוויסט: כתובת ה-URL הבסיסית תלויה בתת-הדומיין של החשבון ({subdomain}.amocrm.ru). כדי לתמוך במספר חשבונות באפליקציה אחת, אנחנו מאחסנים את תת-הדומיין עם הטוקנים כשלישיית subdomain:access_token:refresh_token. זה מאפשר מעבר דינמי בין חשבונות ללא צורך באימות מחדש. החלפת קוד לטוקן:
POST https://{subdomain}.amocrm.ru/oauth2/access_token
{
"client_id": "...",
"client_secret": "...",
"grant_type": "authorization_code",
"code": "...",
"redirect_uri": "..."
}POST https://{subdomain}.amocrm.ru/oauth2/access_token { "client_id": "...", "client_secret": "...", "grant_type": "authorization_code", "code": "...", "redirect_uri": "..." } חי 24 שעות, access_token — 3 חודשים. amoCRM מבטל את ה-refresh_token בכל שימוש ומנפיק חדש — לכן קריטי לשמור את הטוקן החדש מיד. אם לא, האימות נכשל והמשתמש חייב להתחבר שוב.
איך לאחסן נכון refresh_token?
לאחר כל רענון מוצלח, אנחנו מיד מחליפים את צמד הטוקנים. אנחנו גם מוסיפים סנכרון עם שרת טוקנים — אם המכשיר נכשל, המשתמש יכול להתחבר מחדש ללא אובדן נתונים. אנו ממליצים לאחסן את חותמת הזמן של העדכון האחרון כדי להימנע מרענון יותר מפעם בשעה.
עבודה עם לידים ועסקאות
שליפת לידים עם פגינציית cursor:
suspend fun getLeads(cursor: String? = null): LeadsResponse {
return api.getLeads(
withQuery = mapOf(
"contacts" to listOf("contacts"),
"catalog_elements" to listOf("catalog_elements")
),
cursor = cursor,
limit = 50
)
}amoCRM מחזיר refresh_token עם כתובת URL מוכנה כולל ה-cursor. אין צורך לבנות כתובות URL ידנית — השתמשו בה ישירות. פגינציית cursor יעילה פי 10 לשליפת למעלה מ-5000 ישויות, מכיוון שהיא מונעת סריקות טבלה מלאות.
יצירת ליד המקושר לאיש קשר — שתי בקשות: suspend fun getLeads(cursor: String? = null): LeadsResponse { return api.getLeads( withQuery = mapOf( "contacts" to listOf("contacts"), "catalog_elements" to listOf("catalog_elements") ), cursor = cursor, limit = 50 ) } → _links.next.href עם מערך אנשי קשר. או השתמשו ביצירה מוטמעת: העבירו POST /api/v4/leads בגוף הליד — amoCRM יוצר ומקשר בבקשה אחת.
Webhooks: איך להבטיח אספקה
amoCRM webhook שולח POST לכתובת ה-URL שלך עם גוף POST /api/v4/leads/{id}/link (לא JSON). ניתוח בצד השרת:
app.post('/webhook/amo', express.urlencoded({ extended: true }), (req, res) => {
const event = req.body;
// event.leads.update[0].id - ID изменённой сделки
// event.leads.status_change[0].status_id - новый статус
res.sendStatus(200);
});amoCRM מצפה ל-_embedded.contacts תוך 10 שניות, אחרת הוא מחשיב את האספקה כנכשלת ומנסה שוב עם השהיה אקספוננציאלית. אל תבצעו פעולות כבדות ב-handler — קבלו, הכניסו לתור, החזירו 200. בפרויקטים שלנו, אנו משתמשים ב-RabbitMQ לעיבוד אסינכרוני. הרשמות לאירועים: לידים, אנשי קשר, משימות, שיחות — כל סוג מוגדר בנפרד.
טבלה 1. סוגי אירועים והרשמה
| סוג אירוע | הרשמה | פורמט נתונים |
|---|---|---|
| leads.create | כן | x-www-form-urlencoded |
| leads.update | כן | x-www-form-urlencoded |
| contacts.create | כן | x-www-form-urlencoded |
| contacts.update | כן | x-www-form-urlencoded |
| tasks.create | כן | x-www-form-urlencoded |
| calls.in | כן | x-www-form-urlencoded |
טבלה 2. השוואת שיטות פגינציה
| שיטה | מהירות ל-10,000 רשומות | מורכבות יישום |
|---|---|---|
| Cursor | ~0.5 שניות | בינונית |
| Offset | ~3 שניות | פשוטה |
| מבוססת עמודים | ~2 שניות | גבוהה |
טלפוניה ושיחות
amoCRM מתעד שיחות דרך x-www-form-urlencoded:
{
"direction": "outbound",
"duration": 125,
"source": "МоёПриложение",
"link": "https://...",
"phone": "+79001234567",
"call_result": "Успешно",
"call_status": 4,
"responsible_user_id": 123456,
"created_by": 123456
}app.post('/webhook/amo', express.urlencoded({ extended: true }), (req, res) => { const event = req.body; // event.leads.update[0].id - ID изменённой сделки // event.leads.status_change[0].status_id - новый статус res.sendStatus(200); }); : 1 — השאיר הודעה, 2 — יחזור, 3 — לא ענה, 4 — דיבר. לאחר שיחה מהאפליקציה הניידת, נוצר אוטומטית רשומה ב-amoCRM המקושרת לאיש הקשר לפי מספר טלפון.
איך עובד קישור שיחה לאיש קשר
amoCRM מוצא אוטומטית איש קשר לפי מספר הטלפון בשדה `phone`. אם לא נמצא איש קשר, נוצר חדש. מומלץ להעביר `responsible_user_id` — המשתמש האחראי שאליו תוקשר השיחה.מה כלול בעבודה
- תיעוד זרימת OAuth ל-iOS/Android (בהתחשב בהנחיות סקירת App Store סעיפים 4.2/5.1)
- תוכנית עיבוד Webhook עם תור הודעות
- קוד לדוגמה ב-Kotlin/Swift לעבודה עם עסקאות ואנשי קשר
- הוראות פרסום ל-App Store ו-Google Play (פרופיל provisioning, חתימת קוד, תעודות push)
- בדיקות על 5+ תרחישי כשל: פקיעת טוקן, חוסר זמינות שרת, webhooks כפולים
- אחריות על פעילות תקינה של השילוב למשך 3 חודשים לאחר המסירה
לוח זמנים
שילוב בסיסי (לידים, אנשי קשר, עסקאות, OAuth) עם פגינציה — 1 עד 2 שבועות. Webhooks, רישום שיחות, התראות push — בתוספת 3-5 ימים. העלות מחושבת באופן אישי לאחר הערכת היקף. התיעוד הרשמי של amoCRM מאשר את הגישה שלנו. צרו קשר — נכין הערכה ולוח זמנים לפרויקט שלכם. קבלו ייעוץ למשימה שלכם.
ניסיון ואחריות
אנחנו צוות פיתוח נייד עם 5 שנות ניסיון. השלמנו למעלה מ-30 שילובי CRM עם אפליקציות ב-iOS (Swift/SwiftUI) ואנדרואיד (Kotlin/Compose). עבדנו עם amoCRM מאז גרסה 4.0, אנחנו מכירים את כל המלכודות — מ-OAuth ועד פתרון קונפליקטים בכתיבה מקבילה. אנו מבטיחים עמידה בדרישות App Store ו-Google Play. באמצעות הפתרונות שלנו, לקוחות מפחיתים עלויות פיתוח ב-40% — חוסכים לפחות 100,000 RUB לפרויקט. בדיקות על 5+ תרחישי כשל מונעות הפסדים של עד 300,000 RUB מהשבתה.
למה פגינציית cursor עדיפה על offset? כי עם שינויים מקבילים בנתונים, offset מוביל לכפילויות או החמצות, בעוד cursor תמיד מצביע על המיקום המדויק.







