Skip to content

事件上报 API

事件上报 API 用于上报用户行为事件数据,支持批量上报多个事件。

基础信息

  • 基础路径: /users/report/events
  • V2 路径: /v2/users/report/events
  • 认证: 需要 API Key (通过 X-API-KEY 请求头)
  • 请求方法: POST

接口说明

上报事件

上报用户行为事件数据,支持批量上报。

http
POST /users/report/events
POST /v2/users/report/events  # V2 版本(推荐使用)

请求头

请求头类型必填描述
X-API-KEYstringAPI Key
X-USER-IDstring当前用户的唯一标识
User-Agentstring用户代理信息
X-APP-IDstring应用的唯一标识
X-PLATFORMstring平台标识(iOS/Android)
X-VERSIONstringSDK 版本号
Content-Typestringapplication/json
Acceptstringapplication/json

请求体

json
{
  "events": [
    {
      "name": "app_opened",
      "user": "user_123456",
      "sessionId": "session_abc123",
      "extra": {
        "source": "push_notification",
        "screen": "home"
      }
    },
    {
      "name": "purchase_completed",
      "user": "user_123456",
      "sessionId": "session_abc123",
      "extra": {
        "product_id": "premium_monthly",
        "price": 9.99,
        "currency": "USD"
      }
    }
  ]
}

请求参数说明

参数类型必填描述
eventsarray事件数组
events[].namestring事件名称
events[].userstring用户标识
events[].sessionIdstring会话 ID
events[].extraobject事件额外属性(自定义属性)

响应示例

成功响应

json
{
  "status": "success",
  "message": "Events reported successfully"
}

错误响应

json
{
  "status": "error",
  "code": "INVALID_PARAMETER",
  "message": "Event name is required"
}

使用示例

cURL 示例

bash
curl -X POST \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-USER-ID: user_123456" \
  -H "User-Agent: YourApp/1.0" \
  -H "X-APP-ID: com.example.app" \
  -H "X-PLATFORM: iOS" \
  -H "X-VERSION: 1.0.0" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  "https://mobile.dingyue.io/users/report/events" \
  -d '{
    "events": [
      {
        "name": "app_opened",
        "user": "user_123456",
        "sessionId": "session_abc123",
        "extra": {
          "source": "push_notification"
        }
      },
      {
        "name": "feature_used",
        "user": "user_123456",
        "sessionId": "session_abc123",
        "extra": {
          "feature_name": "premium_analytics",
          "usage_duration": 120
        }
      }
    ]
  }'

iOS Swift 示例

swift
import Foundation

func reportEvents() {
    let url = URL(string: "https://mobile.dingyue.io/users/report/events")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    // 设置请求头
    request.setValue("YOUR_API_KEY", forHTTPHeaderField: "X-API-KEY")
    request.setValue("user_123456", forHTTPHeaderField: "X-USER-ID")
    request.setValue("YourApp/1.0", forHTTPHeaderField: "User-Agent")
    request.setValue("com.example.app", forHTTPHeaderField: "X-APP-ID")
    request.setValue("iOS", forHTTPHeaderField: "X-PLATFORM")
    request.setValue("1.0.0", forHTTPHeaderField: "X-VERSION")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    
    // 构建请求体
    let events: [String: Any] = [
        "events": [
            [
                "name": "app_opened",
                "user": "user_123456",
                "sessionId": "session_abc123",
                "extra": [
                    "source": "push_notification"
                ]
            ],
            [
                "name": "purchase_completed",
                "user": "user_123456",
                "sessionId": "session_abc123",
                "extra": [
                    "product_id": "premium_monthly",
                    "price": 9.99,
                    "currency": "USD"
                ]
            ]
        ]
    ]
    
    request.httpBody = try? JSONSerialization.data(withJSONObject: events)
    
    URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error: \(error)")
            return
        }
        
        if let data = data {
            let result = try? JSONSerialization.jsonObject(with: data)
            print("Result: \(result ?? "nil")")
        }
    }.resume()
}

Android Java 示例

java
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;

public class EventReporter {
    private static final String API_URL = "https://mobile.dingyue.io/users/report/events";
    private static final String API_KEY = "YOUR_API_KEY";
    
