Skip to main content

Hi all!

One quick questions about a thing I’m trying to do in Django Python: I’m setting up a signal that creates/updates the user data to Klaviyo when the user is created/updated.

I tried to do the same via http requests in the same environment (same key, same objects) and it all works.

When trying with the Python API, it returns an unathorized error (401). I troubleshooted the issue checking:

  • that the key has both the string and the key, it has
  • that the key has the correct permissions, it has

At this point I’m out of all ideas. I’m afraid something is missing from my code, but as far as I saw on the guides on GitHub I cannot find the missing element.

My code is this:

from django.conf import settings
from klaviyo_api import KlaviyoAPI

import pprint
import traceback

private_key = settings.KLAVIYO_PRIVATE_KEY
klaviyo = KlaviyoAPI(api_key=private_key, max_delay=5, max_retries=3)

def create_update_profile(user):
payload = {
"data": {
"type": "profile",
"attributes": {
"email": user.email,
"phone_number": user.prefix + user.phone,
"external_id": str(user.id),
"first_name": user.first_name,
"last_name": user.last_name,
"location": {
"address1": user.address,
"city": user.city,
"country": "Italy",
"region": user.province,
"zip": user.zipCode,
"timezone": "Europe/Rome"
},
"properties": {
"Gender": user.gender,
"Birthday": user.birthday.strftime('%Y-%m-%d')
}
}
}
}

try:
k_profile = klaviyo.Profiles.create_or_update_profile(payload)
pprint(f'Job done: {k_profile}')
return k_profile

except Exception as e:
pprint.pprint(e)
traceback.print_exc()
return None

And this is the error:

openapi_client.exceptions.UnauthorizedException: (401)
Reason: Unauthorized
HTTP response headers: HTTPHeaderDict({'Date': 'Mon, 30 Sep 2024 09:07:41 GMT', 'Content-Type': 'application/vnd.api+json', 'Content-Length': '264', 'Connection': 'keep-alive', 'CF-Ray': '8cb31067ca4dbabe-MXP', 'CF-Cache-Status': 'DYNAMIC', 'Allow': 'POST, OPTIONS', 'Content-Language': 'en-us', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'Vary': 'Accept-Language, Cookie, Accept-Encoding', 'WWW-Authenticate': 'Bearer, Klaviyo-API-Key', 'Content-Security-Policy': "script-src 'report-sample' 'strict-dynamic' 'unsafe-eval'; object-src 'none'; base-uri 'none'; frame-ancestors 'self' login.bigcommerce.com *.mybigcommerce.com admin.shopify.com klaviyo.file.force.com klaviyo.lightning.force.com klaviyo.my.salesforce.com; report-uri /csp/", 'X-Content-Type-Options': 'nosniff', 'X-Robots-Tag': 'noindex, nofollow', 'Server': 'cloudflare'})
HTTP response body: errors=yGetAccounts4XXResponseErrorsInner(id='e8249737-283b-4db2-b1b1-fa324fe71f02', code='not_authenticated', title='Authentication credentials were not provided.', detail='Missing or invalid authorization scheme. Please use Klaviyo-API-Key.', source=GetAccounts4XXResponseErrorsInnerSource(pointer='/data/', parameter=None))]

Can any of you help me out on this?

Thank you in advance!

Federico

Hi @federico.vitale 

The error indicates that there is a missing or invalid key passed in the authorization header in the request initiated by the Klaviyo python client

1. please tell us what version of the python klaviyo API client you are using
2. please try running this exact same operation creating a test user with the client in a script outside of django and set the API key manually to make sure there isn't an issue with django settings resolution
3. please print the value of `settings.KLAVIYO_PRIVATE_KEY` in your example and verify it is set with the expected private key

~Chloe


Hi @chloe.strange!

Thanks for getting back to me. Going through your list:

please tell us what version of the python klaviyo API client you are using

federicovitale@MacBook-Pro-di-Federico ~ % pip3 show klaviyo-api
Name: klaviyo-api
Version: 13.0.0
Summary: Klaviyo Python SDK
Home-page: https://github.com/klaviyo/klaviyo-api-python
Author: Klaviyo Developers
Author-email: developers@klaviyo.com
License: UNKNOWN
Location: /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages
Requires: aenum, pydantic, python-dateutil, setuptools, tenacity, urllib3
Required-by:

2. please try running this exact same operation creating a test user with the client in a script outside of django and set the API key manually to make sure there isn't an issue with django settings resolution

