--- title: todo.sr.ht API reference --- The todo.sr.ht API allows you to browse, create, and manage repositories on todo.sr.ht programmatically. This API follows the [standard sourcehut API conventions](../api-conventions.md). ## Authentication Authentication is done via the [meta.sr.ht OAuth flow](https://man.sr.ht/meta.sr.ht/oauth-api.md). The following OAuth scopes are available for todo.sr.ht: - **events:read**: read ticket events - **trackers:read**, **trackers:write**: read & write tracker details - **tickets:read**, **tickets:write**: read & write tickets & comments ## Resources ### Comment resource ```json { "id": integer, "created": "timestamp", "submitter": { short-form user resource }, "text": "string (markdown)", "ticket" { short-form ticket resoruce } } ``` Short form: ```json { "id": integer, "created": "timestamp", "submitter": { short-form user resource }, "text": "string (markdown)" } ``` ### Event resource ```json { "id": integer, "created": "timestamp", "event_type": [ ...list of event types... ], "old_status": status or null, "old_resolution": resolution or null, "new_status": status or null, "new_resolution": resolution or null, "user": { short-form user resource } or null, "ticket": { short-form ticket resource } or null, "comment": { short-form comment resource } or null, "label": [ ...list of strings... ] or null, "by_user": { short-form user resource } or null, "from_ticket": { short-form ticket resource } or null } ``` **Event type** may be one or more of created, comment, status_change, label_added, label_removed, assigned_user, unassigned_user, user_mentioned, or ticket_mentioned. **Status** fields may be one of reported, confirmed, in_progress, pending, or resolved. **Resolution** fields may be one of unresolved, fixed, implemented, wont_fix, by_design, invalid, duplicate, or not_our_bug. The by_user and from_ticket features are used for events where a ticket or user was mentioned in a comment somewhere. The ticket field and user field are set to the mentioned ticket or user, and the by_user or from_ticket field are set according to the discussion where the mention occured. ### Label resource ```json { "name": "string", "created": "timestamp", "colors": { "background": "#rrggbb", "text": "#rrggbb" }, "tracker": { short-form tracker resource } } ``` Short form: ```json { "name": "string", "colors": { "background": "#rrggbb", "text": "#rrggbb" } } ``` ### Ticket resource ```json { "id": integer, "ref": "string", "tracker": { short-form tracker resource }, "title": "ticket subject", "created": "timestamp", "updated": "timestamp", "submitter": { short-form user resource }, "description": "string (markdown)", "status": status, "resolution": resolution, "permissions": { "anonymous": [ ...list of strings... ] or null, "submitter": [ ...list of strings... ] or null, "user": [ ...list of strings... ] or null, }, "labels": [ ...list of label names... ], "assignees": [ ...list of short-form user resources... ] } ``` **Status** fields may be one of reported, confirmed, in_progress, pending, or resolved. **Resolution** fields may be one of unresolved, fixed, implemented, wont_fix, by_design, invalid, duplicate, or not_our_bug. **Permissions** may be one or more of browse, submit, comment, edit, and triage. If null, the permissions are inherited from the tracker. Short form: ```json { "id": integer, "ref": "string", "tracker": { short-form tracker resource } } ``` ### Tracker resource ```json { "owner": { short-form user resource }, "created": "timestamp", "updated": "timestamp", "name": "string", "description": "string (markdown)", "default_permissions": { "anonymous": [ ...list of permissions... ], "submitter": [ ...list of permissions... ], "user": [ ...list of permissions... ] } } ``` **Permissions** may be one or more of browse, submit, comment, edit, and triage. Short form: ```json { "owner": { short-form user resource }, "created": "timestamp", "updated": "timestamp", "name": "string", } ``` ## Endpoints **Note**: usernames are prefixed with `~`. ### GET /api/user/:username Retrieves a user resource. ### GET /api/user Equivalent to [/api/user/:username](#GET-apiuserusername), implies the authenticated user. ### GET /api/user/:username/trackers List of [tracker resources](#tracker-resource) owned by this user. **OAuth scope**: `trackers:read` ### GET /api/trackers Equivalent to [/api/:username/trackers](#GET-apiusernametrackers), implies the authenticated user. **OAuth scope**: `trackers:read` ### POST /api/trackers Creates a new [tracker resource](#tracker-resource). **OAuth scope**: `trackers:write` **Request body** ```json { "name": "tracker name", "description": "tracker description (markdown)" (optional) } ``` **Response** The new [tracker resource](#tracker-resource) ### GET /api/user/:username/trackers/:tracker-name Retrieves a [tracker resource](#tracker-resource). **OAuth scope**: `trackers:read` ### GET /api/trackers/:tracker-name Equivalent to [/api/:username/trackers/:tracker-name](#GET-apiusernametrackerstrackername), implies the authenticated user. **OAuth scope**: `trackers:read` ### PUT /api/user/:username/trackers/:tracker-name Updates a [tracker resource](#tracker-resource). ```json { "description": "tracker description (markdown)" (optional) } ``` **OAuth scope**: `trackers:write` ### PUT /api/trackers/:tracker-name Equivalent to [/api/:username/trackers/:tracker-name](#PUT-apiusernametrackerstrackername), implies the authenticated user. **OAuth scope**: `trackers:write` ### DELETE /api/trackers/:tracker-name Deletes a [tracker resource](#tracker-resource). **OAuth scope**: `trackers:write` ### DELETE /api/trackers/:tracker-name Equivalent to [/api/:username/trackers/:tracker-name](#DELETE-apiusernametrackerstrackername), implies the authenticated user. **OAuth scope**: `trackers:write` ### GET /api/user/:username/trackers/:tracker-name/labels List of [label resources](#label-resource) associated with this tracker. **OAuth scope**: `trackers:read` ### GET /api/trackers/:tracker-name/labels Equivalent to [/api/:username/trackers/:tracker-name/labels](#GET-apiusernametrackerstrackernamelabels), implies the authenticated user. **OAuth scope**: `trackers:read` ### GET /api/user/:username/trackers/:tracker-name/tickets List of [ticket resources](#ticket-resource) associated with this tracker. **OAuth scope**: `tickets:read` ### GET /api/trackers/:tracker-name/tickets Equivalent to [/api/:username/trackers/:tracker-name/tickets](#GET-apiusernametrackerstrackernametickets), implies the authenticated user. **OAuth scope**: `tickets:read` ### POST /api/user/:username/trackers/:tracker-name/tickets Creates a new [ticket resources](#ticket-resource) associated with this tracker. **OAuth scope**: `tickets:write` **Request body** ```json { "title": "ticket title", "description": "ticket description (markdown)" (optional) } ``` **Response** The new [ticket resource](#ticket-resource) ### POST /api/trackers/:tracker-name/tickets Equivalent to [/api/:username/trackers/:tracker-name/tickets](#POST-apiusernametrackerstrackernametickets), implies the authenticated user. **OAuth scope**: `tickets:write` ### GET /api/user/:username/trackers/:tracker-name/tickets/:ticket-id Retrieves a [ticket resource](#ticket-resource). **OAuth scope**: `tickets:read` ### GET /api/trackers/:tracker-name/tickets/:ticket-id Equivalent to [/api/:username/trackers/:tracker-name/tickets/:ticket-id](#GET-apiusernametrackerstrackernameticketsticketid), implies the authenticated user. **OAuth scope**: `tickets:read` ### PUT /api/user/:username/trackers/:tracker-name/tickets/:ticket-id Updates a [ticket resource](#ticket-resource). This endpoint is used to: - Open or close tickets - Comment on tickets - Add or remove labels **OAuth scope**: `tickets:write` **Request body** ```json { "comment": "comment text (markdown)" (optional), "status": "ticket status enum" (optional), "resolution": "ticket resolution enum" (optional), "labels": ["list of desired label names"] (optional) } ``` **Ticket status enum** One of: - `reported` - `confirmed` - `in_progress` - `pending` - `resolved` **Ticket resolution enum** One of: - `unresolved` - `fixed` - `implemented` - `wont_fix` - `by_design` - `invalid` - `duplicate` - `not_our_bug` **Response** ```json { "ticket": { affected ticket resource }, "events": [ list of event resources created by this update ] } ``` ### PUT /api/trackers/:tracker-name/tickets/:ticket-id Equivalent to [/api/:username/trackers/:tracker-name/tickets/:ticket-id](#PUT-apiusernametrackerstrackernameticketsticketid), implies the authenticated user. **OAuth scope**: `tickets:write` ### GET /api/user/:username/trackers/:tracker-name/tickets/:ticket-id/events List of [event resources](#event-resource) associated with this ticket. **OAuth scope**: `tickets:read` ### GET /api/trackers/:tracker-name/tickets/:ticket-id/events Equivalent to [/api/:username/trackers/:tracker-name/tickets/:ticket-id/events](#GET-apiusernametrackerstrackernameticketsticketidevents), implies the authenticated user. **OAuth scope**: `tickets:read` ## Webhooks ### /api/user/... Webhook for user events. Includes the [standard webhook endpoints](../api-conventions.md#webhooks) #### tracker:create Issued when the user creates a new tracker. **OAuth scope**: `trackers:read` **Request body** The new [tracker resource](#tracker-resource). #### tracker:update Issued when the user updates a tracker. **OAuth scope**: `trackers:read` **Request body** The affected [tracker resource](#tracker-resource). #### tracker:delete Issued when the user deletes a tracker. **OAuth scope**: `trackers:read` **Request body** ```json { "id": the affected tracker ID } ``` #### ticket:create Issued when the user creates a new ticket. **OAuth scope**: `tickets:read` **Request body** The new [ticket resource](#ticket-resource). #### event:create Issued when a new event is created for a ticket on this tracker. **OAuth scope**: `tickets:read` **Request body** The new [event resource](#event-resource). ### /api/user/:username/trackers/:tracker-name Webhook for tracker events. Includes the [standard webhook endpoints](../api-conventions.md#webhooks) #### label:create Issued when a new label is added to this tracker. **OAuth scope**: `trackers:read` **Request body** The new [label resource](#label-resource). #### label:delete Issued when a label is removed from this tracker. **OAuth scope**: `trackers:read` **Request body** ```json { "id": affected label ID } ``` #### ticket:create Issued when a ticket is created for this tracker. **OAuth scope**: `tickets:read` **Request body** The new [ticket resource](#ticket-resource). ### /api/user/:username/trackers/:tracker-name/tickets/:ticket-id Webhook for ticket events. Includes the [standard webhook endpoints](../api-conventions.md#webhooks) #### ticket:update Issued when this tickets details are updated. **OAuth scope**: `tickets:read` **Request body** The updated [ticket resource](#ticket-resource). #### event:create Issued when a new event is created for this this ticket. **OAuth scope**: `tickets:read` **Request body** The new [event resource](#event-resource).