Periodically synching data from an API to database is extremely slow
Error handling

if response.status_code != 200:
    print('api response error: {}'.format(response))
    return


is better represented as a simple call to response.raise_for_status().

Also, this:

try:
    response_payload = response.json()
except ValueError:
    return


is dangerous. Silently failing should (at the least) be left up to the caller to decide whether an exception should be caught and swallowed, caught and printed, or allowed to fall through.

Tuple unpacking

for (key, value) in clients_data.items():


can be

for key, value in clients_data.items():


Undeclared variable

        if action == constants.SyncActions.CRT:
            result['new'] += 1
        if action == constants.SyncActions.UPD:
            result['update'] += 1


Where does result come from? You don't show this. Is it a defaultdict?

Incorrect default

hub_data['id'] = int(hub_data.get('client', ''))


will not work in the case that the key is missing. You can't convert '' to an int. Perhaps you meant:

hub_data['id'] = int(hub_data.get('client', '0'))


Ellipses

This is more of a meta-comment, but

# Set `is_active` based on the `archived` flag.
if client_data.get('archive', None) == '1':
    client_data['is_active'] = False
else:
    client_data['is_active'] = True
...


should show the ellipses as a comment to avoid breaking syntactical validity, and you should provide rationale as to why this code is elided. Eliding code harms the potential for you to receive a meaningful review.

Optimization


  How can I optimize it to perform better? 


It's nearly impossible to say. You haven't run a profiler, which you should; you've elided too much code for us to run this thing; you haven't shown any example data; and you haven't given us an API endpoint (or if that's not possible, at least a sample of a payload the endpoint would return).