3. please print the value of `settings.KLAVIYO_PRIVATE_KEY` in your example and verify it is set with the expected private key

I ran a script directly on the Python IDE, also outside any virtual environment (the key is redacted here but not when I ran the script):

from klaviyo_api import KlaviyoAPI
import pprint
import traceback

private_key = 'Klaviyo-API-Key pk_0bc882e60f0b6c97975e27383c68e*****'

klaviyo = KlaviyoAPI(api_key=private_key)

payload = {
"data": {
"type": "profile",
"attributes": {
"email": "federico@test.test",
"first_name": "Federico",
"last_name": "Vitale",
"properties": {
"Gender": "Male",
"Birthday": "1987-09-21"
}
}
}
}

try:
k_profile = klaviyo.Profiles.create_or_update_profile(payload)
pprint(k_profile)

except Exception as e:
pprint.pprint(e)
traceback.print_exc()

Here the result:

UnauthorizedException()
Traceback (most recent call last):
File "/Users/federicovitale/Desktop/Test_klaviyo.py", line 25, in <module>
k_profile = klaviyo.Profiles.create_or_update_profile(payload)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/klaviyo_api/wrapper.py", line 441, in _wrapped_func
return func(*args,**kwargs)
^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tenacity/__init__.py", line 336, in wrapped_f
return copy(f, *args, **kw)
^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tenacity/__init__.py", line 475, in __call__
do = self.iter(retry_state=retry_state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tenacity/__init__.py", line 376, in iter
result = action(retry_state)
^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tenacity/__init__.py", line 398, in <lambda>
self._add_action_func(lambda rs: rs.outcome.result())
^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 449, in result
return self.__get_result()
^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
raise self._exception
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tenacity/__init__.py", line 478, in __call__
result = fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pydantic/validate_call_decorator.py", line 60, in wrapper_function
return validate_call_wrapper(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pydantic/_internal/_validate_call.py", line 96, in __call__
res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/openapi_client/api/profiles_api.py", line 149, in create_or_update_profile
return self.api_client.response_deserialize(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/openapi_client/api_client.py", line 328, in response_deserialize
raise ApiException.from_response(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/openapi_client/exceptions.py", line 146, in from_response
raise UnauthorizedException(http_resp=http_resp, body=body, data=data)
openapi_client.exceptions.UnauthorizedException: (401)
Reason: Unauthorized
HTTP response headers: HTTPHeaderDict({'Date': 'Thu, 03 Oct 2024 16:02:47 GMT', 'Content-Type': 'application/vnd.api+json', 'Content-Length': '264', 'Connection': 'keep-alive', 'CF-Ray': '8cce2895ca37bad0-MXP', 'CF-Cache-Status': 'DYNAMIC', 'Allow': 'POST, OPTIONS', 'Content-Language': 'en-us', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'Vary': 'Accept-Language, Cookie, Accept-Encoding', 'WWW-Authenticate': 'Bearer, Klaviyo-API-Key', 'Content-Security-Policy': "object-src 'none'; frame-ancestors 'self' login.bigcommerce.com *.mybigcommerce.com admin.shopify.com klaviyo.file.force.com klaviyo.lightning.force.com klaviyo.my.salesforce.com; base-uri 'none'; script-src 'report-sample' 'strict-dynamic' 'unsafe-eval'; report-uri /csp/", 'X-Content-Type-Options': 'nosniff', 'X-Robots-Tag': 'noindex, nofollow', 'Server': 'cloudflare'})
HTTP response body: errors=[GetAccounts4XXResponseErrorsInner(id='35b6281d-9f4c-465e-94aa-09543e5b892d', code='not_authenticated', title='Authentication credentials were not provided.', detail='Missing or invalid authorization scheme. Please use Klaviyo-API-Key.', source=GetAccounts4XXResponseErrorsInnerSource(pointer='/data/', parameter=None))]

Thank you again for any assistance!


Hi @federico.vitale

You have the following:
private_key = 'Klaviyo-API-Key pk_0bc882e60f0b6c97975e27383c68e*****'

Please try the following - note that it does not include the Klaviyo-API-Key prefix:
private_key = pk_0bc882e60f0b6c97975e27383c68e*****

If you were doing a raw http request, then this would be in the header but the client is expecting an API key without the prefix
Authorization: Klaviyo-API-Key your-private-api-key'

~Chloe 


@chloe.strange, thank you so much!!! It works!


Reply