Phase 2 Update a Contact API

Greetings, I received good help with the syntax needed to successfully use the /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId} API, to add a new contact HERE: 400 Bad Request api_instance.post_outbound_contactlist_contacts - #18 by Jerome.Saint-Marc.

Now I could use help updating existing contacts. When I create my initial contact list (logged into Genesys GUI side) I select to use one of my columns as the unique identifier under the advance settings. I would like to now key off that identifier to update data on existing contacts such as updating new hire start dates. So far all I can do using my code is cause duplicate new contacts to be created despite my unique identifiers matching. (Please reference the above URL to see the detailed code being used.) I've tried both the POST and PUT APIs for updating contacts.

My question is, how do I need to modify my existing code (from the linked discussion) to execute an update to an existing contact, using my custom unique identifier?

Thanks!

Hi @mhanna77
Are you able to get the contact back with GET /api/v2/externalcontacts/contacts/{contactId} using that same ID? In my experience the contactId query param and id field should be the same.
I suggest using that GET request first, then using the response as a basis to construct the PUT request, then update fields as needed. The PUT replaces the entire contact, so you provide all the fields that will be present in the updated contact.
I'm curious if the duplication still happens using this method.
Another thing you can try, is go to your external contacts in the Genesys Cloud app with the Chrome browser and try updating a contact with the Chrome DevTools open. Then open the "network" tab and inspect the payload for the PUT /api/v2/externalcontacts/contacts/{contactId} request. If it was successful, you can take any pointers from how that request is constructed.

Excellent, I will try these suggestions and report back, thank you.

Are you able to get the contact back with GET /api/v2/externalcontacts/contacts/{contactId} using that same ID? Yes I can, FYI the API I need to use is GET /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId}
. In my experience the contactId query param and id field should be the same.
I suggest using that GET request first, then using the response as a basis to construct the PUT request, then update fields as needed. The PUT replaces the entire contact, so you provide all the fields that will be present in the updated contact.
I'm curious if the duplication still happens using this method. The PUT API explorer woks well, no duplicates
Another thing you can try, is go to your external contacts in the Genesys Cloud app with the Chrome browser and try updating a contact with the Chrome DevTools open. Then open the "network" tab and inspect the payload for the PUT /api/v2/externalcontacts/contacts/{contactId} request. FYI The API I need to use here is PUT /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId} If it was successful, you can take any pointers from how that request is constructed. The DevTools didn't provide anything the API Explorer wasn't already from what I could find.

I don't think I can attach so I'll post my code, hoping someone can help me out and figure out why I'm getting "HTTP response body: {"message":"The request could not be understood by the server due to malformed syntax.","code":"bad.request","status":400" I'm using the PUT /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId}

import PureCloudPlatformClientV2
from PureCloudPlatformClientV2.rest import ApiException
from pprint import pprint
import requests
import os

print("-------------------------------------------------------")
print("- Contact List Contact Update -")
print("-------------------------------------------------------")

GENESYS_CLOUD_CLIENT_ID = 'MY STUFF GOES HERE'
GENESYS_CLOUD_CLIENT_SECRET = 'MY STUFF GOES HERE'

PureCloudPlatformClientV2.configuration.host = 'MY STUFF GOES HERE'

apiclient = PureCloudPlatformClientV2.api_client.ApiClient().get_client_credentials_token(GENESYS_CLOUD_CLIENT_ID,
GENESYS_CLOUD_CLIENT_SECRET)

api_instance = PureCloudPlatformClientV2.OutboundApi(apiclient);
contact_list_id = '32298f99-d4d2-4a02-837b-016a8900740c'
contact_id = '123456789'

