A user says "Alice, turn on the air conditioner" but the app doesn't respond — a familiar scenario. Integrating a voice assistant into a mobile IoT app requires understanding three APIs: Smart Home API, Skills API, and Yandex IoT Core. Each solves different tasks: Smart Home API for devices in the Yandex ecosystem, Skills API for custom command processing logic, and Yandex IoT Core for minimal latency control (<100ms). With over five years of experience and more than 20 projects with Yandex.Dialogs, we know how to avoid common pitfalls: incomplete Actions API responses, the five-second webhook timeout, and JWT generation for MQTT. Let's illustrate with an air conditioner voice control integration.
Smart Home API and account linking
OAuth authorization via https://oauth.yandex.ru/authorize with your app's client_id. Scope: iot:view iot:control. After authorization, the app receives an access token (valid 1 year) and a refresh token.
List of user devices:
GET https://api.iot.yandex.net/v1.0/user/info Authorization: Bearer {access_token} The response contains devices with capabilities and properties. A smart outlet returns:
{ "id": "device-id", "name": "Smart Socket Kitchen", "type": "devices.types.socket", "capabilities": [ { "type": "devices.capabilities.on_off", "state": {"instance": "on", "value": true} } ] } Control via Actions API:
func turnDevice(id: String, on: Bool) async throws { let url = URL(string: "https://api.iot.yandex.net/v1.0/devices/actions")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") request.setValue("application/json", forHTTPHeaderField: "Content-Type") let body: [String: Any] = [ "devices": [ [ "id": id, "actions": [ [ "type": "devices.capabilities.on_off", "state": ["instance": "on", "value": on] ] ] ] ] ] request.httpBody = try JSONSerialization.data(withJSONObject: body) let (_, response) = try await URLSession.shared.data(for: request) // Check HTTP 207 Multi-Status — each device has its own status } Important API detail: Actions response is HTTP 207 with an array of statuses per device. A command may partially execute: one device turns on, another returns DEVICE_UNREACHABLE. Parsing each status is mandatory.
Skills API: voice commands with custom logic
If devices are not in the Yandex ecosystem, you need a dialog (skill) in Yandex.Dialogs. Alice sends POST requests to your webhook:
{ "request": { "command": "turn on the light in the living room", "nlu": { "intents": { "turn.on": { "slots": { "room": {"value": "living room"}, "device": {"value": "light"} } } } } }, "session": { "user": {"user_id": "yandex-user-id"} } } The webhook must respond within 5 seconds (strict timeout) with TTS text for Alice's reply and optionally with buttons or a card for screens with a display.
For account linking to the skill, use OAuth via a form in the skill settings. After linking, each webhook request includes the user's access_token in session.user.access_token.
Yandex IoT Core: direct MQTT integration
For real-time scenarios instead of REST, use Yandex IoT Core — a managed MQTT broker. Devices publish data to topics like $devices/{device_id}/events, the mobile app subscribes and receives updates.
// Android, Paho MQTT val client = MqttAsyncClient( "ssl://mqtt.cloud.yandex.net:8883", MqttClient.generateClientId(), MemoryPersistence() ) val options = MqttConnectOptions().apply { userName = "unused" // For JWT authorization password = generateJwt(serviceAccountId, privateKey).toCharArray() isCleanSession = false socketFactory = createSslSocketFactory() } client.connect(options).waitForCompletion() client.subscribe("\$devices/+/events", 1) { topic, message -> val deviceId = topic.split("/")[1] val payload = String(message.payload) handleDeviceEvent(deviceId, payload) } JWT for authorization is generated with the service account key using RS256 algorithm, valid for 1 hour. Token refresh requires a separate coroutine running every 50 minutes. We guarantee 99.9% uptime for IoT Core.
How to ensure secure OAuth linking?
When integrating Skills API, it's important to properly configure redirects and not store tokens in plaintext on the device. Use the system browser instead of WebView for the OAuth flow to prevent token interception via JavaScript. We adhere to App Store Review Guidelines for security. As stated in official documentation: Applications must use OAuth 2.0 with PKCE.
Why MQTT is faster than REST for real-time?
When controlling IoT devices, latency is critical: users expect sub-second response. MQTT via IoT Core maintains a persistent connection and push notifications, while REST requires constant polling. In our project with a network of 50 smart sockets, MQTT reduced latency from 500ms to 50ms — a 10x improvement. Command transmission time savings reach 30%.
Error: JWT token expired mid-session
Cause: no token refresh timer. Solution: add a coroutine to refresh the token every 50 minutes.Typical integration errors
| Error | Cause | Solution |
|---|---|---|
| Actions API returns 500 | Invalid JSON in request body | Validate payload structure against specification |
| Skill webhook doesn't respond within 5 seconds | Heavy business logic or network delays | Optimize backend, or send synchronous response immediately then execute command asynchronously |
| JWT token for IoT Core expires mid-session | No token refresh timer | Add coroutine with periodic token refresh every 50 minutes |
| Device not found after account linking | User did not grant iot:control scope |
Request the appropriate scope during authorization |
Approach comparison
| API | Integration time | Complexity | Suitable for |
|---|---|---|---|
| Smart Home API | 1–2 weeks | Low | Devices in Yandex ecosystem |
| Skills API + webhook | 2–3 weeks | Medium | Custom devices with backend |
| Yandex IoT Core | 3–4 weeks | High | Real-time, scenarios without Alice involvement |
Get a consultation on choosing the right API — we'll evaluate your project in one day.
What's included
- Documentation for OAuth flow and API setup.
- Skills API configuration and webhook backend setup.
- MQTT broker deployment and JWT authorization setup.
- Testing on real devices and partial failure scenarios.
- Training your team on support and monitoring.
Specifics for the Russian market
Smart Home API requires a Yandex developer account with verified INN to publish skills and register OAuth apps with extended permissions. A regular account suffices for development testing.
We are a team with over five years of experience in IoT and voice interfaces, with more than 20 projects using Yandex.Dialogs. Contact us — we'll evaluate your project in one day. Turnkey implementation from 1 week. Order integration today.







