I've recently answered a number of questions about using the Sub-Item field via the API, so I thought that I would create a post here and share the information more broadly.
Sub-Item was left off of the list of fields that are documented on our developer site - my oversight! I'll add information there shortly, but I'll give you the basics here.
First, sub-items look like an embedded set of records - the field itself is an object that has an "items" array that holds the individual subitems. Here is an example (a snippet of python code):
# Sub-Item payload
payload = {
"title": "foo",
"sed28c82ae": {
"items": [
{
"name": "test",
"description": "test",
"date": { "date": "2023-12-26T00:00:00.000Z", "include_time": False },
"first_created": { "by": None, "on": "" },
"last_updated": { "by": None, "on": "" },
"id": "c98ff143dedb43d79077eaed"
},
{
"name": "test2_mod",
"description": "test2",
"date": { "date": "2023-12-26T00:00:00.000Z", "include_time": False },
"id": object_id_str
}
]
},
"id": "658aea5ff07cbda745758354"
}
A few things to note:
You need to give your sub-items an id. The Id should be in the format of an ObjectId - 24 hexadecimal characters: 12 bytes represented as a 24-character hexadecimal string. If you're using python, the easiest way to do this is to generate an actual objectId and use it:
from bson import ObjectId
# Generate a new ObjectId
new_object_id = ObjectId()
# Convert the ObjectId to a string
object_id_str = str(new_object_id)
Next important bit is that you need to include each sub-item when you update / add / remove items. You delete them by PATCHING the record and just dropping the target item from the array. Add new by appending to the array, and update by changing the properties of the target item, while leaving the same id value.
FYI we are changing the structure here soon - Sub-Items are going to be migrated to a structure that is like Linked Records. If there is the possibility of using a separate table and a Linked Records field instead of the Sub-Item, it may save you some update time when that change is made.
Here is a bit more python code that shows how sub-item fields and their values can be updated. It grabs the records from a table, looks for a specific sub-item, and increments a numeric field by 1. I've intentionally hard-coded the values so you can better see what's going on. Remember you also have to update the API key, account id, and the field slugs to make it work in your environment.
import requests
import json
table = "659ff7e0bbe6a9be8c320475"
headers = {
"Authorization": "Token YOUR_TOKEN",
"ACCOUNT-ID": "ACCOUNT_ID",
"Content-Type": "application/json"
}
def get_records():
url = f"https://app.smartsuite.com/api/v1/applications/{table}/records/list/?async=true&return_empty_response=true"
# Initialize the payload dictionary
payload = {}
try:
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200 or response.status_code == 201:
print("Got records successfully!")
data = response.json()
return data['items']
else:
print(f"Error sending payload. Status Code: {response.status_code}")
except Exception as e:
print(f"An error occurred: {str(e)}")
def update_record(id, payload):
url = f"https://app.smartsuite.com/api/v1/applications/{table}/records/{id}/"
try:
response = requests.patch(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200 or response.status_code == 201:
print(f"Updated record {id} successfully!")
else:
print(f"Error sending update payload. Status Code: {response.status_code}")
except Exception as e:
print(f"An error occurred: {str(e)}")
def process_subs():
records = get_records()
updated_subs = []
for record in records:
sub_item = record['sb291f748c']
for sub in sub_item['items']:
if sub['sc5116dd7c'] is not None:
num_value = int(sub['sc5116dd7c'])
num_value = num_value + 1
else:
num_value = 1
sub['sc5116dd7c'] = str(num_value)
updated_subs.append(sub)
update_payload = {
'sb291f748c': {
'items': updated_subs
},
'id': record['id']
}
print(json.dumps(update_payload))
update_record(record['id'], update_payload)
process_subs()
I hope that helps - please let me know if you have any questions!