Posting data submissions using the KOBO Rest API

Hi @ks_1, unfortunately submitting data with JSON can be unpredictable — I’m also battling. I would recommend rather using XML as that’s how we handle it on the backend. You can see how we handled submission duplication here.

It isn’t pretty, but I adapted what I did there to try and meet your current need. You’ll just need to adjust things to make it work for you and likely use Python’s xml.etree library as I did to programmatically update the xml tree. In this example I’ve just used the submission’s XML structure as a template (you can see that if you navigate to /api/v2/assets/{asset_uid}/data.xml)

You can give this a try:

import io
import requests
import uuid
from datetime import datetime

BASE_URL = 'https://kc.kobotoolbox.org'
SUMISSION_URL = f'{BASE_URL}/api/v1/submissions'
TOKEN = '<TOKEN>'

def format_openrosa_datetime():
    return datetime.now().isoformat('T', 'milliseconds')

def create_xml_submission(data, _uuid):
    return f'''
    <atewgEAX2sG2ibzvs6dTHV id="atewgEAX2sG2ibzvs6dTHV" version="1 (2021-03-25 18:06:48)">
        <formhub>
            <uuid>8db71a06863349c6abe8bb5edf6d4b4e</uuid>
        </formhub>
        <start>{format_openrosa_datetime()}</start>
        <end>{format_openrosa_datetime()}</end>
        <answer_me>{data}</answer_me>
        <__version__>vWG8dR5D2BhooJjhQ8zrqy</__version__>
        <meta>
            <instanceID>uuid:{_uuid}</instanceID>
        </meta>
    </atewgEAX2sG2ibzvs6dTHV>
    '''.encode()

def submit_data(data):
    _uuid = str(uuid.uuid4())
    file_tuple = (_uuid, io.BytesIO(create_xml_submission(data, _uuid)))
    files = {'xml_submission_file': file_tuple}
    headers = {'Authorization': f'Token {TOKEN}'}
    res = requests.Request(
        method='POST', url=SUMISSION_URL, files=files, headers=headers
    )
    session = requests.Session()
    res = session.send(res.prepare())

    if res.status_code == 201:
        return 'Success 🎉'
    return 'Something went wrong 😢'

if __name__ == '__main__':
    res = submit_data('hello world')
    print(res)

If you enter your token there it should send data to my form.

3 Likes