Search code examples
rresthttr

httr POST request with auth token in body


I am looking to POST an array to create a new profile in an email service provider via their API via the httr package. The API documenation can be found here.

A copy and paste of the curl command provided via the documentation works, but my implementations are throwing 403. The key was replaced for the purpose of posting here.

I am really struggling to determine the issue. I'm fairly new to API calls, especially POST and feel there's a core concept I'm missing.

My attempt:

identify_body <- '{
  "token" : "public_key_goes_here",
  "properties" : {
    "$email" : "thomas.jefferson@klaviyo.com",
    "$first_name" : "Thomas",
    "$last_name" : "Jefferson",
    "Plan" : "Premium",
    "SignUpDate" : "2016-05-01 10:10:00"
  }
}'

httr::POST("https://a.klaviyo.com/api/identify",
           body = identify_body, 
           content_type_json(), 
           verbose())

Results:

-> POST /api/identify HTTP/1.1
-> Host: a.klaviyo.com
-> User-Agent: libcurl/7.59.0 r-curl/3.3 httr/1.4.0
-> Accept-Encoding: gzip, deflate
-> Accept: application/json, text/xml, application/xml, */*
-> Content-Type: application/json
-> Content-Length: 222
-> 
>> {
>>   "token" : "public_key_goes_here",
>>   "properties" : {
>>     "$email" : "thomas.jefferson@klaviyo.com",
>>     "$first_name" : "Thomas",
>>     "$last_name" : "Jefferson",
>>     "Plan" : "Premium",
>>     "SignUpDate" : "2016-05-01 10:10:00"
>>   }
>> }

<- HTTP/1.1 403 Forbidden
<- Content-Encoding: gzip
<- Content-Type: text/html
<- Date: Mon, 04 Jan 2021 22:02:12 GMT
<- Server: nginx
<- Vary: Accept-Encoding
<- Vary: Cookie
<- Content-Length: 779
<- Connection: keep-alive
<- 
Response [https://a.klaviyo.com/api/identify]
  Date: 2021-01-04 22:02
  Status: 403
  Content-Type: text/html
  Size: 1.46 kB

<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta name="robots" content="NONE,NOARCHIVE">
  <title>403 Forbidden</title>
  <style type="text/css">
    html * { padding:0; margin:0; }
    body * { padding:10px 20px; }

Solution

  • From the docs

    The Server-Side APIs use the same request and response formats. Requests are made with a GET request to the specified endpoint with a single parameter, data, which is a JSON object that has been base64 and URL encoded

    You need to convert the request to a GET request and convert the JSON to a base64 / URL encoded string and pass as a query param called data.

    Or you could use one of their helper libraries that they have provided.