Mark task done with REST API

I have on a python script that displays my Vikunja tasks in my ubuntu system tray (GitFr33 / What Am I Doing · GitLab)

It’s working well to fetch tasks from the API but I am failing to mark a task as done with the following request:

headers = {"Authorization": "Bearer "+auth.vikunja['token']}
data = {'done': True}
response ="api/v1/tasks/"+str(task['id']), data=data, headers=headers)

I get the following response and the task does not get marked as done. (Oddly, it does get removed from my favourites.)

{'id': 225, 'title': 'task indicator', 'description': '', 'done': False, 'done_at': '0001-01-01T00:00:00Z', 'due_date': '0001-01-01T00:00:00Z', 'reminders': None, 'project_id': 30, 'repeat_after': 0, 'repeat_mode': 0, 'priority': 0, 'start_date': '0001-01-01T00:00:00Z', 'end_date': '0001-01-01T00:00:00Z', 'assignees': [], 'labels': None, 'hex_color': '', 'percent_done': 0, 'identifier': '', 'index': 15, 'related_tasks': None, 'attachments': None, 'cover_image_attachment_id': 0, 'is_favorite': False, 'created': '0001-01-01T00:00:00Z', 'updated': '2024-06-05T00:22:37Z', 'bucket_id': 48, 'position': 171798691.84, 'kanban_position': 171798691.84, 'created_by': None}

What am I missing?

Due to the way Go’s nil types work, there is no way to tell if a value was reset intentionally or left out. To work around this, Vikunja fetches the full task from the database and overrides it with the existing data when not all values were provided. I guess this causes the problem in your case.
Does it work if you pass the whole task to the api? At least that’s what the frontend does.

Thank you for getting back to me about this @kolaente!

I tried fetching, modifying, and sending the full task but I’m still not having success.

Here is my python script and output:

    # get
    data = requests.get(conf.todolist_uri+"api/v1/tasks/"+str(task['id']), headers=headers).json()

    # modify   
    data['done'] = True
    # I also tried data['done'] = 'True' and data['done'] = 1

    print("Modified task data")

    # send
    response ="api/v1/tasks/"+str(task['id']), data=data, headers=headers)





And output is as follows:

Modified task data
{'id': 250, 'title': 'Test Task', 'description': '', 'done': True, 'done_at': '0001-01-01T00:00:00Z', 'due_date': '0001-01-01T00:00:00Z', 'reminders': None, 'project_id': 30, 'repeat_after': 0, 'repeat_mode': 0, 'priority': 0, 'start_date': '0001-01-01T00:00:00Z', 'end_date': '0001-01-01T00:00:00Z', 'assignees': None, 'labels': None, 'hex_color': '', 'percent_done': 0, 'identifier': '#14', 'index': 14, 'related_tasks': {}, 'attachments': None, 'cover_image_attachment_id': 0, 'is_favorite': True, 'created': '2024-06-02T03:47:04Z', 'updated': '2024-06-05T18:34:55Z', 'bucket_id': 48, 'position': 148102320.55172414, 'kanban_position': 148102320.55172414, 'created_by': {'id': 1, 'name': 'FM', 'username': 'FM', 'created': '2023-01-24T20:33:58Z', 'updated': '2024-02-21T22:24:34Z'}}




{'id': 250, 'title': 'Test Task', 'description': '', 'done': False, 'done_at': '0001-01-01T00:00:00Z', 'due_date': '0001-01-01T00:00:00Z', 'reminders': None, 'project_id': 30, 'repeat_after': 0, 'repeat_mode': 0, 'priority': 0, 'start_date': '0001-01-01T00:00:00Z', 'end_date': '0001-01-01T00:00:00Z', 'assignees': [], 'labels': None, 'hex_color': '', 'percent_done': 0, 'identifier': '', 'index': 14, 'related_tasks': None, 'attachments': None, 'cover_image_attachment_id': 0, 'is_favorite': False, 'created': '0001-01-01T00:00:00Z', 'updated': '2024-06-05T18:35:04Z', 'bucket_id': 48, 'position': 148102320.55172414, 'kanban_position': 148102320.55172414, 'created_by': None}

Any insight about what I’m doing wrong or how to diagnose the issue further?


In your example it looks like you don’t modify the fetched task?

Good point! I’m sorry. I scrambled the python script cut and paste (corrected now). (The print of the modified data shows 'done': True)

One thing I noticed in the meantime is that the created_by value seems to have been getting scrambled in the request which may be causing the problem. I’ll report back once I’ve tested further.

Heres the python code snippet that is relevant to this that I use:

    head = {'Authorization': 'Bearer {}'.format(API_KEY)}    
    headers = {'content-type': 'application/json'}    
    data = {'done': True,}
    response =,json=data, headers=head)

1 Like

Thanks @Grim73!

I don’t exactly understand what the difference is (something related to the json encoding it seems) but your snippet works perfectly!

I have no idea what the difference is either, Stack Overflow helped me with this :joy::clinking_glasses:glad to have helped

1 Like

The difference is that you’re using requests data parameter. When sending a POST request and specifying data, request will Form encode (as in: content type set to application/x-www-form-urlencoded). The input is a dict, this will just map the content of the dict to form fields.

When sending data with the json= parameter, it will be - you guessed correctly - sent as plain JSON in the request body, which is what Vikunja expects. Don’t use data unless you want to submit form data :slight_smile: