# Device Change Event

By using this interface, you can subscribe to receive notifications of device management change records, including event notifications when new devices are added, devices are deleted, device ownership changes, trusted status changes, and device features such as production serial numbers and hard disk serial numbers change{Usage Examples}(url=/api/tools/api_explore/api_explore_config?project=security_and_compliance&version=v2&resource=device_record&event=device_change_event)

## Event

Facts | &nbsp;
---|---
Event type | security_and_compliance.device_record.device_change_event_v2
Supported app types | Custom App、Store App
Required scopes<br>**To subscribe to this event, enable any of the listed scopes.** | Retrieve device information(security_and_compliance:device_record:read)
Required field scopes | **Notice**：The response body of the API contains the following sensitive fields, and they will be returned only after corresponding scopes are added. If you do not need the fields, it is not recommended that you request the scopes.<br>Obtain user ID(contact:user.employee_id:readonly)
Push Mode | [Webhook](https://open.feishu.cn/document/ukTMukTMukTM/uUTNz4SN1MjL1UzM)

### Event body

Parameter | Type | Description
---|---|---
schema | string | Event schema
header | event_header | Event header
event_id | string | Event ID
event_type | string | Event type
create_time | string | Event creation timestamp(in ms)
token | string | Event token
app_id | string | App ID
tenant_key | string | Tenant key
event | \- | \-
device_record_id | string | Device verification code
version | string | Version
change_type | int | Change type<br>**Optional values are**:<br>- 1：Insert<br>- 2：Update<br>- 3：Delete
before | device_change_event | Previous Data
device_record_id | string | Device verification code
version | string | Version
current_user_id | user_id | Current logged-in user ID
union_id | string | User's union_id
user_id | string | user's user id<br>**Required field scopes**:<br>Obtain user ID(contact:user.employee_id:readonly)
open_id | string | User's open_id
device_name | string | Device name
model | string | Device model
device_system | int | Operate system<br>**Optional values are**:<br>- 1：Windows<br>- 2：macOS<br>- 3：Linux<br>- 4：Android<br>- 5：iOS<br>- 6：OpenHarmony
serial_number | string | Serial number
disk_serial_number | string | Disk serial number
uuid | string | Mother board UUID
mac_address | string | MAC Address
android_id | string | Android identifier
idfv | string | iOS vendor identifier
aaid | string | Harmony vendor identifier
device_ownership | int | Device ownership<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Personal<br>- 2：Company
device_status | int | Trusted status<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Trusted<br>- 2：Untrusted
certification_level | int | Certification level<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Lark<br>- 2：MDM
device_terminal_type | int | Terminal type<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Mobile<br>- 2：PC
is_managed | boolean | Is managed device or not
mdm_device_id | string | MDM device ID
mdm_provider_name | string | MDM provider name
device_env_detect_status | int | Device Environment Detection Status<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Safe<br>- 2：Unsafe
is_public | boolean | Is public device or not<br>**Default value**: `false`
after | device_change_event | Current data
device_record_id | string | Device verification code
version | string | Version
current_user_id | user_id | Current logged-in user ID
union_id | string | User's union_id
user_id | string | user's user id<br>**Required field scopes**:<br>Obtain user ID(contact:user.employee_id:readonly)
open_id | string | User's open_id
device_name | string | Device name
model | string | Device model
device_system | int | Operate system<br>**Optional values are**:<br>- 1：Windows<br>- 2：macOS<br>- 3：Linux<br>- 4：Android<br>- 5：iOS<br>- 6：OpenHarmony
serial_number | string | Serial number
disk_serial_number | string | Disk serial number
uuid | string | Mother board UUID
mac_address | string | MAC Address
android_id | string | Android identifier
idfv | string | iOS vendor identifier
aaid | string | Harmony vendor identifier
device_ownership | int | Device ownership<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Personal<br>- 2：Company
device_status | int | Trusted status<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Trusted<br>- 2：Untrusted
certification_level | int | Certification level<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Lark<br>- 2：MDM
device_terminal_type | int | Terminal type<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Mobile<br>- 2：PC
is_managed | boolean | Is managed device or not
mdm_device_id | string | MDM device ID
mdm_provider_name | string | MDM provider name
device_env_detect_status | int | Device Environment Detection Status<br>**Optional values are**:<br>- 0：Unknown<br>- 1：Safe<br>- 2：Unsafe
is_public | boolean | Is public device or not<br>**Default value**: `false`

### Event body example
```json
{
    "schema": "2.0",
    "header": {
        "event_id": "5e3702a84e847582be8db7fb73283c02",
        "event_type": "security_and_compliance.device_record.device_change_event_v2",
        "create_time": "1608725989000",
        "token": "rvaYgkND1GOiu5MM0E1rncYC6PLtF7JV",
        "app_id": "cli_9f5343c580712544",
        "tenant_key": "2ca1d211f64f6438"
    },
    "event": {
        "device_record_id": "7089353870308032531",
        "version": "0",
        "change_type": 1,
        "before": {
            "device_record_id": "7089353870308032531",
            "version": "0",
            "current_user_id": {
                "union_id": "on_8ed6aa67826108097d9ee143816345",
                "user_id": "e33ggbyz",
                "open_id": "ou_84aad35d084aa403a838cf73ee18467"
            },
            "device_name": "Q9C6RYMFDK",
            "model": "iPhone13,2",
            "device_system": 0,
            "serial_number": "C02DTHRMML7H",
            "disk_serial_number": "CC344362-5990-5A68-8DDD-64A23C99FA0C",
            "uuid": "621CDFF0-13D0-5AB1-9ADC-5F560095F6ED",
            "mac_address": "ac:de:48:00:11:21",
            "android_id": "02a11ac4a83b918e",
            "idfv": "968F0E5C-C297-4122-ACB6-102494DEFD9A",
            "aaid": "ff3c2237-cd76-4331-9d72-0a4470854567",
            "device_ownership": 0,
            "device_status": 0,
            "certification_level": 0,
            "device_terminal_type": 0,
            "is_managed": true,
            "mdm_device_id": "123abc",
            "mdm_provider_name": "Workspace_ONE",
            "device_env_detect_status": 0,
            "is_public": false
        },
        "after": {
            "device_record_id": "7089353870308032531",
            "version": "0",
            "current_user_id": {
                "union_id": "on_8ed6aa67826108097d9ee143816345",
                "user_id": "e33ggbyz",
                "open_id": "ou_84aad35d084aa403a838cf73ee18467"
            },
            "device_name": "Q9C6RYMFDK",
            "model": "iPhone13,2",
            "device_system": 0,
            "serial_number": "C02DTHRMML7H",
            "disk_serial_number": "CC344362-5990-5A68-8DDD-64A23C99FA0C",
            "uuid": "621CDFF0-13D0-5AB1-9ADC-5F560095F6ED",
            "mac_address": "ac:de:48:00:11:21",
            "android_id": "02a11ac4a83b918e",
            "idfv": "968F0E5C-C297-4122-ACB6-102494DEFD9A",
            "aaid": "ff3c2237-cd76-4331-9d72-0a4470854567",
            "device_ownership": 0,
            "device_status": 0,
            "certification_level": 0,
            "device_terminal_type": 0,
            "is_managed": true,
            "mdm_device_id": "123abc",
            "mdm_provider_name": "Workspace_ONE",
            "device_env_detect_status": 0,
            "is_public": false
        }
    }
}
```

### Sample code for event subscriptions

For event subscription process, refer to:[Event Subscription overview](https://open.feishu.cn/document/ukTMukTMukTM/uUTNz4SN1MjL1UzM)，Guide for beginners:[Tutorial](https://open.feishu.cn/document/uAjLw4CM/uMzNwEjLzcDMx4yM3ATM/develop-an-echo-bot/introduction)

**

package main

import (
	"context"
	"fmt"

larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	larkevent "github.com/larksuite/oapi-sdk-go/v3/event"
	"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
	"github.com/larksuite/oapi-sdk-go/v3/service/security_and_compliance/v2"
	larkws "github.com/larksuite/oapi-sdk-go/v3/ws"
)

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/golang-sdk-guide/preparations
func main() {
	// 注册事件 Register event
	eventHandler := dispatcher.NewEventDispatcher("", "").
		OnP2DeviceRecordDeviceChangeEventV2(func(ctx context.Context, event *larksecurity_and_compliance.P2DeviceRecordDeviceChangeEventV2) error {
			fmt.Printf("[ OnP2DeviceRecordDeviceChangeEventV2 access ], data: %s\n", larkcore.Prettify(event))
			return nil
		})

// 构建 client Build client
	cli := larkws.NewClient("YOUR_APP_ID", "YOUR_APP_SECRET",
		larkws.WithEventHandler(eventHandler),
		larkws.WithLogLevel(larkcore.LogLevelDebug),
	)

// 建立长连接 Establish persistent connection
	err := cli.Start(context.Background())

if err != nil {
		panic(err)
	}
}

# SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/python--sdk/preparations-before-development
import lark_oapi as lark

def do_p2_security_and_compliance_device_record_device_change_event_v2(data: lark.security_and_compliance.v2.P2SecurityAndComplianceDeviceRecordDeviceChangeEventV2) -> None:
    print(f'[ do_p2_security_and_compliance_device_record_device_change_event_v2 access ], data: {lark.JSON.marshal(data, indent=4)}')

# 注册事件 Register event
event_handler = lark.EventDispatcherHandler.builder("", "") \
    .register_p2_security_and_compliance_device_record_device_change_event_v2(do_p2_security_and_compliance_device_record_device_change_event_v2) \
    .build()

def main():
    # 构建 client Build client
    cli = lark.ws.Client("APP_ID", "APP_SECRET",
                        event_handler=event_handler, log_level=lark.LogLevel.DEBUG)
    # 建立长连接 Establish persistent connection
    cli.start()

if __name__ == "__main__":
    main()

package com.example.sample;

import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.security_and_compliance.SecurityAndComplianceService;
import com.lark.oapi.service.security_and_compliance.v2.model.P2DeviceRecordDeviceChangeEventV2;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.ws.Client;

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/java-sdk-guide/preparations
public class Sample {
    // 注册事件 Register event
    private static final EventDispatcher EVENT_HANDLER = EventDispatcher.newBuilder("", "")
            .onP2DeviceRecordDeviceChangeEventV2(new SecurityAndComplianceService.P2DeviceRecordDeviceChangeEventV2Handler() {
                @Override
                public void handle(P2DeviceRecordDeviceChangeEventV2 event) throws Exception {
                    System.out.printf("[ onP2DeviceRecordDeviceChangeEventV2 access ], data: %s\n", Jsons.DEFAULT.toJson(event.getEvent()));
                }
            })
            .build();

public static void main(String[] args) {
        // 构建 client Build client
        Client client = new Client.Builder("APP_ID", "APP_SECRET")
                .eventHandler(EVENT_HANDLER)
                .build();
        // 建立长连接 Establish persistent connection
        client.start();
    }
}

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/nodejs-sdk/preparation-before-development
import * as Lark from '@larksuiteoapi/node-sdk';
const baseConfig = {
    appId: 'APP_ID',
    appSecret: 'APP_SECRET'
}
// 构建 client Build client
const wsClient = new Lark.WSClient(baseConfig);
// 建立长连接 Establish persistent connection
wsClient.start({
    // 注册事件 Register event
    eventDispatcher: new Lark.EventDispatcher({}).register({
        'security_and_compliance.device_record.device_change_event_v2': async (data) => {
            console.log(data);
        }
    })
});

package main

import (
	"context"
	"fmt"
	"net/http"

larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
	larkevent "github.com/larksuite/oapi-sdk-go/v3/event"
	"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
	"github.com/larksuite/oapi-sdk-go/v3/service/security_and_compliance/v2"
)

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/golang-sdk-guide/preparations
func main() {
	// 注册事件 Register event
	eventHandler := dispatcher.NewEventDispatcher("", "").
		OnP2DeviceRecordDeviceChangeEventV2(func(ctx context.Context, event *larksecurity_and_compliance.P2DeviceRecordDeviceChangeEventV2) error {
			fmt.Printf("[ OnP2DeviceRecordDeviceChangeEventV2 access ], data: %s\n", larkcore.Prettify(event))
			return nil
		})

// 创建路由处理器 Create route handler
	http.HandleFunc("/webhook/event", httpserverext.NewEventHandlerFunc(handler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))

err := http.ListenAndServe(":7777", nil)

if err != nil {
		panic(err)
	}
}

# SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/python--sdk/preparations-before-development
from flask import Flask
from lark_oapi.adapter.flask import *
import lark_oapi as lark

app = Flask(__name__)

def do_p2_security_and_compliance_device_record_device_change_event_v2(data: lark.security_and_compliance.v2.P2SecurityAndComplianceDeviceRecordDeviceChangeEventV2) -> None:
    print(f'[ do_p2_security_and_compliance_device_record_device_change_event_v2 access ], data: {lark.JSON.marshal(data, indent=4)}')

# 注册事件 Register event
event_handler = lark.EventDispatcherHandler.builder("", "") \
    .register_p2_security_and_compliance_device_record_device_change_event_v2(do_p2_security_and_compliance_device_record_device_change_event_v2) \
    .build()

# 创建路由处理器 Create route handler
@app.route("/webhook/event", methods=["POST"])
def event():
    resp = event_handler.do(parse_req())
    return parse_resp(resp)

if __name__ == "__main__":
    app.run(port=7777)

package com.lark.oapi.sample.event;

import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.security_and_compliance.SecurityAndComplianceService;
import com.lark.oapi.service.security_and_compliance.v2.model.P2DeviceRecordDeviceChangeEventV2;
import com.lark.oapi.sdk.servlet.ext.ServletAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/java-sdk-guide/preparations
@RestController
public class EventController {

// 注册事件 Register event
    private static final EventDispatcher EVENT_HANDLER = EventDispatcher.newBuilder("verificationToken", "encryptKey")
            .onP2DeviceRecordDeviceChangeEventV2(new SecurityAndComplianceService.P2DeviceRecordDeviceChangeEventV2Handler() {
                @Override
                public void handle(P2DeviceRecordDeviceChangeEventV2 event) throws Exception {
                    System.out.printf("[ onP2DeviceRecordDeviceChangeEventV2 access ], data: %s\n", Jsons.DEFAULT.toJson(event.getEvent()));
                }
            })
            .build();

// 注入 ServletAdapter 实例 Inject ServletAdapter instance
    @Autowired
    private ServletAdapter servletAdapter;

// 创建路由处理器 Create route handler
    @RequestMapping("/webhook/event")
    public void event(HttpServletRequest request, HttpServletResponse response)
            throws Throwable {
        // 回调扩展包提供的事件回调处理器 Callback handler provided by the extension package
        servletAdapter.handleEvent(request, response, EVENT_DISPATCHER);
    }
}

// SDK 使用说明 SDK user guide：https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/nodejs-sdk/preparation-before-development
import http from 'http';
import * as lark from '@larksuiteoapi/node-sdk';

// 注册事件 Register event
const eventDispatcher = new lark.EventDispatcher({
    encryptKey: '',
    verificationToken: '',
}).register({
    'security_and_compliance.device_record.device_change_event_v2': async (data) => {
        console.log(data);
        return 'success';
    },
});

const server = http.createServer();
// 创建路由处理器 Create route handler
server.on('request', lark.adaptDefault('/webhook/event', eventDispatcher));
server.listen(3000);