body = []
contact_data = PureCloudPlatformClientV2.WritableDialerContact()
contact_data.contact_list_id = contact_list_id
contact_data.contact_id = contact_id
contact_data.data = {}
contact_data.data['Clearance Status'] = 'contact_data API'
contact_data.data['Patient ID'] = '777777777'
contact_data.data['Last Name'] = 'Zztest'
contact_data.data['First Name'] = 'Betsy'
contact_data.data['WD ID'] = '777777'
contact_data.data['SSN'] = '123456789'
contact_data.data['Home Phone'] = '15135551212'
contact_data.data['DOB'] = '6/6/1988'
contact_data.data['Gender'] = 'm'
contact_data.data['Cell Phone'] = '15135551313'
contact_data.data['Email'] = 'betsy.zztest@chocolatemail.com'
contact_data.data['Company ID'] = '3501'
contact_data.data['Job Title'] = 'Nurse Practitioner'
contact_data.data['Hire Date'] = '5/21/2024'
contact_data.data['Tier'] = 'Tier 2'
contact_data.data['Market'] = 'Cincinnasty'
contact_data.data['Zip'] = '45241'
contact_data.callable = True
contact_data.phone_number_status = {}
contact_data.phone_number_status['Home Phone'] = PureCloudPlatformClientV2.PhoneNumberStatus()
contact_data.phone_number_status['Home Phone'].callable = True
contact_data.phone_number_status['Cell Phone'] = PureCloudPlatformClientV2.PhoneNumberStatus()
contact_data.phone_number_status['Cell Phone'].callable = True
contact_data.contactable_status = {}
contact_data.contactable_status['Email'] = PureCloudPlatformClientV2.ContactableStatus()
contact_data.contactable_status['Email'].contactable = True
body.append(contact_data);

try:
# Update a contact.
api_response = api_instance.put_outbound_contactlist_contact(contact_list_id, contact_id, body)
pprint(api_response)
except ApiException as e:
print("Exception when calling OutboundApi->put_outbound_contactlist_contact: %s\n" % e)

PureCloudPlatformClientV2.configuration.logger.log_level = PureCloudPlatformClientV2.logger.LogLevel.LDebug
PureCloudPlatformClientV2.configuration.logger.log_request_body = True
PureCloudPlatformClientV2.configuration.logger.log_response_body = True
PureCloudPlatformClientV2.configuration.logger.log_format = PureCloudPlatformClientV2.logger.LogFormat.TEXT
PureCloudPlatformClientV2.configuration.logger.log_to_console = False
PureCloudPlatformClientV2.configuration.logger.log_file_path = "C:/PerfLogs/pythonsdk.log"

I'm still looking for help figuring out what the body of the code needs to be. The Genesys API Explorer tool does not provide a Python example of the body even upon successful submission of a call, so it's extremely difficult to know what the formatting should be. I have opened an "idea" and there is another similar idea submission out there now for this enhancement. Genesys Cloud Ideas Portal and Genesys Cloud Ideas Portal.

For now, I would love to see a Python example of code that can successfully use the PUT /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId} API

Thanks!

Per PUT /api/v2/outbound/contactlists/{contactListId}/contacts/{contactId} and put_outbound_contactlist_contact, the request body is a single object, not an array of objects. You should also use the documented request body type for that function, which is DialerContact.

I haven't been trying to update via an object array style, but rather a single object list style.

  1. The API notes do state: " data (Map<string, string> required) An ordered map of the contact's columns and corresponding values."

So do I need to include all the columns, even though I'm only trying to update one value?

  1. This is the extent of the body example from the API explorer: body = PureCloudPlatformClientV2.DialerContact() # DialerContact | Contact

Where can I look to find a functional example of what the formatting needs to be? Or maybe a better question is, if JSON is the only provided formatting, how do I convert that to functional Python?

Thanks

I wasn't referring to the data property within the body, I'm referring to the body itself. In the code I quoted above, you've declared the body variable as an array, which is incorrect for the resource.

Yes. A PUT is a replacement operation. You can read more about how a PUT operation is expected to behave here: PUT - HTTP | MDN.

You can find the documentation for this method in Python SDK in my previous reply. This documents the function itself and links to the model schema for the request body it accepts. If you click that link for DialerContact, you'll see the documentation for each property including its name, type, description, and whether or not it's an optional property. If the property is a complex type, it will link to the model documentation for that type.

If you don't know how to write Python code that sets values for the documented properties, I would suggest sites like stack overflow or udemy for guidance with learning the basics of Python. That kind of general programming assistance is beyond the scope of this forum. Genesys Professional Services can also be engaged to write it for you or provide 1 on 1 consulting to walk you through it. There are some general code examples on github for reference, but I don't think there's anything you can copy/paste for this exact endpoint. GitHub - MyPureCloud/quick-hits-python.

Hi @tim.smith I'm not seeing a Python SDK link to the DialerContact schema, I'd love to take a look if you could share that. Current state using my PUT call, I'm having a successful return of the current contact's data. The code is failing to update any data, but it's pulling everything for that contact....

Hello,

You can find the Python SDK documentation here.

