استيراد الإحالات الناجحة عبر الاتصال الهاتفي

يمكنك استخدام Google Ads API لاستيراد الإحالات الناجحة عبر الاتصال الهاتفي خارج إطار الإنترنت إلى "إعلانات Google" من أجل تتبُّع الحالات التي تؤدي فيها الإعلانات إلى مكالمات هاتفية والحالات التي تؤدي فيها هذه المكالمات الهاتفية إلى إجراءات قيّمة يتخذها العملاء.

عند الربط بواجهة مستخدم "إعلانات Google"، يكون ذلك مماثلاً لاستخدام مصدر الإحالة الناجحة عمليات التحميل، ثم اختيار الإحالات الناجحة من المكالمات.

المتطلبات

يجب استيفاء المتطلبات التالية عند استيراد CallConversion.

لتجنُّب حدوث خطأ في ConversionUploadError.INVALID_CONVERSION_ACTION، يجب أن تشير السمة conversion_action إلى ConversionAction حيث:

  • تبلغ قيمة "ConversionActionType" UPLOAD_CALLS.

  • status في ConversionAction هو ENABLED. وإلا، ستتعذّر العملية مع ظهور الخطأ NO_CONVERSION_ACTION_FOUND.

  • يتوفّر ConversionAction في عميل الإحالات الناجحة للإعلان على "إعلانات Google" لحساب "إعلانات Google" الخاص بالنقرة.

ننصحك أيضًا بضبط السمة ConversionAction.category على الفئة التي تصف إحالاتك الناجحة بأفضل شكل.

بالإضافة إلى ذلك، يجب استيفاء الشروط التالية:

  • في وقت المكالمة، كانت ميزة تتبُّع الإحالات الناجحة مفعَّلة في حساب عميل الإحالات الناجحة في "إعلانات Google" لحساب "إعلانات Google" الخاص بالمكالمة.

  • يجب أن يكون customer_id UploadCallConversionsRequest هو رقم تعريف العميل الخاص بعميل الإحالة الناجحة في "إعلانات Google" لحساب "إعلانات Google" المرتبط بالمكالمة. وإلا، سيؤدي استيراد الإحالات الناجحة إلى حدوث خطأ ConversionUploadError.INVALID_CUSTOMER_FOR_CALL.

  • يجب أن تكون قيمة السمة conversion_value أكبر من صفر أو مساوية له.

  • يجب أن تتضمّن السمة conversion_date_time منطقة زمنية محدّدة، ويجب أن يكون التنسيق yyyy-mm-dd HH:mm:ss+|-HH:mm، على سبيل المثال: 2022-01-01 19:32:45-05:00 (مع تجاهل نظام التوقيت الصيفي) . يمكن أن تكون المنطقة الزمنية لأي قيمة صالحة: ليس من الضروري أن تتطابق مع المنطقة الزمنية للحساب. ومع ذلك، إذا كنت تخطط لمقارنة بيانات الإحالات الناجحة المستوردة مع تلك الموجودة في واجهة مستخدم إعلانات Google، فنوصي باستخدام نفس المنطقة الزمنية لحساب إعلانات Google بحيث تتطابق أعداد الإحالات الناجحة.

الاعتبارات الأساسية

يُرجى مراعاة ما يلي عند إنشاء CallConversion:

  • يجب ملء الحقل consent في الكائن CallConversion.

  • يجب ضبط سمة partial_failure في UploadCallConversionsRequest دائمًا على true. اتّبِع إرشادات حالات الإخفاق الجزئي عند التعامل مع العمليات الصالحة والفاشلة في الوقت نفسه.

  • إذا تلقّيت رسالة الردّ TOO_RECENT_CONVERSION_ACTION أو TOO_RECENT_CALL على طلب استيراد الإحالات الناجحة، انتظِر لمدة 6 ساعات أو 12 ساعة على التوالي قبل إعادة محاولة استيراد الصفوف التي تعذّر استيرادها.

  • يستغرق ظهور إحصاءات الإحالات الناجحة المستورَدة في حسابك على "إعلانات Google" مدة تصل إلى 3 ساعات.

  • إذا كان طلب واحد يحتوي على عمليات متعددة للإحالة الناجحة نفسها، يظهر الخطأ DUPLICATE_CALL_CONVERSION_IN_REQUEST.

  • إذا نسخ المستخدم رقم توجيه المكالمات من Google يدويًا واتصل به، لا يمكن تسجيل أي إحالة ناجحة.

