Thanks for Anash's good advice. Now the code of removing keywords look better without needing to use fake matchtype or keyword text.
Unfortunately, the INVALID_ID errors still occur. And I made sure that the items in each message sent is no more than 500. And apparently the rate of failing to remove keywords became a bit lower. I wonder how other AdWords client programmers had encountered such error. The items are generated from reading some local database tables with GoogleAdGroupID and GoogleKeywordID previously recorded, and sometimes AdWords complained 1 to 10 records out of 2000 records in a batch has INVALID_ID (keywordID). public static bool RemoveKeywords(IEnumerable<KeywordBaseItem> items) { if (items == null) return true; if (items.Count() == 0) return true; Trace.TraceInformation("Ready to delete {0} keywords...", items.Count()); List<AdGroupCriterionOperation> operations = new List<AdGroupCriterionOperation>(items.Count()); foreach (KeywordBaseItem item in items) { Criterion keyword = new Criterion(); keyword.id = item.GoogleId; keyword.idSpecified = true; BiddableAdGroupCriterion keywordCriterion = new BiddableAdGroupCriterion(); keywordCriterion.criterion = keyword; keywordCriterion.adGroupId = item.GoogleAdGroupId; keywordCriterion.adGroupIdSpecified = true; AdGroupCriterionOperation operation = new AdGroupCriterionOperation(); operati...@operator = Operator.REMOVE; operation.operatorSpecified = true; operation.operand = keywordCriterion; operations.Add(operation); } bool finalResult = false; try { AdGroupCriterionService adGroupCriterionService = (AdGroupCriterionService)GlobalSettings.Default.CurrentUser.GetService(AdWordsService.v200909.AdGroupCriterionService); GlobalSettings.Default.APIUnitCostsOfCurrentCampaignOfSession += GlobalSettings.Default.CurrentUser.GetUnitsForLastOperation();// operations.Count * APIUnitCostsTable.AdGroupCriterion_Remove; AdGroupCriterionReturnValue result = adGroupCriterionService.mutate( operations.ToArray()); if (result != null && result.value != null) { foreach (AdGroupCriterion adGroupCriterion in result.value) { Trace.TraceInformation("Ad group criterion with ad group id = '{0}, criterion id = '{1} " + "and type = '{2}' was deleted.", adGroupCriterion.adGroupId, adGroupCriterion.criterion.id, adGroupCriterion.criterion.CriterionType); } } else { Trace.TraceWarning("No ad group criteria were deleted.\n"); } return true; } catch (AdWordsApiException ex) { ApiException e = ex.ApiException as ApiException; foreach (ApiError error in e.errors) { EntityNotFound entityError = error as EntityNotFound; if (entityError != null) { Trace.TraceWarning("When RemoveKeywords: Exception says \"{0}\". The trigger {1} in campaign {2} is in {3}. Reason: {4}", entityError.reason.ToString(), entityError.trigger, GlobalSettings.Default.CurrentCampaignName, error.fieldPath, entityError.reason); continue; } Trace.TraceWarning("When RemoveKeywords: Exception says \"{0}\". The cause in campaign {1} is in {2}.", error.ToString(), GlobalSettings.Default.CurrentCampaignName, error.fieldPath); finalResult = false; } } return finalResult; } -- =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ Also find us on our blog and discussion group: http://adwordsapi.blogspot.com http://groups.google.com/group/adwords-api =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ You received this message because you are subscribed to the Google Groups "AdWords API Forum" group. To post to this group, send email to adwords-api@googlegroups.com To unsubscribe from this group, send email to adwords-api+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/adwords-api?hl=en