    public void reportEvents() {
        OkHttpClient client = new OkHttpClient();
        
        // 构建请求体
        JSONArray events = new JSONArray();
        
        JSONObject event1 = new JSONObject();
        event1.put("name", "app_opened");
        event1.put("user", "user_123456");
        event1.put("sessionId", "session_abc123");
        JSONObject extra1 = new JSONObject();
        extra1.put("source", "push_notification");
        event1.put("extra", extra1);
        events.put(event1);
        
        JSONObject event2 = new JSONObject();
        event2.put("name", "purchase_completed");
        event2.put("user", "user_123456");
        event2.put("sessionId", "session_abc123");
        JSONObject extra2 = new JSONObject();
        extra2.put("product_id", "premium_monthly");
        extra2.put("price", 9.99);
        extra2.put("currency", "USD");
        event2.put("extra", extra2);
        events.put(event2);
        
        JSONObject requestBody = new JSONObject();
        requestBody.put("events", events);
        
        RequestBody body = RequestBody.create(
            requestBody.toString(),
            MediaType.parse("application/json")
        );
        
        Request request = new Request.Builder()
            .url(API_URL)
            .addHeader("X-API-KEY", API_KEY)
            .addHeader("X-USER-ID", "user_123456")
            .addHeader("User-Agent", "YourApp/1.0")
            .addHeader("X-APP-ID", "com.example.app")
            .addHeader("X-PLATFORM", "Android")
            .addHeader("X-VERSION", "1.0.0")
            .addHeader("Content-Type", "application/json")
            .addHeader("Accept", "application/json")
            .post(body)
            .build();
        
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }
            
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    System.out.println("Success: " + result);
                } else {
                    System.out.println("Error: " + response.code());
                }
            }
        });
    }
}

JavaScript 示例

javascript
async function reportEvents() {
  const url = 'https://mobile.dingyue.io/users/report/events';
  
  const events = [
    {
      name: 'app_opened',
      user: 'user_123456',
      sessionId: 'session_abc123',
      extra: {
        source: 'push_notification'
      }
    },
    {
      name: 'purchase_completed',
      user: 'user_123456',
      sessionId: 'session_abc123',
      extra: {
        product_id: 'premium_monthly',
        price: 9.99,
        currency: 'USD'
      }
    }
  ];
  
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'X-API-KEY': 'YOUR_API_KEY',
        'X-USER-ID': 'user_123456',
        'User-Agent': 'YourApp/1.0',
        'X-APP-ID': 'com.example.app',
        'X-PLATFORM': 'iOS',
        'X-VERSION': '1.0.0',
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({ events })
    });
    
    const result = await response.json();
    console.log('Result:', result);
  } catch (error) {
    console.error('Error:', error);
  }
}

// 使用示例
reportEvents();

常见事件类型

应用生命周期事件

事件名称描述建议属性
app_opened应用启动source (启动来源)
app_closed应用关闭duration (使用时长)
app_background应用进入后台-
app_foreground应用回到前台-

用户行为事件

事件名称描述建议属性
screen_view页面浏览screen_name (页面名称)
button_click按钮点击button_name (按钮名称)
feature_used功能使用feature_name (功能名称)

购买相关事件

事件名称描述建议属性
purchase_started开始购买product_id (产品 ID)
purchase_completed完成购买product_id, price, currency
purchase_cancelled取消购买product_id, reason
subscription_started订阅开始product_id, trial_period
subscription_renewed订阅续费product_id
subscription_cancelled订阅取消product_id, reason

最佳实践

1. 批量上报

为了提高效率,建议将多个事件合并到一次请求中批量上报:

javascript
// ✅ 推荐:批量上报
const events = [
  { name: 'app_opened', user: 'user_123', sessionId: 'sess_1', extra: {} },
  { name: 'screen_view', user: 'user_123', sessionId: 'sess_1', extra: { screen: 'home' } },
  { name: 'button_click', user: 'user_123', sessionId: 'sess_1', extra: { button: 'upgrade' } }
];
await reportEvents({ events });

// ❌ 不推荐:逐个上报
for (const event of events) {
  await reportEvents({ events: [event] });
}

2. 事件命名规范

建议使用小写字母和下划线命名事件:

  • app_opened
  • purchase_completed
  • screen_view
  • AppOpened
  • purchaseCompleted
  • screen-view

3. 会话 ID 管理

确保同一个会话的所有事件使用相同的 sessionId

javascript
const sessionId = generateSessionId(); // 会话开始时生成

// 同一会话中的所有事件使用相同的 sessionId
reportEvent('app_opened', { sessionId });
reportEvent('screen_view', { sessionId, screen: 'home' });
reportEvent('button_click', { sessionId, button: 'upgrade' });

4. 错误处理

始终处理可能的错误情况:

javascript
async function reportEventsWithRetry(events, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await reportEvents({ events });
      if (response.status === 'success') {
        return response;
      }
    } catch (error) {
      if (i === maxRetries - 1) {
        throw error;
      }
      // 等待后重试
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
    }
  }
}

V2 版本

V2 版本的接口路径为 /v2/users/report/events,建议新项目使用 V2 版本,它提供了:

  • 更好的数据结构
  • 增强的错误处理
  • 性能优化

V2 版本的请求格式与 V1 相同。

错误码

错误码描述
INVALID_API_KEYAPI Key 无效
MISSING_REQUIRED_HEADER缺少必需的请求头
INVALID_PARAMETER请求参数不合法
EVENT_NAME_REQUIRED事件名称不能为空
USER_REQUIRED用户标识不能为空
SESSION_ID_REQUIRED会话 ID 不能为空

相关资源