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

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

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.

Screenshot of menu on right side of client list

Terms of use

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