Specific users of this database are given the ability to create statements of reasons using an API endpoint. This greatly increases efficiency and allows for automation.
To set up your statement of reasons submission process, please register here regarding your obligations under article 24(5) of the DSA. After receiving your registration form, the Digital Service Coordinator of your Member State will contact you providing the details on how to complete the onboarding of your online platform.
Once you are onboarded via your Digital Service Coordinator, you will gain access to a sandbox environment to test your submissions to the DSA Transparency Database, which you can perform either via an Application Programming Interface ( API) or a webform, according to the volume of your data and technical needs.
Once the testing phase is completed, you will be able to move to the production environment of the DSA Transparency Database, where you can start submitting your statement of reasons via an API or a webform.
When your account is given the ability to use the API then you are able to generate a private secure token that will allow you to use the API.
This token looks something like this:
X|ybqkCFX7ZkIFoLxtI0VAk1JBzMR9jVk4c4EU
If you do not know your token or need to generate a new token you may do so in the user profile of this application. Simply click the button "Generate New Token"
This token will be shown one time, so it will need to be copied and stored safely.
Each time you generate a new token the old token becomes invalid!
To create a statement of reason using the API you will need to make a
POST
request to this endpoint.
https://transparency.dsa.ec.europa.eu/api/v1/statement
For this request you will need to provide authorization, accept, and content type headers of the request:
Authorization: Bearer YOUR_TOKEN Accept: application/json Content-Type: application/json
The body of your request needs to be a json encoded payload with the information of the statement
Example JSON payload body:
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DISABLED"
],
"decision_monetary": "DECISION_MONETARY_TERMINATION",
"end_date_monetary_restriction": "2023-08-08",
"decision_provision": "DECISION_PROVISION_TOTAL_SUSPENSION",
"decision_account": "DECISION_ACCOUNT_SUSPENDED",
"account_type": "ACCOUNT_TYPE_BUSINESS",
"decision_ground": "DECISION_GROUND_INCOMPATIBLE_CONTENT",
"decision_ground_reference_url": "https://www.anurl.com",
"content_type": [
"CONTENT_TYPE_VIDEO",
"CONTENT_TYPE_AUDIO",
"CONTENT_TYPE_SYNTHETIC_MEDIA"
],
"category": "STATEMENT_CATEGORY_PORNOGRAPHY_OR_SEXUALIZED_CONTENT",
"illegal_content_legal_ground": "illegal content legal grounds",
"illegal_content_explanation": "illegal content explanation",
"incompatible_content_ground": "incompatible content grounds",
"incompatible_content_explanation": "incompatible content explanation",
"incompatible_content_illegal": "Yes",
"territorial_scope": [
"PT",
"ES",
"DE"
],
"content_language": "EN",
"content_date": "2023-08-08",
"application_date": "2023-08-08",
"decision_facts": "facts about the decision",
"source_type": "SOURCE_TRUSTED_FLAGGER",
"automated_detection": "No",
"automated_decision": "AUTOMATED_DECISION_PARTIALLY",
"puid": "TK421"
}
When the request has been sent and it is correct, a response of 201
Created
will be
sent back.
You will also receive a payload with the statement as created in the database:
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DISABLED"
],
"decision_monetary": "DECISION_MONETARY_TERMINATION",
"decision_provision": "DECISION_PROVISION_TOTAL_SUSPENSION",
"decision_account": "DECISION_ACCOUNT_SUSPENDED",
"account_type": "ACCOUNT_TYPE_BUSINESS",
"decision_ground": "DECISION_GROUND_INCOMPATIBLE_CONTENT",
"decision_ground_reference_url": "https://www.anurl.com",
"incompatible_content_ground": "incompatible content grounds",
"incompatible_content_explanation": "incompatible content explanation",
"incompatible_content_illegal": "Yes",
"content_type": [
"CONTENT_TYPE_AUDIO",
"CONTENT_TYPE_SYNTHETIC_MEDIA",
"CONTENT_TYPE_VIDEO"
],
"category": "STATEMENT_CATEGORY_PORNOGRAPHY_OR_SEXUALIZED_CONTENT",
"territorial_scope": [
"DE",
"ES",
"PT"
],
"content_language": "EN",
"content_date": "2023-08-08",
"application_date": "2023-08-08",
"end_date_monetary_restriction": "2023-08-08",
"decision_facts": "facts about the decision",
"source_type": "SOURCE_TRUSTED_FLAGGER",
"automated_detection": "No",
"automated_decision": "AUTOMATED_DECISION_PARTIALLY",
"end_date_visibility_restriction": null,
"end_date_account_restriction": null,
"end_date_service_restriction": null,
"uuid": "4b989c23-3736-4fd9-8612-a975b98d88d6",
"created_at": "2024-11-25 09:16:55",
"id": 34509873504987,
"platform_name": "The Platform",
"permalink": "https://.../statement/34509873504987",
"self": "https://.../api/v1/statement/34509873504987",
"puid": "TK421"
}
Every statement created in the database receives an UUID which identifies the statement uniquely.
Every statement created in the database receives an ID which identifies the statement uniquely.
This ID is then used in the urls for retrieving and viewing the statement online.
These urls are present in the response after creating as the, "permalink" and "self" attributes.
We highly encourage all platforms to bundle and create multiple Statements of Reason in one API call using the multiple endpoint.
Please to make a POST
request to this endpoint.
https://transparency.dsa.ec.europa.eu/api/v1/statements
The payload of this request should contain one field called "statements" and that field needs to be an array of Statements of Reason.
Here is an example:
{
"statements"
:
[
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DISABLED"
],
"decision_monetary": "DECISION_MONETARY_TERMINATION",
"decision_provision": "DECISION_PROVISION_TOTAL_SUSPENSION",
...
...
},
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DISABLED"
],
"decision_monetary": "DECISION_MONETARY_TERMINATION",
"decision_provision": "DECISION_PROVISION_TOTAL_SUSPENSION",
...
...
},
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DISABLED"
],
"decision_monetary": "DECISION_MONETARY_TERMINATION",
"decision_provision": "DECISION_PROVISION_TOTAL_SUSPENSION",
...
...
}
...
]
}
The multiple endpoint is capable of making 100 statements per call.
When the request has been sent and it is correct, a response of 201
Created
will be
sent back.
The response payload when calling the multiple endpoint will be an array of the Statements of Reason when successful. Each Statement of Reason will then have an uuid, created_at, self, and permalink attribute to reflect that it was created.
{
"statements"
:
[
{
"decision_visibility": [
"DECISION_VISIBILITY_CONTENT_DEMOTED"
],
"decision_monetary": "DECISION_MONETARY_OTHER",
...
...
...
"uuid"
:
"bf92a941-c77a-4b9d-a236-38956ae79cc5",
"created_at"
:
"2023-11-07 07:53:43",
"platform_name"
:
"The Platform",
"puid"
:
"b5ec958d-892a-4c11-a3f2-6a3ad597eeb1"
},
{
"decision_visibility"
:
[
"DECISION_VISIBILITY_CONTENT_DEMOTED"
],
...
...
...
"uuid"
:
"174a1921-0d9e-4864-b095-6774fb0237da",
"created_at"
:
"2023-11-07 07:53:44",
"platform_name"
:
"The Platform",
"puid"
:
"a12b436a-33b1-4403-99b2-8c16e3c5502f"
}
,
{
"decision_account"
:
"DECISION_ACCOUNT_SUSPENDED",
"account_type"
:
"ACCOUNT_TYPE_PRIVATE",
"decision_ground"
:
"DECISION_GROUND_INCOMPATIBLE_CONTENT",
...
...
...
"uuid"
:
"b8f03bf5-b8fd-4987-ac56-6fe6ab155e9e",
"created_at"
:
"2023-11-07 07:53:45",
"platform_name"
:
"The Platform",
"puid"
:
"649c58f6-8412-4100-b10c-010b76f5a41a"
}
,
...
]
}
The attributes of the statement take on two main forms.
When submitting statements please take care to not submit ANY personal data. On a regular basis we will do checks on the database to ensure that no personal data has been submitted. However, in accordance with Article 24(5), it is the obligation of providers of online platforms to ensure that the information submitted does not contain personal data.
Please refer to our Additional Explanation For Statement Attributes page for more information about the attributes.
This attribute tells us the visibility restriction of specific items of information provided by the recipient of the service.
This attribute is mandatory only if the following fields are empty: decision_monetary, decision_provision and decision_account
The value provided must be an array with at least one of the following:
This is required if DECISION_VISIBILITY_OTHER was the decision_visibility.
Limited to 500 characters.
This is an attribute that gives information about the Monetary payments suspension, termination or other restriction
This attribute is mandatory only if the following fields are empty: decision_visibility, decision_provision and decision_account
The value provided must be one of the following:
This is required if DECISION_MONETARY_OTHER was the decision_monetary.
Limited to 500 characters.
This is an attribute that tells us about the suspension or termination of the provision of the service.
This attribute is mandatory only if the following fields are empty: decision_visibility, decision_monetary and decision_account
The value provided must be one of the following:
This is an attribute that tells us about the account's status.
This attribute is mandatory only if the following fields are empty: decision_visibility, decision_monetary and decision_provision
The value provided must be one of the following:
This is an attribute that tells us about the account's type.
This attribute is optional.
The value provided must be one of the following:
This is a required textual field to describe the facts and circumstances relied on in taking the decision.
Limited to 5000 characters.
This is a required field and tells us the basis on which the decision was taken.
This is an url to the TOS or Law relied upon in taking the decision.
This is an optional attribute.
This is required if the DECISION_GROUND_ILLEGAL_CONTENT was the decision_ground. It is the legal grounds relied on.
Limited to 500 characters.
This is required if the DECISION_GROUND_ILLEGAL_CONTENT was the decision_ground. This is a text that explains why the content was illegal.
Limited to 2000 characters.
This is required if DECISION_GROUND_INCOMPATIBLE_CONTENT was the decision_ground. It is the reference to contractual grounds.
Limited to 500 characters.
This is required if DECISION_GROUND_INCOMPATIBLE_CONTENT was the decision_ground. This is a text that explains why the content is considered as incompatible on that ground.
Limited to 2000 characters.
This is an optional attribute and it can be in the form "Yes" or "No". This is a possibility to indicate that the content was not only considered incompatible but also illegal.
This is a required attribute, and it tells us what type of content is targeted by the statement of reason.
The value provided must be an array with at least one of the following:
This is required if CONTENT_TYPE_OTHER was the content_type. It is a content type that is not part of provided content type list.
Limited to 500 characters.
This is a required attribute, and it tells us which category the statement belongs to.
The value provided must be one of the following:
This is an optional attribute, and it tells us which additional categories the statement belongs to.
The value provided must be an array with one or more of the following:
This is an optional attribute, and it tells us which additional keywords the statement belongs to.
The value provided must be an array with one or more of the following:
This field can be provided if KEYWORD_OTHER is part of the category_specification.
Limited to 500 characters.
This is a required attribute that defines territorial scope of the restriction. Each value must be the 2-letter iso code for the country and the countries must be (EU/EEA) countries.
The value provided must be an array.
Allowed values are:
AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK
For European Union (EU) use:
["AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO", "SE", "SI", "SK"]
For European Economic Area (EEA) use:
["AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GR", "HR", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MT", "NL", "NO", "PL", "PT", "RO", "SE", "SI", "SK"]
This is the language that the content was in.
This attribute is optional.
The value though must be one of the uppercase two letter ISO 639-1 codes.
Ex,
"EN", "BG", "HR", "CS", "DA", "NL", "ET", "FI", "FR", "DE", "EL", "HU", "GA", "IT", "LV", "LT", "MT", "PL", "PT", "RO", "SK", "SL", "ES", "SV"
This is a required date field that indicates the upload or posting date of the content. The date should follow this format:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to 2000-01-01.
This is the date that this decision starts from. The date needs to take the form of:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to 2020-01-01.
This is the date that the decision on the account ends. Leave blank for indefinite.
The date needs to take the form of:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to the application date.
This is the date that the monetary decision ends. Leave blank for indefinite.
The date needs to take the form of:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to the application date.
This is the date that the provision decision ends. Leave blank for indefinite.
The date needs to take the form of:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to the application date.
This is the date that the visibility decision ends. Leave blank for indefinite.
The date needs to take the form of:
YYYY-MM-DD
The day and the month have leading zeroes.
The date must be after or equal to the application date.
This is a required field and tells us the facts and circumstances relied upon in taking the decision.
The value provided must be one of the following:
This is an optional field to describe the source/notifier if needed. Will not be taken into account if the 'source_type' is set to 'SOURCE_VOLUNTARY'
Limited to 500 characters.
This is a required attribute and it must be in the form "Yes" or "No". This indicates to us that decision taken in respect of automatically detected means.
This is a required attribute and it must be one of the following:
This is a string that uniquely identifies this statement within the platform. This attribute is required and it must be unique within your platform.
Limited to 500 characters and must contain alphanumeric characters (a-z, A-Z, 0-9), hyphens "-" and underscores "_"only. No spaces, new-line or any other special characters are accepted.
This endpoint allows you to determine whether a given PUID (Persistent Unique Identifier) is already associated with a Statement of Reason (SoR).
To check if an existing PUID is already used in a statement of reason using the API you will need to make a
GET
request to this endpoint.
https://transparency.dsa.ec.europa.eu/api/v1/statement/existing-puid/<PUID>
Replace <PUID>
with the actual PUID you want to check.
Authorization: Bearer YOUR_TOKEN Accept: application/json Content-Type: application/json
404 Not Found
{
"message": "statement of reason not found",
"puid": "YOUR_PUID"
}
302 Found
.{
"message": "statement of reason found",
"puid": "YOUR_PUID"
}
When a call to the API has been made AND there was an error in the call you may expect the following to occur:
201 Created
.For Ex,
You made an API with a blank JSON payload or an invalid JSON payload.
{
}
The HTTP Status code coming back will be 422 Unproccessable Content
The payload body will be a JSON object containing more information and the errors in the API call.
{
"message"
:
"The decision visibility field is required when none of decision monetary / decision provision / decision account are present. (and 13 more errors)",
"errors"
:
{
"decision_visibility"
:
[
"The decision visibility field is required when none of decision monetary / decision provision / decision account are present."
],
"decision_monetary"
:
[
"The decision monetary field is required when none of decision visibility / decision provision / decision account are present."
],
"decision_provision"
:
[
"The decision provision field is required when none of decision visibility / decision monetary / decision account are present."
],
"decision_account"
:
[
"The decision account field is required when none of decision visibility / decision monetary / decision provision are present."
],
"decision_ground"
:
[
"The decision ground field is required."
],
"content_type"
:
[
"The content type field is required."
],
"category"
:
[
"The category field is required."
],
"application_date"
:
[
"The application date field is required."
],
"decision_facts"
:
[
"The decision facts field is required."
],
"source_type"
:
[
"The source type field is required."
],
"automated_detection"
:
[
"The automated detection field is required."
],
"automated_decision"
:
[
"The automated decision field is required."
],
"puid"
:
[
"The puid field is required."
]
}
}
The error messages for the individual fields will vary depending on what was attempted.
Such as the following:
If you sent
{
...
"automated_decision":"maybe"
...
}
"Maybe" is not a valid value for automated_decision. (only "Yes" or "No")
{
"message"
:
"The selected automated decision is invalid.",
"errors"
:
{
"automated_decision"
:
[
"The selected automated decision is invalid."
]
}
}
When you are you calling the multiple endpoint you will encounter the same errors as the single endpoint. However, the errors will be indexed to the Statement of Reason that you are trying to create.
ex,
{
"errors"
:
{
"statement_0"
:
{
"decision_monetary"
:
[
"The selected decision monetary is invalid."
],
"decision_ground"
:
[
"The selected decision ground is invalid."
],
"automated_detection"
:
[
"The automated detection field is required."
]
}
,
"statement_2"
:
{
"decision_provision"
:
[
"The selected decision provision is invalid."
]
}
}
}
This means that the decision monetary, the decision ground and the automated detection fields were invalid in the statement of reason at position 0 in the array. This means that the decision provision is invalid in the statement of reason at position 2 in the array.
In this case, NONE of the statements where created, the request needs to be fixed and resent.
Another common error that may occur when calling the API is that the authorization token is not valid.
This will result in a HTTP status code of 401 Unauthorized
The API authorization token needs to be double checked or a new API authorization token needs to be generated. See again the section above: Your API Token
In addition to the common 422
and 401
errors, Any of the standard 4XX HTTP can be
encountered. 4XX statuses generally indicate that there is an issue with your request. Please try to
troubleshoot and resolve the problem.
When there is an error of 5XX we are immediately notified and there is no need to report the issue.
When you attempt to create a statement for your platform and there exists a statement with the same puid, the
response will still be 422 Unproccessable Content
and the error returned will contain the existing
the statement. This will look like the following:
{
"message"
:
"The identifier given is not unique within this platform.",
"errors"
:
{
"puid"
:
[
"The identifier given is not unique within this platform."
]
}
,
"existing"
:
{
"uuid"
:
"6bf8beb0-765c-4e79-8cb1-dc93fc7478bb",
"decision_visibility"
:
[
...
],
...
"permalink"
:
"... /statement/6bf8beb0-765c-4e79-8cb1-dc93fc7478bb",
"self"
:
"... /api/v1/statement/6bf8beb0-765c-4e79-8cb1-dc93fc7478bb"
}
}
The source code for this application can be viewed here:
DSA Transparency Database Source - GitHub
Using the repository code you can even setup and run a local replica development testing area.
Within the github environment you are also more than welcome to give pull requests and reviews concerning the source code.