package douyin import ( "context" "encoding/json" "fmt" "io" "net/http" "strings" "time" ) const ( // PhoneNumberURL Douyin get phone number interface address PhoneNumberURL = "https://developer.toutiao.com/api/apps/v1/number_get/bind/" ) // PhoneNumberRequest request parameters type PhoneNumberRequest struct { AppID string `json:"app_id"` // Note: specific parameter name might vary, but usually it's app_id or appid. Docs say `app_id` for some v1 interfaces. Code string `json:"code"` } // PhoneNumberResponse response type PhoneNumberResponse struct { ErrNo int `json:"err_no"` ErrTips string `json:"err_tips"` Data struct { PhoneNumber string `json:"phone_number"` } `json:"data"` } // GetPhoneNumber calls Douyin interface to get user phone number func GetPhoneNumber(ctx context.Context, accessToken, appID, code string) (string, error) { if accessToken == "" || code == "" { return "", fmt.Errorf("missing parameters") } // Note: Verify the correct endpoint and parameters. // Commonly for `v1/number_get/bind/`, it might expect `encryptedData`? // But `tt.getPhoneNumber` provides `code`. // Let's assume the modern Code-based API which is often similar to `number_get/bind` but with `code`. // Check if we need to call `https://developer.toutiao.com/api/apps/v1/user/get_phone_number_v1` instead? // Or `https://developer.open-douyin.com/api/apps/v1/img/get_phone_number_v1`? // Since I cannot verify the exact URL visually, I will stick to the one I hypothesized or the most "standard" one found in similar Go SDKs. // Actually, let's try to assume it's `POST /api/apps/v2/jscode2session` style but for phone. // A common variation for "get phone number by code" in Douyin is sending `code` and `app_id` to an endpoint. // Let's go with the one stated in many online resources for "Douyin Mini Program Get Phone Number". reqBody := map[string]string{ "app_id": appID, "code": code, } jsonBody, err := json.Marshal(reqBody) if err != nil { return "", fmt.Errorf("failed to marshal request: %w", err) } httpClient := &http.Client{Timeout: 10 * time.Second} // The URL might need `access_token` in query param or header? // Most `v1` Douyin APIs require `access_token` in header or query. We will put in header `access-token`. req, err := http.NewRequestWithContext(ctx, "POST", PhoneNumberURL, strings.NewReader(string(jsonBody))) if err != nil { return "", fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Content-Type", "application/json") // Some docs say `access-token` in header req.Header.Set("access-token", accessToken) resp, err := httpClient.Do(req) if err != nil { return "", fmt.Errorf("failed to request Douyin interface: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } var result PhoneNumberResponse if err := json.Unmarshal(body, &result); err != nil { return "", fmt.Errorf("failed to parse response: %w, body: %s", err, string(body)) } if result.ErrNo != 0 { return "", fmt.Errorf("failed to get phone number: %s (code: %d)", result.ErrTips, result.ErrNo) } return result.Data.PhoneNumber, nil }