Streaming live at 10am (PST)

Unable to Post to Collections: ValidationError: Invalid request body

Hello, I’m new to working with APIs and I’m having difficulty solving this error.

I’m using SQL Server to retrieve data and Python to post it to my collections in webflow
To test out the API process my collections only include two fields: Name and Slug.
This is how I format my resultset from SQL Server (results)

"fields": [
        "slug": "please",
        "name": "help",
        "_draft": "false",
        "_archived": "false"
        "slug": "im-going",
        "name": "crazy",
        "_draft": "false",
        "_archived": "false"

this is my python code

        'Authorization': 'Bearer <######>',
        'Accept-Version': '1.0.0',
        'Content-Type': 'application/json',
        'accept': 'application/json'
for myData in results:
    data = myData[0]
    r =

and here is the response I get

{'code': 400,
 'err': 'ValidationError: Invalid request body',
 'msg': 'Invalid request body',
 'name': 'ValidationError',
 'path': '/collections/5f3ff7d787584bc00a2beb1b/items'}

I feel like I have tried everything and I am wondering if i’m missing something in my JSON. The API documentation is not clear to me (a novice) in terms of what I need to pass to Webflow.

I have tried Zapier with success by connecting it to google sheets but that isn’t a method I want to use. I tried looking up the json behind it but I was unsuccessful. I tried adding the additional columns i saw returned form zapier but i still received the same error message when using python


Download postman and send your request to the API through Postman. If it comes back clean, your request is fine. Postman also does syntax highlighting and can help you structure your request. If, with postman, your request comes back with the same error, the issue is indeed in your request and you can grant your python code a pass.

From what I can see in your JSON, it seems to be a valid JSON. That leads me to believe that you are forgetting to include a required field with the request OR that you have the wrong datatype set for the request.

You can try your JSON body as different data types with postman. Give it a try. I believe it’s free.

Thank you for the reply. I decided to start from the beginning and use the curl example in the documentation and execute it through Postman. It turns out the json wasn’t properly formatted coming through from SQL Server. It also seems I can’t include multiple items in the same POST request so I had to iterate through each record

Here’s the code I used, hopefully it will save someone else a headache

import pyodbc
import requests
import pprint
import json
Webflow variables
bearer = '#####'
collection_id = '#####'
isLive = 'false'
webflow_api = ''
webflow_api_collections = webflow_api.replace(':collection_id',collection_id).replace(':isLive',isLive)
SQL Server Connection
connection = pyodbc.connect(
            'Driver={SQL Server};'
with connection.cursor() as cursor:
qryJsonOutput = ("SELECT * FROM [SCHEMA].[VIEW_NAME] FOR JSON PATH, ROOT('webflow');")
jResults = cursor.fetchall()
api header parameters
    'Authorization': 'Bearer ' + bearer,
    'Accept-Version': '1.0.0',
    'Content-Type': 'application/json'
POST new items to Collection
for row in jResults:
myData = json.loads(row[0])
for data in myData['webflow']:
    r = requests.request("POST", 

My Sql Server view

    SELECT  slug AS [fields.slug]
            , name AS []
            , 'false' AS [fields._draft]
            , 'false' AS [fields._archived]
    FROM    dbo.my_tableName;

I’m using Python 3.8 and SQL Server 2017

1 Like

For future reference, just stringify your body then pass it separately:

let body = JSON.stringify({
                "fields": {
                    "_draft": Boolean(false),
                    "_archived": Boolean(false),
                    "album": albumName,
                    "artist": artistName,
                    "small-album": albumCoverSmall,
                    "medium-album": albumCoverMedium,
                    "large-album": albumCoverBig,
                    "extra-large-album": albumCoverXl,
                    "position": i,
                    "name": track

Then when you do your request you can pass the body separately.

      let postChart = await fetch("<your collection id>/items?live=true",  {
                "method": "POST",
                "headers": {
                    "Authorization": "Bearer <your key>",
                    "accept-version": "1.0.0",
                    "Content-Type": "application/json; charset=utf-8",
                "body": body