diff --git a/README.md b/README.md
index 97f3567..96d9152 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 This service allows to run SQL queries on the database.
 In particular, this service allows users with limited permissions to see reports of aggregated statistics across all data (e.g. a supervisor could analyse reports without having access to possibly confidential details of participants or notes).
 
-## Usage
+## Deployment
 See the [ndb-setup repo](https://github.com/Aam-Digital/ndb-setup) for full deployment instructions.
 
 To use this you need a running [CouchDB](https://docs.couchdb.org/en/stable/) and [structured query server (SQS)](https://neighbourhood.ie/products-and-services/structured-query-server).
@@ -14,3 +14,44 @@ The following variables might need to be configured in the `.env` file:
 - `SCHEMA_CONFIG_ID` database ID of the document which holds the SQS schema (default `_design/sqlite:config`)
 - `PORT` where the app should listen (default 3000)
 - `SENTRY_DSN` for remote logging
+
+-----
+# API access to reports
+Reports and their results are available for external services through the given API endpoints ([see OpenAPI specs](./docs/api-specs/reporting-api-v1.yaml)). Endpoints require a valid JWT access token, which can be fetched via OAuth2 client credential flow.
+
+## Initial setup of an API integration
+1. Request client_id and client_secret from server administrator (--> admin has to [create new client grant in Keycloak](https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients))
+
+![Keycloak Client Setup](docs/assets/keycloak-client-setup.png)
+
+2. Get the realm of your instance (e.g. https://[your_realm].aam-digital.com). This is both the subdomain of systems hosted on aam-digital.com and the Keycloak Realm for authentication (case sensitive!).
+
+## Access a report via API (after setup)
+
+1. Get valid access token using your client secret:
+
+```bash
+curl -X "POST" "https://keycloak.aam-digital.net/realms/<your_realm>/protocol/openid-connect/token" \
+     -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
+     --data-urlencode "client_id=<your_client_id>" \
+     --data-urlencode "client_secret=<your_client_secret>" \
+     --data-urlencode "grant_type=client_credentials" \
+     --data-urlencode "scopes=openid reports_read reports_write"
+```
+Check API docs for the required "scopes".
+This returns a JWT access token required to provided as Bearer Token for any request to the API endpoints. Sample token:
+```json
+{
+  "access_token": "eyJhbGciOiJSUzI...",
+  "expires_in": 300,
+  "refresh_expires_in": 0,
+  "token_type": "Bearer",
+  "not-before-policy": 0,
+  "scope": "openid reports_read reports_write"
+}
+```
+
+2. Request the all available reports: `GET /reports` (see OpenAPI specs for details)
+3. Trigger the calculation of a reports data: `POST /report-calculation/<report-id>`
+4. Get status of the report calculation: `GET /report-calculation/<calculation-id>`
+5. Once the status shows the calculation is completed, get the actual result data: `GET /report-calculation/<calculation-id>/data`
\ No newline at end of file
diff --git a/docs/api-specs/reporting-api-v1.yaml b/docs/api-specs/reporting-api-v1.yaml
new file mode 100644
index 0000000..e72b67e
--- /dev/null
+++ b/docs/api-specs/reporting-api-v1.yaml
@@ -0,0 +1,252 @@
+openapi: 3.0.3
+info:
+  title: Aam Digital - Reporting API
+  description: |-
+    API to manage reports that provide data calculated based on any entities of the Aam Digital system.
+  version: 1.0.0-alpha.1
+servers:
+  - url: https://{customerId}.aam-digital.net/api/v1/reporting
+    description: Developer Instance for testing
+    variables:
+      customerId:
+        default: dev
+        description: Customer ID assigned by the service provider
+tags:
+  - name: report
+
+paths:
+  /report:
+    get:
+      security:
+        - development:
+          - reports_read
+      tags:
+        - report
+      summary: Return list of available Reports
+      responses:
+        200:
+          description: List of all available Reports the requester has access permissions to, empty array if no reports are available
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/Report'
+        401:
+          description: If no valid access token
+
+  /report/{reportId}:
+    get:
+      security:
+        - development:
+          - reports_read
+      tags:
+        - report
+      summary: Return report metadata by ID
+      parameters:
+        - in: path
+          name: reportId
+          schema:
+            type: string
+          required: true
+      responses:
+        200:
+          description: Get details of a report, including details of the data structure (schema) this specific report's data has
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Report'
+        404:
+          description: If the Report does not exist
+        401:
+          description: If the access token does not grant permission to this Report
+
+  /report-calculation/report/{reportId}:
+    get:
+      security:
+        - development:
+          - reports_read
+      tags:
+        - report
+      summary: Return all report calculations for a report
+      parameters:
+        - in: path
+          name: reportId
+          schema:
+            type: string
+          required: true
+      responses:
+        200:
+          description: List of metadata of all calculations triggered by any user (pending and completed)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ReportCalculation'
+        401:
+          description: If the access token does not grant permission to this Report
+        404:
+          description: If report does not exist
+
+    post:
+      security:
+        - development:
+          - reports_write
+      tags:
+        - report
+      summary: Trigger a new report calculation run.
+      description: Trigger a new report calculation run. Check status of the asynchronous calculation via the /report-calculation endpoint
+        (CURRENTLY UNDER DEVELOPMENT) optionally receive status updates via a webhook if that has been set up for the authorized client
+      parameters:
+        - in: path
+          name: reportId
+          schema:
+            type: string
+          required: true
+        - in: query
+          name: from
+          description: start date for report period
+          schema:
+            type: string
+            format: date
+        - in: query
+          name: to
+          description: end date for report period
+          schema:
+            type: string
+            format: date
+      responses:
+        200:
+          description: Return calculation identifier, to be used to check status and result data
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  id:
+                    type: string
+                    format: uuid
+        401:
+          description: If the access token does not grant permission to this Report
+
+  /report-calculation/{calculationId}:
+    get:
+      security:
+        - development:
+          - reports_read
+      tags:
+        - report
+      summary: Return metadata for a report calculation
+      parameters:
+        - in: path
+          name: calculationId
+          schema:
+            type: string
+          required: true
+      responses:
+        200:
+          description: Status and details of the given report calculation run
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/ReportCalculation'
+        401:
+          description: If the access token does not grant permission to this Report
+        404:
+          description: If the calculation identifier does not exist
+
+  /report-calculation/{calculationId}/data:
+    get:
+      security:
+        - development:
+          - reports_read
+      tags:
+        - report
+      summary: Fetch actual report data for a specific calculation
+      parameters:
+        - in: path
+          name: calculationId
+          schema:
+            type: string
+          required: true
+      responses:
+        200:
+          description: The actual data that has been calculated by the calculation run. This matches the schema defined in the /report/id 
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ReportData'
+            application/xml:
+              schema:
+                $ref: '#/components/schemas/ReportData'
+        404:
+          description: report data is not available yet (when either the calculation id is not valid or the calculation is still running)
+        401:
+          description: If the access token does not grant permission to this Report
+
+components:
+  schemas:
+    Report:
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+        name:
+          type: string
+          example: report_all_course_members
+        calculationPending:
+          type: boolean
+        schema:
+          $ref: '#/components/schemas/ReportSchema'
+
+    ReportSchema:
+      type: object
+      properties:
+        fields:
+          type: array
+          items:
+            type: object
+
+    ReportCalculation:
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+        start_date:
+          type: string
+          example: date
+        end_date:
+          type: string
+          example: date
+          nullable: true
+        status:
+          type: string
+          description: Current status of the run
+          enum:
+            - PENDING
+            - RUNNING
+            - FINISHED_SUCCESS
+            - FINISHED_ERROR
+
+    ReportData:
+      type: object
+      properties:
+        reportId:
+          type: string
+          format: uuid
+        data:
+          type: object
+
+  securitySchemes:
+    development:
+      type: oauth2
+      description: This API uses OAuth2 with the Client Credentials Flow
+      flows:
+        clientCredentials:
+          tokenUrl: https://keycloak.aam-digital.net/realms/TolaData/protocol/openid-connect/token
+          scopes:
+            reports_read: Read Report and ReportCalculation
+            reports_write: Trigger new ReportCalculation
diff --git a/docs/assets/keycloak-client-setup.png b/docs/assets/keycloak-client-setup.png
new file mode 100644
index 0000000..454bb59
Binary files /dev/null and b/docs/assets/keycloak-client-setup.png differ