استيراد إحالة ناجحة عبر الاتصال الهاتفي

لربط الإحالات الناجحة عبر الاتصال الهاتفي غير الإلكترونية بإجراء إحالة ناجحة، عليك تمرير معرّف المتصل (رقم الهاتف) وتاريخ الإحالة الناجحة ووقتها واسم مورد إجراء الإحالة الناجحة وقيمة الإحالة الناجحة الاختيارية ورمز العملة إلى ConversionUploadService. لمزيد من التفاصيل حول الإدخالات المختلفة، يُرجى الاطّلاع على مقالة استيراد الإحالات الناجحة عبر الاتصال الهاتفي. يصف مثال الرمز البرمجي أيضًا تنسيقات المدخلات المختلفة.

مثال على الرمز البرمجي

جافا

private void runExample(
    GoogleAdsClient googleAdsClient,
    long customerId,
    String conversionActionId,
    String callerId,
    String callStartDateTime,
    double conversionValue,
    Long conversionCustomVariableId,
    String conversionCustomVariableValue,
    ConsentStatus adUserDataConsent) {
  // Create a call conversion by specifying currency as USD.
  CallConversion.Builder conversionBuilder =
      CallConversion.newBuilder()
          .setConversionAction(conversionActionId)
          .setCallerId(callerId)
          .setCallStartDateTime(callStartDateTime)
          .setConversionValue(conversionValue)
          .setCurrencyCode("USD");

  if (conversionCustomVariableId != null && conversionCustomVariableValue != null) {
    conversionBuilder.addCustomVariables(
        CustomVariable.newBuilder()
            .setConversionCustomVariable(
                ResourceNames.conversionCustomVariable(customerId, conversionCustomVariableId))
            .setValue(conversionCustomVariableValue));
  }

  // Sets the consent information, if provided.
  if (adUserDataConsent != null) {
    // Specifies whether user consent was obtained for the data you are uploading. See
    // https://www.google.com/about/company/user-consent-policy for details.
    conversionBuilder.setConsent(Consent.newBuilder().setAdUserData(adUserDataConsent));
  }

  CallConversion conversion = conversionBuilder.build();

  // Uploads the call conversion to the API.
  try (ConversionUploadServiceClient conversionUploadServiceClient =
      googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) {
    // Partial failure MUST be enabled for this request.

    // NOTE: This request contains a single conversion as a demonstration.  However, if you have
    // multiple conversions to upload, it's best to upload multiple conversions per request
    // instead of sending a separate request per conversion. See the following for per-request
    // limits:
    // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
    UploadCallConversionsResponse response =
        conversionUploadServiceClient.uploadCallConversions(
            UploadCallConversionsRequest.newBuilder()
                .setCustomerId(String.valueOf(customerId))
                .setCustomerId(Long.toString(customerId))
                .addConversions(conversion)
                .setPartialFailure(true)
                .build());

    // Prints any partial failure errors returned.
    if (response.hasPartialFailureError()) {
      GoogleAdsFailure googleAdsFailure =
          ErrorUtils.getInstance().getGoogleAdsFailure(response.getPartialFailureError());
      googleAdsFailure
          .getErrorsList()
          .forEach(e -> System.out.println("Partial failure occurred: " + e.getMessage()));
      throw new RuntimeException(
          "Partial failure occurred " + response.getPartialFailureError().getMessage());
    }

    // Prints the result if valid.
    CallConversionResult result = response.getResults(0);
    System.out.printf(
        "Uploaded call conversion that occurred at '%' for caller ID '%' to the conversion"
            + " action with resource name '%'.%n",
        result.getCallStartDateTime(), result.getCallerId(), result.getConversionAction());
  }
}
      

#C

