Nettskjema API v3
This documentation is for developers working on software that will use version 3 of the Nettskjema API. The workflow is based on an OAuth 2.1 client model, using the client credentials flow.
Please send a comment to nettskjema@usit.uio.no if you find something missing or unclear.
API documentation
Please see the swagger documentation for a list and specification of available endpoints: https://nettskjema.no/apidoc
Power Tip:
You can try out the different endpoints in the swagger-doc against your forms by first clicking the Authorize button at the top right corner of Swagger UI, and entering your access token. This is very handy for testing the API.
To access a form from the swagger doc you will first need to
- Create an API client
- Give your API client access to a form
- Create an access token for the API client
The API client model
Nettskjema is using an OAuth 2.1 client model. The term “client” is how OAuth refers to applications, the software that is going to access data behind the API.
To access the API (which OAuth calls ?Resource Server?) you need to use an access token.
You can get an access token by sending a request to the authorization server with the client ID and the client secret (password).
The authorization server’s job is to create API clients, and make sure it only gives access tokens to legitimate clients.
Creating an API client
- Log in to the Nettskjema authorization server: authorization.nettskjema.no
- Only FEIDE, TSD and ID-Porten users with administrative privileges, privileges to create forms in Nettskjema, may log in and create API clients.
- The main page of the authorization server lists your existing API clients.
- To create a new client, click ?Register client?
- Client IDs are long alphanumeric strings, so you are asked to add a human readable ?Client Name?, which is used only as a label to keep different clients apart.
- The email is only used to send notifications when a client expire. This is important because the client is deleted if it is not renewed before expiring.
- After clicking ?Register? you will receive a clientId, clientSecret and an expiration date.
- The clientSecret is a password, and you need to save it in a safe place as a password.
- The clientSecret is only displayed once. If this is lost, you must renew the API client before it expires or create a new API client.
- The clientSecret is valid for 365 days, you need to renew it before this. You will receive a new clientSecret when renewing.
Giving an API client access to a Nettskjema form
The client ID has a username variant which is <client ID>@apiclient, for instance
71b941-abcd-1a2b3c4e@apiclient
You can give the API client access to a form in Nettskjema by logging into nettskjema.no adding the API client username to the form like an ordinary user:
Settings > Permissions > Editing permissions
You can find a list of your API client IDs and usernames by logging into authorization.nettskjema.no
Creating a new access token
A new access token can be fetched from the authorization server using the client ID and the client secret.
The access token is valid for 86,400 seconds (24 hours). After that you will need to create a new one.
The following is an example on how to create an access token:
curl -X POST \
-u "clientId:clientSecret" \
-d "grant_type=client_credentials" \
'https://authorization.nettskjema.no/oauth2/token' \
| jq .
Which returns:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 86399
}
Never store the client secret in your code! – it is a password! Prompt it as input or fetch it from a file for good security.
NB: Please do not make a new token for each request. The access token lasts for 24h and is meant to be reused in your workflow. If you are unsure there are multiple libraries out there that supports this flow. Please check them out
There are multiple libraries that have good support for the oauth2 flow. An example in Python
The access token is a JWT, you can base64 decode the token to see the content.
Using the API client
The following is an example on how to use the access token to access an endpoint. The request returns all forms that the API client, which the access token represents, has access to:
curl -v https://nettskjema.no/api/v3/form/me \
-H "Accept: application/json" \
-H "Authorization: Bearer eyJ..." | jq .
Which returns a list of objects with information about each form"
[
{
"formId": 0,
"title": "string",
"openFrom": "2024-05-30T10:30:47.979Z",
"openTo": "2024-05-30T10:30:47.980Z",
"lastSubmissionDate": "2024-05-30T10:30:47.980Z",
"modifiedDate": "2024-05-30T10:30:47.980Z",
"personalDataErasedDate": "2024-05-30T10:30:47.980Z",
"deliveryDestination": "string",
"anonymous": true,
"numberOfDeliveredSubmissions": 0,
"owners": 0,
"isDictaphone": true,
"myFormsFormListingGroup": "MY",
"open": true
}
]
Never store the client secret in your code! – it is a password! Prompt it as input or fetch it from a file for good security.
Create a form using the API
This example shows how one may create a form using the API. It is also the minimal requirement to include in the json. It returns the form id of your newly created form. It takes a json structure with object of formSettings and elements. The formSettings is mandatory, but you may omit the elements. You can find all attributes of the objects in Swagger doc, they are called FormSettingsDTO and ElementDTO.
If no editors are included, the default is that the apiclient will have sole editing rights. If you want to see the forms in the nettskjema.no interface, you need to either include your username during the request. Or add it afterwards using another endpoint.
curl -v -X POST https://nettskjema.no/api/v3/form \
-H "Accept: application/json" \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{
"formSettings": {
"title": "Title",
"formType": "DEFAULT",
"languageCode": "nb",
"collectsPersonalData": false,
"sensitivePersonalDataCollected": false,
"respondentGroup": "ALL",
"editors": [
{
"username": "<clientId>@apiclient"
},
{
"username": "username@instituion.no"
}
]
}
}' | jq .
Which returns:
{
"formId": 12345
}
Create a form with elements
If you already have a form, you can use the API to obtain the formSettings and elements structure. You can do this by adding your apiclient to the list of editing permissions, and performing these calls.
You get formSettings by calling https://nettskjem.no/api/v3/form/{formId}/settings?is-for-create-form=true
You get elements by calling https://nettskjema.no/api/v3/form/{formId}/elements
This allows you to create a form with elements with one request. This is an example of putting it together
Show example
curl -v -X POST https://nettskjema.no/api/v3/form \
-H "Authorization: Bearer eyJ..." \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"formSettings":
{
"formType": "HIGH_SECURITY",
"scoreResultDisplayType": "NONE",
"title": "a kopi",
"editorsContactEmail": "tester@uio.no",
"collectsPersonalData": true,
"sensitivePersonalDataCollected": false,
"personalDataPurposeTypes": [
"STUDY_OR_EDUCATION"
],
"languageCode": "nb",
"shouldHideProgressBar": false,
"shouldPreventDataManipulation": true,
"codebookActivated": true,
"maxSubmissionsPerson": 1,
"respondentGroup": "FEIDE",
"postponable": false,
"retainRespondentAccessAfterDelivery": false,
"sendingReceiptToRespondent": true,
"editorsSubmissionEmailType": "NONE",
"editors": [
{
"username": "3f12f75a-2712-4c35-92db-a30c01334bb9@apiclient"
},
{
"username": "tester@uio.no"
}
],
"consentForm": false,
"randomizedOrder": false,
"globalCopyPermissionEnabled": false
},
"elements":
[
{
"elementId": 8078547,
"questionId": 9017017,
"text": "Hvilket tall liker du best",
"description": null,
"elementType": "RADIO",
"dateFormat": null,
"sequence": 1,
"maxSelectedAnswerOptions": 0,
"imageUrl": null,
"altText": null,
"linearScaleType": null,
"nationalIdNumberType": null,
"repeatedNationalIdRequired": null,
"nationalIdNumberOfLetters": null,
"nationalIdNumberOfDigits": null,
"isAutofill": null,
"image": null,
"isMandatory": false,
"isHorizontal": false,
"isRangeMarksShown": false,
"externalElementId": "var1",
"minimumValue": null,
"maximumValue": null,
"sendAdditionalRecipientEmail": false,
"useForRedirectToForm": false,
"minimumValueText": null,
"midValueText": null,
"maximumValueText": null,
"numberOfDecimals": null,
"routingReferenceIds": [],
"answerOptions": [
{
"answerOptionId": 19033039,
"sequence": 1,
"text": "1",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "1",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var1",
"textOrAltText": "1"
},
{
"answerOptionId": 19033040,
"sequence": 2,
"text": "2",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "2",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var1",
"textOrAltText": "2"
},
{
"answerOptionId": 19033041,
"sequence": 3,
"text": "3",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "3",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var1",
"textOrAltText": "3"
}
],
"answerOptionsVisibilityFilter": [],
"subElements": [],
"validationScripts": [],
"isAnswerHashed": false,
"maxNumberOfCharacters": null,
"isRandomizedOrder": false
},
{
"elementId": 8078548,
"questionId": 9017018,
"text": "Er det fordi det er partall",
"description": null,
"elementType": "RADIO",
"dateFormat": null,
"sequence": 2,
"maxSelectedAnswerOptions": 0,
"imageUrl": null,
"altText": null,
"linearScaleType": null,
"nationalIdNumberType": null,
"repeatedNationalIdRequired": null,
"nationalIdNumberOfLetters": null,
"nationalIdNumberOfDigits": null,
"isAutofill": null,
"image": null,
"isMandatory": false,
"isHorizontal": false,
"isRangeMarksShown": false,
"externalElementId": "var2",
"minimumValue": null,
"maximumValue": null,
"sendAdditionalRecipientEmail": false,
"useForRedirectToForm": false,
"minimumValueText": null,
"midValueText": null,
"maximumValueText": null,
"numberOfDecimals": null,
"routingReferenceIds": [],
"answerOptions": [
{
"answerOptionId": 19033042,
"sequence": 1,
"text": "Ja",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "1",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var2",
"textOrAltText": "Ja"
},
{
"answerOptionId": 19033043,
"sequence": 2,
"text": "Nei",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "2",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var2",
"textOrAltText": "Nei"
}
],
"answerOptionsVisibilityFilter": [
{
"answerOptionId": 19033040,
"sequence": 2,
"text": "2",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "2",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var1",
"textOrAltText": "2"
}
],
"subElements": [],
"validationScripts": [],
"isAnswerHashed": false,
"maxNumberOfCharacters": null,
"isRandomizedOrder": false
},
{
"elementId": 8078549,
"questionId": 9017019,
"text": "Beskriv hvorfor du liker tallet",
"description": null,
"elementType": "QUESTION_MULTILINE",
"dateFormat": null,
"sequence": 3,
"maxSelectedAnswerOptions": null,
"imageUrl": null,
"altText": null,
"linearScaleType": null,
"nationalIdNumberType": null,
"repeatedNationalIdRequired": null,
"nationalIdNumberOfLetters": null,
"nationalIdNumberOfDigits": null,
"isAutofill": null,
"image": null,
"isMandatory": false,
"isHorizontal": false,
"isRangeMarksShown": false,
"externalElementId": "var3",
"minimumValue": null,
"maximumValue": null,
"sendAdditionalRecipientEmail": false,
"useForRedirectToForm": false,
"minimumValueText": null,
"midValueText": null,
"maximumValueText": null,
"numberOfDecimals": null,
"routingReferenceIds": [],
"answerOptions": [],
"answerOptionsVisibilityFilter": [
{
"answerOptionId": 19033043,
"sequence": 2,
"text": "Nei",
"redirectToForm": null,
"isPreselected": false,
"isCorrect": false,
"additionalRecipientEmail": null,
"externalAnswerOptionId": "2",
"image": null,
"imageUrl": null,
"altText": null,
"externalElementId": "var2",
"textOrAltText": "Nei"
}
],
"subElements": [],
"validationScripts": [],
"isAnswerHashed": false,
"maxNumberOfCharacters": null,
"isRandomizedOrder": false
}
]
}' | jq .
Which returns:
{
"formId": 12345
}
Editing settings using the API
The attributes can be found as FormSettingsDTO in the swagger documentation. You may add as many attributes as you want on the same request. This example shows replacing the existing editors with <clientId>@apiclient and username@institution.no.
curl -v -X PATCH https://nettskjema.no/api/v3/form/{formId}/settings \
-H "Authorization: Bearer eyJ..." \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"editors": [
{
"username": "<clientId>@apiclient"
},
{
"username": "username@institution.no"
}
]
}' | jq .
Which returns no content (204).
Delivering attachments to forms
When using the endpoint: /api/v3/form/submission/{submissionId}/attachment, you need to add an attachmentToken. You receive the attachmentToken in the response when submitting forms through this endpoint: /api/v3/form/{formId}/submission. The response will include a field like this: "attachmentToken": "string-value". You must include this value in the header when uploading the attachment. The header should be: X-nettskjema-attachment-token
An example of a request with the attachmentToken looks like this:
curl -X PUT \
"https://nettskjema.no/api/v3/form/submission/{submissionId}/attachment?questionId={questionId}&filename={filename}&fileSize={fileSize}" \
-H "Accept: application/json" \
-H "Content-Type: application/octet-stream" \
-H "X-nettskjema-attachment-token: {attachmentToken}" \
--data-binary @{filename}
Editing, renewing and deleting an API client
Log into the Nettskjema authorization server: authorization.nettskjema.no
The main page of the authorization server lists your existing API clients. Use the menu at the right of each row to Edit, Delete, Renew or edit Editors for an API client.

Terms of use
Please read Data protection regulations and terms of use for Nettskjema-authorization