The description of the DialerContact class/schema is here: https://developer.genesys.cloud/devapps/sdk/docexplorer/purecloudpython/DialerContact

Regards,

Jerome dropped the direct links, but to help you understand how to navigate the docs, click the previous link:

Which takes you to a section that looks like this:

If you look in the Parameters section, it lists a parameter for body, which has a link to the DialerContact type.

Additionally, if you know the type you want to look for, you can type it in the filter and navigate to it directly:

Thank you, I had not run across that resource for the schema properties! When I execute my code, what returns is all the current data for the contact and it is inclusive of every property listed out in the DialerContact link you just provided. Where I'm failing is to successfully execute an update to that data. Here's what is returning now: {'call_records': {'Cell Phone': {'last_attempt': datetime.datetime(2024, 5, 24, 20, 29, 24, 997000, tzinfo=tzutc()),
'last_result': 'ININ-OUTBOUND-PREVIEW-SKIPPED'},
'Home Phone': {'last_attempt': datetime.datetime(2024, 5, 24, 20, 29, 24, 997000, tzinfo=tzutc()),
'last_result': 'ININ-OUTBOUND-PREVIEW-SKIPPED'}},
'callable': True,
'configuration_overrides': None,
'contact_column_time_zones': {'Cell Phone': {'column_type': 'PHONE',
'time_zone': 'EST5EDT'},
'Home Phone': {'column_type': 'PHONE',
'time_zone': 'EST5EDT'},
'Zip': {'column_type': 'ZIP',
'time_zone': 'EST5EDT'}},
'contact_list_id': '32298f99-d4d2-4a02-837b-016a8900740c',
'contactable_status': {'Email': {'column_status': {'Email': {'contactable': True}},
'contactable': True}},
'data': {'Cell Phone': '1513515xxxx',
'Clearance Status': '1st voice attempt',
'Company ID': '2222',
'DOB': '4/5/1900',
'Email': 'mrpibb@drpepper.com',
'First Name': 'Samwise',
'Gender': 'M',
'Hire Date': '5/26/2024',
'Home Phone': '15135555555',
'Job Title': 'Physician Asst CONTRACT',
'Last Name': 'Gamgee',
'Market': 'Springfield',
'Patient ID': '',
'SSN': '111111111',
'Tier': '',
'WD ID': '333333',
'Zip': '43230'},
'id': 'xxxxxxxxxxxx',
'latest_email_evaluations': None,
'latest_sms_evaluations': {'Cell Phone': {'contact_address': '15135555555',
'contact_column': 'Cell Phone',
'message_type': 'Sms',
'timestamp': datetime.datetime(2024, 5, 24, 18, 19, 52, 592000, tzinfo=tzutc()),
'wrapup_code_id': 'OUTBOUND-INVALID-PHONE-NUMBER'}},
'name': None,
'phone_number_status': {'Cell Phone': {'callable': True},
'Home Phone': {'callable': True}},
'self_uri': '/api/v2/outbound/contactlists/32298f99-d4d2-4a02-837b-016a8900740c/contacts/xxxxxxxxxxx'}

Process finished with exit code 0

Hello,

I don't do much python. But the following works.

try:
    api_instance = PureCloudPlatformClientV2.OutboundApi(apiclient);
    contact_list_id = 'YOUR_CONTACT_LIST_ID'
    contact_id = 'YOUR_CONTACT_ID'
    api_response_get = api_instance.get_outbound_contactlist_contact(contact_list_id, contact_id)
    pprint(api_response_get)
    new_hire_date = {'Hire Date':'5/21/2024'}
    api_response_get.data.update(new_customer_type)
    api_response_update = api_instance.put_outbound_contactlist_contact(contact_list_id, contact_id, api_response_get)
    pprint(api_response_update)

You get your contact first (api_response_get = api_instance.get_outbound_contactlist_contact(contact_list_id, contact_id)).
Then, you can modify the response directly to change the field you want. And use this as the body of your update request (api_response_update = api_instance.put_outbound_contactlist_contact(contact_list_id, contact_id, api_response_get)).

Regards,

My friend you're a genius! I've taken your example and used it to update one data point for my existing contact and further modified it to update multiple data points for an existing contact. That example is what's missing from the resource documentation. I imagine your team doesn't have time to create working Python examples for every API, but man would it be powerful for the community if you could. Thanks again, super job!!

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.