public void Run(GoogleAdsClient client, long customerId,
    long conversionActionId, string callerId, string callStartTime,
    string conversionTime, double conversionValue,
    long? conversionCustomVariableId, string conversionCustomVariableValue,
    ConsentStatus? adUserDataConsent)
{
    // Get the ConversionUploadService.
    ConversionUploadServiceClient conversionUploadService =
        client.GetService(Services.V26.ConversionUploadService);

    // Create a call conversion by specifying currency as USD.
    CallConversion callConversion = new CallConversion()
    {
        ConversionAction = ResourceNames.ConversionAction(customerId, conversionActionId),
        CallerId = callerId,
        CallStartDateTime = callStartTime,
        ConversionDateTime = conversionTime,
        ConversionValue = conversionValue,
        CurrencyCode = "USD",
    };

    if (adUserDataConsent != null)
    {
        // Specifies whether user consent was obtained for the data you are uploading. See
        // https://www.google.com/about/company/user-consent-policy
        // for details.
        callConversion.Consent = new Consent()
        {
            AdUserData = (ConsentStatus)adUserDataConsent
        };
    }

    if (conversionCustomVariableId != null &&
        !string.IsNullOrEmpty(conversionCustomVariableValue))
    {
        callConversion.CustomVariables.Add(new CustomVariable()
        {
            ConversionCustomVariable = ResourceNames.ConversionCustomVariable(
                customerId, conversionCustomVariableId.Value),
            Value = conversionCustomVariableValue
        });
    }

    UploadCallConversionsRequest request = new UploadCallConversionsRequest()
    {
        CustomerId = customerId.ToString(),
        Conversions = { callConversion },
        PartialFailure = true
    };

    try
    {
        // Issues a request to upload the call conversion. The partialFailure parameter
        // is set to true, and validateOnly parameter to false as required by this method
        // call.
        // NOTE: This request contains a single conversion as a demonstration.  However, if
        // you have multiple conversions to upload, it's best to upload multiple conversions
        // per request instead of sending a separate request per conversion. See the
        // following for per-request limits:
        // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
        UploadCallConversionsResponse response =
            conversionUploadService.UploadCallConversions(request);

        // Since we set partialFailure = true, we can retrieve error messages (if any) from
        // the operation response.
        if (response.PartialFailureError != null)
        {
            Console.WriteLine("Call conversion upload failed.");

            // Retrieves the errors from the partial failure and prints them.
            List<GoogleAdsError> errors =
                response.PartialFailure.GetErrorsByOperationIndex(0);
            foreach (GoogleAdsError error in errors)
            {
                Console.WriteLine($"Operation failed with error: {error}.");
            }
        }
        else
        {
            // Prints the result.
            CallConversionResult uploadedCallConversion = response.Results[0];
            Console.WriteLine($"Uploaded call conversion that occurred at " +
                $"'{uploadedCallConversion.CallStartDateTime}' for caller ID " +
                $"'{uploadedCallConversion.CallerId}' to the conversion action with " +
                $"resource name '{uploadedCallConversion.ConversionAction}'.");
        }

    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}
      

PHP

    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        int $conversionActionId,
        string $callerId,
        string $callStartDateTime,
        string $conversionDateTime,
        float $conversionValue,
        ?string $conversionCustomVariableId,
        ?string $conversionCustomVariableValue,
        ?int $adUserDataConsent
    ) {
        // Creates a call conversion by specifying currency as USD.
        $callConversion = new CallConversion(
            [
            'conversion_action' =>
                ResourceNames::forConversionAction($customerId, $conversionActionId),
            'caller_id' => $callerId,
            'call_start_date_time' => $callStartDateTime,
            'conversion_date_time' => $conversionDateTime,
            'conversion_value' => $conversionValue,
            'currency_code' => 'USD'
            ]
        );
        if (!is_null($conversionCustomVariableId) && !is_null($conversionCustomVariableValue)) {
            $callConversion->setCustomVariables(
                [new CustomVariable(
                    [
                    'conversion_custom_variable' => ResourceNames::forConversionCustomVariable(
                        $customerId,
                        $conversionCustomVariableId
                    ),
                    'value' => $conversionCustomVariableValue
                    ]
                )]
            );
        }
        // Sets the consent information, if provided.
        if (!empty($adUserDataConsent)) {
            // Specifies whether user consent was obtained for the data you are uploading. See
            // https://www.google.com/about/company/user-consent-policy for details.
            $callConversion->setConsent(new Consent(['ad_user_data' => $adUserDataConsent]));
        }

        // Issues a request to upload the call conversion.
        $conversionUploadServiceClient = $googleAdsClient->getConversionUploadServiceClient();
        // NOTE: This request contains a single conversion as a demonstration.  However, if you have
        // multiple conversions to upload, it's best to upload multiple conversions per request
        // instead of sending a separate request per conversion. See the following for per-request
        // limits:
        // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
        $response = $conversionUploadServiceClient->uploadCallConversions(
            // Partial failure MUST be enabled for this request.
            UploadCallConversionsRequest::build($customerId, [$callConversion], true)
        );

        // Prints the status message if any partial failure error is returned.
        // Note: The details of each partial failure error are not printed here, you can refer to
        // the example HandlePartialFailure.php to learn more.
        if ($response->hasPartialFailureError()) {
            printf(
                "Partial failures occurred: '%s'.%s",
                $response->getPartialFailureError()->getMessage(),
                PHP_EOL
            );
        } else {
            // Prints the result if exists.
            /**
 * @var CallConversionResult $uploadedCallConversion
*/
            $uploadedCallConversion = $response->getResults()[0];
            printf(
                "Uploaded call conversion that occurred at '%s' for caller ID '%s' to the "
                . "conversion action with resource name '%s'.%s",
                $uploadedCallConversion->getCallStartDateTime(),
                $uploadedCallConversion->getCallerId(),
                $uploadedCallConversion->getConversionAction(),
                PHP_EOL
            );
        }
    }
      

