Integrating amoCRM with Mobile Apps: OAuth 2.0, Webhooks, and Call Logging

The Problem: Integrating amoCRM with a Mobile App Every amoCRM mobile integration project hits the same snag: the OAuth flow is tied to the account subdomain. If you don't save the `subdomain` with the tokens, restoring a session after app reinstallation becomes a nightmare. Clients regularly get

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Integrating amoCRM with Mobile Apps: OAuth 2.0, Webhooks, and Call Logging
Medium
~3-5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    897
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    598

The Problem: Integrating amoCRM with a Mobile App

Every amoCRM mobile integration project hits the same snag: the OAuth flow is tied to the account subdomain. If you don't save the subdomain with the tokens, restoring a session after app reinstallation becomes a nightmare. Clients regularly get 401 errors after refreshing tokens because they reuse the old refresh_token. We solve this by saving every new refresh_token immediately after exchange and using a secure storage — Keychain on iOS and EncryptedSharedPreferences on Android. Over 5 years, we’ve completed 30+ CRM integrations, each requiring a custom approach to OAuth, cursor pagination, webhooks, and call logging. Security is paramount: all communication via HTTPS, tokens encrypted on device, and webhooks processed with guaranteed delivery through message queues.

OAuth 2.0 and Multi-Account

amoCRM uses OAuth 2.0 Authorization Code Flow with a twist: the base URL depends on the account subdomain ({subdomain}.amocrm.ru). To support multiple accounts in one app, we store the subdomain with tokens as a subdomain:access_token:refresh_token triplet. This allows dynamic account switching without re-authorization. Code-to-token exchange:

POST https://{subdomain}.amocrm.ru/oauth2/access_token { "client_id": "...", "client_secret": "...", "grant_type": "authorization_code", "code": "...", "redirect_uri": "..." } 

access_token lives 24 hours, refresh_token — 3 months. amoCRM invalidates the refresh_token on each use and issues a new one — so it's critical to save the fresh token immediately. If not, authorization fails and the user must log in again.

How to Properly Store refresh_token?

After each successful refresh, we immediately overwrite the token pair. We also add sync with a token server — if the device fails, the user can re-login without data loss. We recommend storing the last update timestamp to avoid refreshing more than once per hour.

Working with Leads and Deals

Fetching leads with cursor pagination:

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 returns _links.next.href with a ready URL including the cursor. No need to build URLs manually — use it directly. Cursor pagination is 10x more efficient for fetching over 5000 entities, as it avoids full table scans.

Creating a lead linked to a contact — two requests: POST /api/v4/leadsPOST /api/v4/leads/{id}/link with a contacts array. Or use embedded creation: pass _embedded.contacts in the lead body — amoCRM creates and links in one request.

Webhooks: How to Guarantee Delivery

amoCRM webhook sends a POST to your URL with x-www-form-urlencoded body (not JSON). Server-side parsing:

app.post('/webhook/amo', express.urlencoded({ extended: true }), (req, res) => { const event = req.body; // event.leads.update[0].id - ID of changed deal // event.leads.status_change[0].status_id - new status res.sendStatus(200); }); 

amoCRM expects 200 OK within 10 seconds, otherwise considers delivery failed and retries with exponential backoff. Don't perform heavy operations in the handler — accept, queue, return 200. In our projects, we use RabbitMQ for async processing. Event subscriptions: leads, contacts, tasks, calls — each type is configured separately.

Table 1. Event Types and Subscription

Event Type Subscription Data Format
leads.create yes x-www-form-urlencoded
leads.update yes x-www-form-urlencoded
contacts.create yes x-www-form-urlencoded
contacts.update yes x-www-form-urlencoded
tasks.create yes x-www-form-urlencoded
calls.in yes x-www-form-urlencoded

Table 2. Pagination Method Comparison

Method Speed for 10k records Implementation Complexity
Cursor ~0.5 sec Medium
Offset ~3 sec Simple
Page-based ~2 sec High

Telephony and Calls

amoCRM logs calls via POST /api/v4/calls:

{ "direction": "outbound", "duration": 125, "source": "MyApp", "link": "https://...", "phone": "+79001234567", "call_result": "Successful", "call_status": 4, "responsible_user_id": 123456, "created_by": 123456 } 

call_status: 1 — left message, 2 — will call back, 3 — no answer, 4 — spoke. After a call from the mobile app, a record is automatically created in amoCRM linked to the contact by phone number.

How call-to-contact linking works amoCRM automatically finds a contact by the phone number in the `phone` field. If no contact is found, a new one is created. It is recommended to pass `responsible_user_id` — the responsible user to whom the call will be linked.

What's Included in the Work

  • OAuth flow documentation for iOS/Android (considering App Store Review Guidelines Section 4.2/5.1)
  • Webhook processing scheme with message queue
  • Sample code in Kotlin/Swift for working with deals and contacts
  • Publishing instructions for App Store and Google Play (provisioning profile, code signing, push certificates)
  • Testing on 5+ failure scenarios: token expiration, server unavailability, duplicate webhooks
  • Guarantee on correct integration operation for 3 months after delivery

Timeline

Basic integration (leads, contacts, deals, OAuth) with pagination — 1 to 2 weeks. Webhooks, call logging, push notifications — plus 3-5 days. Cost is calculated individually after scope assessment. Official amoCRM documentation confirms our approach. Contact us — we'll prepare an estimate and timeline for your project. Get a consultation for your task.

Experience and Guarantees

We are a mobile development team with 5 years of experience. We've completed over 30 CRM integrations with apps on iOS (Swift/SwiftUI) and Android (Kotlin/Compose). We've worked with amoCRM since version 4.0, know all the pitfalls — from OAuth to conflict resolution in parallel writes. We guarantee compliance with App Store and Google Play requirements. Through our solutions, clients reduce development costs by 40% — saving at least 100,000 RUB per project. Testing on 5+ failure scenarios prevents losses of up to 300,000 RUB from downtime.

Why is cursor pagination better than offset? Because with parallel data changes, offset leads to duplicates or misses, while cursor always points to the exact position.