Project Management¶
Apart from staff users ("Web Users" in the Central management interface) and some site-wide configuration details like Usage Reporting, all of ODK Central's objects (Forms, Submissions, App Users) are partitioned by Project, and available only as subresources below the main Projects resource.
Projects¶
(introduced: version 0.4)
You must create a containing Project before you can create any of its subobjects.
Listing Projects¶
GET /v1/projects
The Projects listing endpoint is somewhat unique in that it is freely accessible to anybody, even unauthenticated clients. Rather than reject the user with a 403
or similar error, the Projects listing will only return Projects that the authenticated Actor is allowed to see. In most cases, this means that unauthenticated requests will receive []
in reply.
Currently, there are no paging or filtering options, so listing Project
s will get you every Project you have access to.
This endpoint supports retrieving extended metadata; provide a header X-Extended-Metadata: true
to additionally retrieve the appUsers
count of App Users and forms
count of Forms within the Project, as well as the lastSubmission
timestamp of the latest submission to any for in the project, if any.
Request
Parameters
forms (query) |
(introduced: Version 1.5) If set to true then endpoint also returns the Forms that the authenticated Actor is allowed to see, with those Forms nested within their corresponding Project under a new parameter Example: |
datasets (query) |
(introduced: Version 2023.4) If set to true then endpoint also returns the Datasets that the authenticated Actor is allowed to see, with those Datasets nested within their corresponding Project under a new parameter Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
]
array
|
HTTP Status: 200
Content Type: application/json; extended
[
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false,
"appUsers": 4,
"forms": 7,
"lastSubmission": "2018-04-18T03:04:51.695Z",
"datasets": 2,
"lastEntity": "2023-04-18T03:04:51.695Z"
}
]
array
|
Creating a Project¶
POST /v1/projects
To create a Project, the only information you must supply (via POST body) is the desired name of the Project.
Request
Request body
{
"name": "Project Name"
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Getting Project Details¶
GET /v1/projects/{id}
To get just the details of a single Project, GET
its single resource route by its numeric ID.
This endpoint supports retrieving extended metadata; provide a header X-Extended-Metadata: true
to additionally retrieve the appUsers
count of App Users and forms
count of forms within the Project, as well as the lastSubmission
timestamp of the latest submission to any for in the project, if any.
In addition, the extended metadata version of this endpoint (but not the overall Project listing) returns an array of the verbs
the authenticated Actor is able to perform on/within the Project.
Request
Parameters
id |
The numeric ID of the Project Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
object
|
HTTP Status: 200
Content Type: application/json; extended
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false,
"appUsers": 4,
"forms": 7,
"lastSubmission": "2018-04-18T03:04:51.695Z",
"datasets": 2,
"lastEntity": "2023-04-18T03:04:51.695Z",
"verbs": [
"form.create",
"form.delete"
]
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Deep Updating Project and Form Details¶
PUT /v1/projects/{id}
(introduced: version 0.7)
When managing a large deployment, it can be necessary to make sweeping changes to all Form States and Assignments within it at once—when rolling out a new Form, for example, or replacing a deprecated version with a new revision.
For this purpose, we offer this PUT
resource, which allows a deep update of Project metadata, Form metadata, and Form Assignment metadata at once and transactionally using a nested data format.
One important mechanic to note immediately here is that we follow true PUT
semantics, meaning that the data you provide is not merged with existing data to form an update. With our usual PATCH
endpoints, we do this kind of merging and so data that you don't explicitly pass us is left alone. Because we allow the deletion of Form Assignments by way of omission with this API, we treat all omissions as an explicit specification to null the omitted field. This means that, for example, you must always re-specify the Project name, the Project description, and archival flag with every PUT
.
This adherence to PUT
semantics would normally imply that Forms could be created or deleted by way of this request, but such an operation could become incredibly complex. We currently return a 501 Not Implemented
error if you supply nested Form information but you do not give us exactly the entire set of extant Forms.
You can inspect the Request format for this endpoint to see the exact nested data structure this endpoint accepts. Each level of increased granularity is optional: you may PUT
just Project metadata, with no forms
array, and you may PUT
Project and Form metadata but omit assignments
from any Form, in which case the omitted detail will be left as-is.
Request
Parameters
id |
The numeric ID of the Project Example: |
Request body
{
"name": "New Project Name",
"description": "New Project Description",
"archived": false,
"forms": [
{
"xmlFormId": "simple",
"state": "open",
"assignments": [
{
"roleId": 2,
"actorId": 14
},
{
"roleId": 2,
"actorId": 21
}
]
},
{
"xmlFormId": "test",
"state": "closed"
}
]
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
HTTP Status: 501
Content Type: application/json
{
"code": "501.1",
"message": "The requested feature $unsupported is not supported by this server."
}
object
|
Deleting a Project¶
DELETE /v1/projects/{id}
Deleting a Project will remove it from the management interface and make it permanently inaccessible. Do not do this unless you are certain you will never need any of its data again. For now, deleting a Project will not purge its Forms. (We will change that in a future release.)
Request
Parameters
id |
The numeric ID of the Project Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Updating Project Details¶
PATCH /v1/projects/{id}
The Project name may be updated, as well as the Project description and the archived
flag.
By default, archived
is not set, which is equivalent to false
. If archived
is set to true
, the Project will be sorted to the bottom of the list, and in the web management application the Project will become effectively read-only. API write access will not be affected.
Request
Parameters
id |
The numeric ID of the Project Example: |
Request body
{
"name": "New Project Name",
"description": "Description of this Project to show on Central.",
"archived": true
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Enabling Project Managed Encryption¶
POST /v1/projects/{id}/key
(introduced: version 0.6)
Project Managed Encryption can be enabled via the API. To do this, POST
with the passphrase
and optionally a reminder hint
about the passphrase. If managed encryption is already enabled, a 409
error response will be returned.
Enabling managed encryption will modify all unencrypted forms in the project, and as a result the version
of all forms within the project will also be modified. It is therefore best to enable managed encryption before devices are in the field. Any forms in the project that already have self-supplied encryption keys will be left alone.
Request
Parameters
id |
The numeric ID of the Project Example: |
Request body
{
"passphrase": "super duper secret",
"hint": "it was a secret"
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"id": 1,
"name": "Default Project",
"description": "Description of this Project to show on Central.",
"keyId": 3,
"archived": false
}
object
|
HTTP Status: 400
Content Type: application/json
{
"code": "400",
"message": "Could not parse the given data (2 chars) as json."
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
HTTP Status: 409
Content Type: application/json
{
"code": "409.1",
"message": "A resource already exists with id value(s) of 1."
}
object
|
Project Assignments¶
(introduced: version 0.5)
There are multiple Assignments resources. This one, specific to the Project it is nested within, only governs Role assignments to that Project. Assigning an Actor a Role that grants, for example, a verb submission.create
, allows that Actor to create a submission anywhere within this Project. It is also possible to assign rights only to specific forms for actions related only to that form and its submissions: see the Form Assignments resource for information about this.
The sitewide Assignments resource, at the API root, manages Role assignments for all objects across the server. Apart from this difference in scope, the introduction to that section contains information useful for understanding the following endpoints.
There are only one set of Roles, applicable to either scenario. There are not a separate set of Roles used only upon Projects or Forms.
Listing all Project Assignments¶
GET /v1/projects/{projectId}/assignments
This will list every assignment upon this Project, in the form of actorId
/roleId
pairs.
This endpoint supports retrieving extended metadata; provide a header X-Extended-Metadata: true
to expand the actorId
into a full actor
objects. The Role reference remains a numeric ID.
Request
Parameters
projectId |
The numeric ID of the Project Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"actorId": 115,
"roleId": 4
}
]
array
|
HTTP Status: 200
Content Type: application/json; extended
[
{
"actor": {
"createdAt": "2018-04-18T23:19:14.802Z",
"displayName": "My Display Name",
"id": 115,
"type": "user",
"updatedAt": "2018-04-18T23:42:11.406Z",
"deletedAt": "2018-04-18T23:42:11.406Z"
},
"roleId": 4
}
]
array
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Listing all Actors assigned some Project Role¶
GET /v1/projects/{projectId}/assignments/{roleId}
Given a roleId
, which may be a numeric ID or a string role system
name, this endpoint lists all Actors
that have been assigned that Role upon this particular Project.
Request
Parameters
roleId |
Typically the integer ID of the Example: |
projectId |
The numeric ID of the Project Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"createdAt": "2018-04-18T23:19:14.802Z",
"displayName": "My Display Name",
"id": 115,
"type": "user",
"updatedAt": "2018-04-18T23:42:11.406Z",
"deletedAt": "2018-04-18T23:42:11.406Z"
}
]
array
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Assigning an Actor to a Project Role¶
POST /v1/projects/{projectId}/assignments/{roleId}/{actorId}
Given a roleId
, which may be a numeric ID or a string role system
name, and a numeric actorId
, assigns that Role to that Actor for this particular Project.
No POST
body data is required, and if provided it will be ignored.
Request
Parameters
projectId |
The numeric ID of the Project Example: |
roleId |
Typically the integer ID of the Example: |
actorId |
The integer ID of the Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Revoking a Project Role Assignment from an Actor¶
DELETE /v1/projects/{projectId}/assignments/{roleId}/{actorId}
Given a roleId
, which may be a numeric ID or a string role system
name, and a numeric actorId
, unassigns that Role from that Actor for this particular Project.
Request
Parameters
projectId |
The numeric ID of the Project Example: |
roleId |
Typically the integer ID of the Example: |
actorId |
The integer ID of the Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Seeing all Form Assignments within a Project¶
GET /v1/projects/{projectId}/assignments/forms
Returns a summary of all Form-specific Assignments within this Project. This endpoint is meant to simplify the task of summarizing all Form permissions within a Project at a glance and in one transactional request. Because it is necessary to specify which Form each Assignment is attached to, returned results form this endpoint include an xmlFormId
field.
This endpoint supports retrieving extended metadata; provide a header X-Extended-Metadata: true
to expand the actorId
into a full actor
objects. The Role reference remains a numeric ID and the Form reference remains a string ID.
Request
Parameters
projectId |
The numeric ID of the Project Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"actorId": 115,
"xmlFormId": "simple",
"roleId": 4
}
]
array
|
HTTP Status: 200
Content Type: application/json; extended
[
{
"actor": {
"createdAt": "2018-04-18T23:19:14.802Z",
"displayName": "My Display Name",
"id": 115,
"type": "user",
"updatedAt": "2018-04-18T23:42:11.406Z",
"deletedAt": "2018-04-18T23:42:11.406Z"
},
"xmlFormId": "simple",
"roleId": 4
}
]
array
|
HTTP Status: 403
Content Type: application/json
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|
Seeing Role-specific Form Assignments within a Project¶
GET /v1/projects/{projectId}/assignments/forms/{roleId}
Like the Form Assignments summary API, but filtered by some roleId
.
This endpoint supports retrieving extended metadata; provide a header X-Extended-Metadata: true
to expand the actorId
into a full actor
objects. The Role reference remains a numeric ID and the Form reference remains a string ID.
Request
Parameters
projectId |
The numeric ID of the Project Example: |
roleId |
The numeric ID of the Role Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"actorId": 115,
"xmlFormId": "simple",
"roleId": 4
}
]
array
|
HTTP Status: 200
Content Type: application/json; extended
[
{
"actor": {
"createdAt": "2018-04-18T23:19:14.802Z",
"displayName": "My Display Name",
"id": 115,
"type": "user",
"updatedAt": "2018-04-18T23:42:11.406Z",
"deletedAt": "2018-04-18T23:42:11.406Z"
},
"xmlFormId": "simple",
"roleId": 4
}
]
array
|
HTTP Status: 403
Content Type: application/json; extended
{
"code": 403.1,
"message": "The authenticated actor does not have rights to perform that action."
}
object
|