Python

def main(
    client: GoogleAdsClient,
    customer_id: str,
    conversion_action_id: str,
    caller_id: str,
    call_start_date_time: str,
    conversion_date_time: str,
    conversion_value: float,
    conversion_custom_variable_id: Optional[str],
    conversion_custom_variable_value: Optional[str],
    ad_user_data_consent: Optional[str],
):
    """Imports offline call conversion values for calls related to your ads.

    Args:
        client: An initialized GoogleAdsClient instance.
        customer_id: The client customer ID string.
        conversion_action_id: The ID of the conversion action to upload to.
        caller_id: The caller ID from which this call was placed. Caller ID is
            expected to be in E.164 format with preceding '+' sign,
            e.g. '+18005550100'.
        call_start_date_time: The date and time at which the call occurred. The
            format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm',
            e.g. '2021-01-01 12:32:45-08:00'.
        conversion_date_time: The the date and time of the conversion (should be
            after the click time). The format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm',
            e.g. '2021-01-01 12:32:45-08:00'.
        conversion_value: The conversion value in the desired currency.
        conversion_custom_variable_id: The ID of the conversion custom
            variable to associate with the upload.
        conversion_custom_variable_value: The str value of the conversion custom
            variable to associate with the upload.
        ad_user_data_consent: The consent status for ad user data for all
            members in the job.
    """
    # Get the ConversionUploadService client.
    conversion_upload_service: ConversionUploadServiceClient = (
        client.get_service("ConversionUploadService")
    )

    # Create a call conversion in USD currency.
    call_conversion: CallConversion = client.get_type("CallConversion")
    call_conversion.conversion_action = client.get_service(
        "ConversionActionService"
    ).conversion_action_path(customer_id, conversion_action_id)
    call_conversion.caller_id = caller_id
    call_conversion.call_start_date_time = call_start_date_time
    call_conversion.conversion_date_time = conversion_date_time
    call_conversion.conversion_value = conversion_value
    call_conversion.currency_code = "USD"

    if conversion_custom_variable_id and conversion_custom_variable_value:
        conversion_custom_variable: CustomVariable = client.get_type(
            "CustomVariable"
        )
        conversion_custom_variable.conversion_custom_variable = (
            conversion_custom_variable_id
        )
        conversion_custom_variable.value = conversion_custom_variable_value
        call_conversion.custom_variables.append(conversion_custom_variable)

    # Specifies whether user consent was obtained for the data you are
    # uploading. For more details. see:
    # https://www.google.com/about/company/user-consent-policy
    if ad_user_data_consent:
        call_conversion.consent.ad_user_data = client.enums.ConsentStatusEnum[
            ad_user_data_consent
        ]

    # Issue a request to upload the call conversion.
    # Partial failure MUST be enabled for this request.
    request: UploadCallConversionsRequest = client.get_type(
        "UploadCallConversionsRequest"
    )
    request.customer_id = customer_id
    request.conversions = [call_conversion]
    request.partial_failure = True
    # NOTE: This request only uploads a single conversion, but if you have
    # multiple conversions to upload, it's most efficient to upload them in a
    # single request. See the following for per-request limits for reference:
    # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
    upload_call_conversions_response: UploadCallConversionsResponse = (
        conversion_upload_service.upload_call_conversions(request=request)
    )

    # Print any partial errors returned.
    if upload_call_conversions_response.partial_failure_error:
        print(
            "Partial error occurred: "
            f"'{upload_call_conversions_response.partial_failure_error.message}'"
        )

    # Print the result if valid.
    uploaded_call_conversion: CallConversionResult = (
        upload_call_conversions_response.results[0]
    )
    if uploaded_call_conversion.call_start_date_time:
        print(
            "Uploaded call conversion that occurred at "
            f"'{uploaded_call_conversion.call_start_date_time}' "
            f"for caller ID '{uploaded_call_conversion.caller_id}' "
            "to the conversion action with resource name "
            f"'{uploaded_call_conversion.conversion_action}'."
        )
      

Ruby

def upload_call_conversion(
  customer_id,
  conversion_action_id,
  caller_id,
  call_start_date_time,
  conversion_date_time,
  conversion_value,
  conversion_custom_variable_id,
  conversion_custom_variable_value,
  ad_user_data_consent)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # Create a call conversion by specifying currency as USD.
  call_conversion = client.resource.call_conversion do |c|
    c.conversion_action = client.path.conversion_action(
      customer_id, conversion_action_id)
    c.caller_id = caller_id
    c.call_start_date_time = call_start_date_time
    c.conversion_date_time = conversion_date_time
    c.conversion_value = conversion_value
    c.currency_code = "USD"
    if conversion_custom_variable_id && conversion_custom_variable_value
      c.custom_variables << client.resource.custom_variable do |cv|
        cv.conversion_custom_variable = client.path.conversion_custom_variable(
          customer_id, conversion_custom_variable_id)
        cv.value = conversion_custom_variable_value
      end
    end

    unless ad_user_data_consent.nil?
      c.consent = client.resource.consent do |c|
        # Specifies whether user consent was obtained for the data you are
        # uploading. For more details, see:
        # https://www.google.com/about/company/user-consent-policy
        c.ad_user_data = ad_user_data_consent
      end
    end
  end

  # Issues a request to upload the call conversion.
  response = client.service.conversion_upload.upload_call_conversions(
    customer_id: customer_id,
    # NOTE: This request only uploads a single conversion, but if you have
    # multiple conversions to upload, it's most efficient to upload them in a
    # single request. See the following for per-request limits for reference:
    # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
    conversions: [call_conversion],
    partial_failure: true
  )

  # Prints errors if any partial failure error is returned.
  if response.partial_failure_error
    failures = client.decode_partial_failure_error(response.partial_failure_error)
    failures.each do |failure|
      failure.errors.each do |error|
        human_readable_error_path = error
          .location
          .field_path_elements
          .map { |location_info|
            if location_info.index
              "#{location_info.field_name}[#{location_info.index}]"
            else
              "#{location_info.field_name}"
            end
          }.join(" > ")

        errmsg =  "error occured while adding operations " \
          "#{human_readable_error_path}" \
          " with value: #{error.trigger.string_value}" \
          " because #{error.message.downcase}"
        puts errmsg
      end
    end
  else
    # Print the result if valid.
    uploaded_call_conversion = response.results.first
    puts "Uploaded call conversion that occurred at " \
      "#{uploaded_call_conversion.call_start_date_time} " \
      "for caller ID " \
      "#{uploaded_call_conversion.caller_id} " \
      "to the conversion action with resource name " \
      "#{uploaded_call_conversion.conversion_action}"
  end
end
      

Perl

sub upload_call_conversion {
  my (
    $api_client,                       $customer_id,
    $conversion_action_id,             $caller_id,
    $call_start_date_time,             $conversion_date_time,
    $conversion_value,                 $conversion_custom_variable_id,
    $conversion_custom_variable_value, $ad_user_data_consent
  ) = @_;

  # Create a call conversion by specifying currency as USD.
  my $call_conversion =
    Google::Ads::GoogleAds::V26::Services::ConversionUploadService::CallConversion
    ->new({
      conversionAction =>
        Google::Ads::GoogleAds::V26::Utils::ResourceNames::conversion_action(
        $customer_id, $conversion_action_id
        ),
      callerId           => $caller_id,
      callStartDateTime  => $call_start_date_time,
      conversionDateTime => $conversion_date_time,
      conversionValue    => $conversion_value,
      currencyCode       => "USD"
    });

  if ($conversion_custom_variable_id && $conversion_custom_variable_value) {
    $call_conversion->{customVariables} = [
      Google::Ads::GoogleAds::V26::Services::ConversionUploadService::CustomVariable
        ->new({
          conversionCustomVariable =>
            Google::Ads::GoogleAds::V26::Utils::ResourceNames::conversion_custom_variable(
            $customer_id, $conversion_custom_variable_id
            ),
          value => $conversion_custom_variable_value
        })];
  }

  # Set the consent information, if provided.
  if ($ad_user_data_consent) {
    # Specify whether user consent was obtained for the data you are uploading.
    # See https://www.google.com/about/company/user-consent-policy for details.
    $call_conversion->{consent} =
      Google::Ads::GoogleAds::V26::Common::Consent->new({
        adUserData => $ad_user_data_consent
      });
  }

  # Issue a request to upload the call conversion.
  # NOTE: This request contains a single conversion as a demonstration.
  # However, if you have multiple conversions to upload, it's best to
  # upload multiple conversions per request instead of sending a separate
  # request per conversion. See the following for per-request limits:
  # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
  my $upload_call_conversions_response =
    $api_client->ConversionUploadService()->upload_call_conversions({
      customerId     => $customer_id,
      conversions    => [$call_conversion],
      partialFailure => "true"
    });

  # Print any partial errors returned.
  if ($upload_call_conversions_response->{partialFailureError}) {
    printf "Partial error encountered: '%s'.\n",
      $upload_call_conversions_response->{partialFailureError}{message};
  }

  # Print the result if valid.
  my $uploaded_call_conversion =
    $upload_call_conversions_response->{results}[0];
  if (%$uploaded_call_conversion) {
    printf "Uploaded call conversion that occurred at '%s' " .
      "for caller ID '%s' to the conversion action with resource name '%s'.\n",
      $uploaded_call_conversion->{callStartDateTime},
      $uploaded_call_conversion->{callerId},
      $uploaded_call_conversion->{conversionAction};
  }

  return 1;
}
      

curl

# This code example uploads a call conversion.
#
# Variables:
#   API_VERSION,
#   CUSTOMER_ID,
#   MANAGER_CUSTOMER_ID,
#   OAUTH2_ACCESS_TOKEN:
#     See https://developers.google.com/google-ads/api/rest/auth#request_headers
#     for details.
#
#   CONVERSION_ACTION_RESOURCE_NAME: Resource name of the conversion action
#     associated with this conversion.
#   CALLER_ID: The caller id from which this call was placed. Caller id is
#     expected to be in E.164 format with preceding '+' sign, for example,
#     "+18005550100".
#   CALL_START_DATE_TIME: The date time at which the call occurred. The format
#      is "yyyy-mm-dd hh:mm:ss+|-hh:mm", for example,
#      "2019-01-01 12:32:45-08:00".
#   CONVERSION_DATE_TIME: The date time at which the conversion occurred. The
#     format is "yyyy-mm-dd hh:mm:ss+|-hh:mm", for example,
#     "2019-01-01 12:32:45-08:00".
#   CONVERSION_VALUE: The value of the conversion for the advertiser.
#   CURRENCY_CODE: The currency code of the conversion value. This is the
#     ISO 4217 3-character currency code. For example: USD, EUR.
#   CONVERSION_CUSTOM_VARIABLE: The name of the conversion custom variable.
#   CONVERSION_CUSTOM_VARIABLE_VALUE: The value of the conversion custom
#     variable.
curl -f --request POST \
"https://googleads.googleapis.com/v${API_VERSION}/customers/${CUSTOMER_ID}:uploadCallConversions" \
--header "Content-Type: application/json" \
--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \
--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \
--data @- <<EOF
{
  "conversions": [
    {
      "conversionAction": "${CONVERSION_ACTION_RESOURCE_NAME}",
      "callerId": "${CALLER_ID}",
      "callStartDateTime": "${CALL_START_DATE_TIME}",
      "conversionDateTime": "${CONVERSION_DATE_TIME}",
      "conversionValue": ${CONVERSION_VALUE},
      "currencyCode": "${CURRENCY_CODE}",
      "customVariables": [
        {
          "conversionCustomVariable": "${CONVERSION_CUSTOM_VARIABLE}",
          "value": "${CONVERSION_CUSTOM_VARIABLE_VALUE}"
        }
      ],
      "consent": {
        "adUserData": "GRANTED"
      }
    }

  ]
}
EOF