summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/admin.md40
-rw-r--r--docs/api/api-v1-2.md (renamed from docs/api/api-v1.md)325
-rw-r--r--docs/api/api-v1-3.md874
-rw-r--r--docs/api/api-v2.md83
-rw-r--r--docs/clients.md9
-rw-r--r--docs/developer.md56
-rw-r--r--docs/faq.md108
-rw-r--r--docs/features/customCSS.md7
-rw-r--r--docs/features/integration.md30
-rw-r--r--docs/features/plugins.md178
-rw-r--r--docs/features/themes.md3
-rw-r--r--docs/install.md67
-rw-r--r--docs/troubleshooting.md168
13 files changed, 1587 insertions, 361 deletions
diff --git a/docs/admin.md b/docs/admin.md
index 00efe0d20..8a180fbb0 100644
--- a/docs/admin.md
+++ b/docs/admin.md
@@ -1,33 +1,55 @@
# Admin
+
Welcome to the Admin documentation this page explains some of the configuration options for news.
+
## System Cron
-Nextcloud uses Cron to run regular jobs, News relies on the Job system to execute the feed updates.
+
+Nextcloud uses cron to run regular jobs, News relies on the Job system to execute the feed updates.
Alternatively you may use an [external updater](https://nextcloud.github.io/news/clients/#update-clients), in this case you need to disable the system cron in the settings.
## Auto purge count
-This value represents the maximum amount of read items per feed, which won't be deleted by the cleanup job.
-For example if the value is 200 there can be maximum 200 read items per feed, unread items are unaffected.
-If old articles reappear after being read, try to increase this value.
-To disable this feature use -1.
+
+- The default value is 200.
+- To disable this feature, use -1.
+- Unread and starred items are not deleted.
+
+Auto purging automatically removes the oldest read items of every feed after every update.
+The value you enter here is used as the limit of read items per feed, unless the feed comes with more items in it's feed.
+The individual limit per feed is only adjusted when it's bigger. Let's say last feed update came with 210 items,
+then that will be the limit for that feed as long as no bigger update with more items is fetched.
+In this case the limit will be 210 instead of 200, for that feed.
+
+This is needed to prevent items from reappearing in the feed.
+
+## Purge unread items
+
+This changes the behavior of the auto purging to also purge unread items. This is useful if you have users with a lot of unread items.
+
+**Starred items are always kept.**
## Explore Service
-If you are using the News app in your company/community it might be interesting to offer your users a bunch of easily to discover default feeds. You could also create a website where people can add and up-vote news feeds like bigger cloud feed readers like Feedly do it or even convert their APIs into a service for the News app (if someone wants to provide one for the News app, feel free to contact us by creating an issue in the bug tracker).
+
+If you are using the News app in your company/community, it might be interesting to offer your users a bunch of easily to discover default feeds. You could also create a website where people can add and up-vote news feeds like bigger cloud feed readers like Feedly do it or even convert their APIs into a service for the News app (if someone wants to provide one for the News app, feel free to contact us by creating an issue in the bug tracker).
The URL should be a path to a directory which contains a JSON file in the format of **feeds.LANG_CODE.json** where LANG_CODE is a two character language code (e.g. **en** or **de**).
-For example, entering the URL **https://domain.com/directory** as explore URL will produce the following request for German users:
+For example, entering the URL **<https://domain.com/directory>** as explore URL will produce the following request for German users:
GET https://domain.com/directory/feeds.de.json
**Do not forget to implement [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) in your API, otherwise the request will fail!**
## Update Interval
+
The update interval is used to determine when the next update of all feeds should be done.
-You can configure this interval as an administrator.
+By default, the value is set to 3600 seconds (1 hour) You can configure this interval as an administrator.
+The new value is only applied after the next run of the updater.
### What is a good update interval?
+
That depends on your individual needs.
Please keep in mind that the lower you set your update interval, the more traffic is generated.
### Can I set individual update intervals per feed/user?
-No, the job framework of Nextcloud is pretty simple. \ No newline at end of file
+
+No, that is not possible.
diff --git a/docs/api/api-v1.md b/docs/api/api-v1-2.md
index fd7575e75..e70eb9b73 100644
--- a/docs/api/api-v1.md
+++ b/docs/api/api-v1-2.md
@@ -23,6 +23,7 @@ You have to design your app with these things in mind!:
* **Use a library to compare versions, ideally one that uses semantic versioning**
## Authentication & Basics
+
Because REST is stateless you have to send user and password each time you access the API. Therefore running Nextcloud **with SSL is highly recommended** otherwise **everyone in your network can log your credentials**.
The base URL for all calls is:
@@ -42,11 +43,13 @@ where $CREDENTIALS is:
base64(USER:PASSWORD)
## How To Sync
+
This is a small overview over how you should sync your articles with the Nextcloud News app. For more fine-grained details about the API see further down.
-All routes are given relative to the base API url (e.g.: https://yournextcloud.com/index.php/apps/news/api/v1-2)
+All routes are given relative to the base API url (e.g.: <https://yournextcloud.com/index.php/apps/news/api/v1-2>)
### Initial Sync
+
The intial sync happens, when a user adds a Nextcloud account in your app. In that case you should fetch all feeds, folders and unread or starred articles from the News app. Do not fetch all articles, not only because it syncs faster, but also because the user is primarily interested in unread articles. To fetch all unread and starred articles, you must call 4 routes:
* **unread articles**: GET /items?type=3&getRead=false&batchSize=-1
@@ -57,6 +60,7 @@ The intial sync happens, when a user adds a Nextcloud account in your app. In th
The JSON response structures can be viewed further down.
### Syncing
+
When syncing, you want to push read/unread and starred/unstarred items to the server and receive new and updated items, feeds and folders. To do that, call the following routes:
* **Notify the News app of unread articles**: PUT /items/unread/multiple {"items": [1, 3, 5] }
@@ -67,31 +71,32 @@ When syncing, you want to push read/unread and starred/unstarred items to the se
* **Get new feeds**: GET /feeds
* **Get new items and modified items**: GET /items/updated?lastModified=12123123123&type=3
-
## Accessing API from a web application
**News 1.401** implements CORS which allows web applications to access the API. **To access the API in a webapp you need to send the correct authorization header instead of simply putting auth data into the URL!**. An example request in jQuery would look like this:
```js
$.ajax({
- type: 'GET',
- url: 'https://yournextcloud.com/index.php/apps/news/api/v1-2/version',
- contentType: 'application/json',
- success: function (response) {
- // handle success
- },
- error: function () {
- // handle errors
- },
- beforeSend: function (xhr) {
- var username = 'john';
- var password = 'doe';
- var auth = btoa(username + ':' + password);
- xhr.setRequestHeader('Authorization', 'Basic ' + auth);
- }
+ type: 'GET',
+ url: 'https://yournextcloud.com/index.php/apps/news/api/v1-2/version',
+ contentType: 'application/json',
+ success: function (response) {
+ // handle success
+ },
+ error: function () {
+ // handle errors
+ },
+ beforeSend: function (xhr) {
+ var username = 'john';
+ var password = 'doe';
+ var auth = btoa(username + ':' + password);
+ xhr.setRequestHeader('Authorization', 'Basic ' + auth);
+ }
});
```
+
An example with AngularJS would look like this:
+
```js
angular.module('YourApp', [])
.config(['$httpProvider', '$provide', function ($httpProvider, $provide) {
@@ -129,14 +134,17 @@ angular.module('YourApp', [])
```
## Input
+
In general the input parameters can be in the URL or request body, the App Framework doesnt differentiate between them.
So JSON in the request body like:
-```jsonc
+
+```json
{
"id": 3
}
```
+
will be treated the same as
/?id=3
@@ -149,17 +157,22 @@ It is recommended though that you use the following convention:
* **DELETE**: parameters as JSON in the request body
## Output
+
The output is JSON.
-# Folders
-## Get all folders
+## API Endpoints
+
+### Folders
+
+#### Get all folders
* **Status**: Implemented
* **Method**: GET
* **Route**: /folders
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"folders": [
{
@@ -170,23 +183,27 @@ The output is JSON.
}
```
-## Create a folder
+#### Create a folder
+
Creates a new folder and returns a new folder object
* **Status**: Implemented
* **Method**: POST
* **Route**: /folders
* **Parameters**:
-```jsonc
+
+```json
{
"name": "folder name"
}
```
+
* **Return codes**:
- * **HTTP 409**: If the folder exists already
- * **HTTP 422**: If the folder name is invalid (for instance empty)
+* **HTTP 409**: If the folder exists already
+* **HTTP 422**: If the folder name is invalid (for instance empty)
* **Returns**:
-```jsonc
+
+```json
{
"folders": [
{
@@ -197,7 +214,8 @@ Creates a new folder and returns a new folder object
}
```
-## Delete a folder
+#### Delete a folder
+
Deletes a folder with the id folderId and all the feeds it contains
* **Status**: Implemented
@@ -205,61 +223,67 @@ Deletes a folder with the id folderId and all the feeds it contains
* **Route**: /folders/{folderId}
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the folder does not exist
+* **HTTP 404**: If the folder does not exist
* **Returns**: nothing
-## Rename a folder
+#### Rename a folder
+
Only the name can be updated
* **Status**: Implemented
* **Method**: PUT
* **Route**: /folders/{folderId}
* **Parameters**:
-```jsonc
+
+```json
{
"name": "folder name"
}
```
+
* **Return codes**:
- * **HTTP 409**: If the folder name does already exist
- * **HTTP 404**: If the folder does not exist
- * **HTTP 422**: If the folder name is invalid (for instance empty)
+* **HTTP 409**: If the folder name does already exist
+* **HTTP 404**: If the folder does not exist
+* **HTTP 422**: If the folder name is invalid (for instance empty)
* **Returns**: nothing
-## Mark items of a folder as read
+#### Mark items of a folder as read
* **Status**: Implemented
* **Method**: PUT
* **Route**: /folders/{folderId}/read
* **Parameters**:
-```jsonc
+
+```json
{
// mark all items read lower than equal that id
// this is mean to prevent marking items as read which the client/user does not yet know of
"newestItemId": 10
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
-# Feeds
+### Feeds
-## Sanitation
+#### Sanitation
The following attributes are **not sanitized** meaning: including them in your web application can lead to XSS:
* **title**
* **link**
-## Get all feeds
+#### Get all feeds
* **Status**: Implemented
* **Method**: GET
* **Route**: /feeds
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"feeds": [
{
@@ -287,24 +311,28 @@ The following attributes are **not sanitized** meaning: including them in your w
}
```
-## Create a feed
+#### Create a feed
+
Creates a new feed and returns the feed
* **Status**: Implemented
* **Method**: POST
* **Route**: /feeds
* **Parameters**:
-```jsonc
+
+```json
{
"url": "http:\/\/www.cyanogenmod.org\/wp-content\/themes\/cyanogenmod\/images\/favicon.ico",
"folderId": 81 // id of the parent folder, null for root
}
```
+
* **Return codes**:
- * **HTTP 409**: If the feed exists already
- * **HTTP 422**: If the feed cant be read (most likely contains errors)
+* **HTTP 409**: If the feed exists already
+* **HTTP 422**: If the feed cant be read (most likely contains errors)
* **Returns**:
-```jsonc
+
+```json
{
"feeds": [
{
@@ -324,7 +352,8 @@ Creates a new feed and returns the feed
}
```
-## Delete a feed
+#### Delete a feed
+
Deletes a feed with the id feedId and all of its items
* **Status**: Implemented
@@ -332,60 +361,65 @@ Deletes a feed with the id feedId and all of its items
* **Route**: /feeds/{feedId}
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
-## Move a feed to a different folder
+#### Move a feed to a different folder
* **Status**: Implemented
* **Method**: PUT
* **Route**: /feeds/{feedId}/move
* **Parameters**:
-```jsonc
+
+```json
{
"folderId": null // id of the parent folder, null for root
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
-## Rename a feed
+#### Rename a feed
* **Status**: Implemented in 1.807
* **Method**: PUT
* **Route**: /feeds/{feedId}/rename
* **Parameters**:
-```jsonc
+
+```json
{
"feedTitle": "New Title"
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
-## Mark items of a feed as read
+#### Mark items of a feed as read
* **Status**: Implemented
* **Method**: PUT
* **Route**: /feeds/{feedId}/read
* **Parameters**:
-```jsonc
+
+```json
{
// mark all items read lower than equal that id
// this is mean to prevent marking items as read which the client/user does not yet know of
"newestItemId": 10
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
+### Items
-# Items
-
-## Sanitation
+#### Sanitation
The following attributes are **not sanitized** meaning: including them in your web application can lead to XSS:
@@ -397,12 +431,39 @@ The following attributes are **not sanitized** meaning: including them in your w
* **mediaThumbnail**
* **mediaDescription**
-## Get items
+#### Types
+
+| Name | Default | Types |
+|------------------|---------|--------------|
+| author | null | string\|null |
+| body | | string\|null |
+| contentHash | | string\|null |
+| enclosureLink | | string\|null |
+| enclosureMime | | string\|null |
+| feedId | | int |
+| fingerprint | | string\|null |
+| guid | | string |
+| guidHash | | string |
+| id | | int |
+| lastModified | \"0\" | string\|null |
+| mediaDescription | | string\|null |
+| mediaThumbnail | | string\|null |
+| pubDate | | int\|null |
+| rtl | false | bool |
+| starred | false | bool |
+| title | | string\|null |
+| unread | false | bool |
+| updatedDate | | string\|null |
+| url | | string\|null |
+
+#### Get items
+
* **Status**: Implemented
* **Method**: GET
* **Route**: /items
* **Parameters**:
-```jsonc
+
+```json
{
"batchSize": 10, // the number of items that should be returned, defaults to -1, new in 5.2.3: -1 returns all items
"offset": 30, // only return older (lower than equal that id) items than the one with id 30
@@ -412,8 +473,10 @@ The following attributes are **not sanitized** meaning: including them in your w
"oldestFirst": false // implemented in 3.002, if true it reverse the sort order
}
```
+
* **Returns**:
-```jsonc
+
+```json
{
"items": [
{
@@ -440,13 +503,15 @@ The following attributes are **not sanitized** meaning: including them in your w
}
```
-### Example
+##### Example
+
Autopaging would work like this:
* Get the **first 20** items from a feed with **id 12**
**GET /items**:
-```jsonc
+
+```json
{
"batchSize": 20,
"offset": 0,
@@ -460,7 +525,7 @@ The item with the lowest item id is 43.
* Get the next **20** items: **GET /items**:
-```jsonc
+```json
{
"batchSize": 20,
"offset": 43,
@@ -470,15 +535,16 @@ The item with the lowest item id is 43.
}
```
+#### Get updated items
-## Get updated items
This is used to stay up to date.
* **Status**: Implemented
* **Method**: GET
* **Route**: /items/updated
* **Parameters**:
-```jsonc
+
+```json
{
"lastModified": 123231, // returns only items with a lastModified timestamp >= than this one
// this may also return already existing items whose read or starred status
@@ -487,8 +553,10 @@ This is used to stay up to date.
"id": 12 // the id of the folder or feed, Use 0 for Starred and All
}
```
+
* **Returns**:
-```jsonc
+
+```json
{
"items": [
{
@@ -512,63 +580,74 @@ This is used to stay up to date.
}
```
-## Mark an item as read
+#### Mark an item as read
+
* **Status**: Implemented
* **Method**: PUT
* **Route**: /items/{itemId}/read
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the item does not exist
+* **HTTP 404**: If the item does not exist
* **Returns**: nothing
-## Mark multiple items as read
+#### Mark multiple items as read
+
* **Status**: Implemented in 1.2
* **Method**: PUT
* **Route**: /items/read/multiple
* **Parameters**:
-```jsonc
+
+```json
{
"items": [2, 3] // ids of the items
}
```
+
* **Returns**: nothing
-## Mark an item as unread
+#### Mark an item as unread
+
* **Status**: Implemented
* **Method**: PUT
* **Route**: /items/{itemId}/unread
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the item does not exist
+* **HTTP 404**: If the item does not exist
* **Returns**: nothing
-## Mark multiple items as unread
+#### Mark multiple items as unread
+
* **Status**: Implemented in 1.2
* **Method**: PUT
* **Route**: /items/unread/multiple
* **Parameters**:
-```jsonc
+
+```json
{
"items": [2, 3] // ids of the items
}
```
+
* **Returns**: nothing
-## Mark an item as starred
+#### Mark an item as starred
+
* **Status**: Implemented
* **Method**: PUT
* **Route**: /items/{feedId}/{guidHash}/star
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the item does not exist
+* **HTTP 404**: If the item does not exist
* **Returns**: nothing
-## Mark multiple items as starred
+#### Mark multiple items as starred
+
* **Status**: Implemented in 1.2
* **Method**: PUT
* **Route**: /items/star/multiple
* **Parameters**:
-```jsonc
+
+```json
{
"items": [
{
@@ -578,23 +657,27 @@ This is used to stay up to date.
]
}
```
+
* **Returns**: nothing
-## Mark an item as unstarred
+#### Mark an item as unstarred
+
* **Status**: Implemented
* **Method**: PUT
* **Route**: /items/{feedId}/{guidHash}/unstar
* **Parameters**: none
* **Return codes**:
- * **HTTP 404**: If the item does not exist
+* **HTTP 404**: If the item does not exist
* **Returns**: nothing
-## Mark multiple items as unstarred
+#### Mark multiple items as unstarred
+
* **Status**: Implemented in 1.2
* **Method**: PUT
* **Route**: /items/unstar/multiple
* **Parameters**:
-```jsonc
+
+```json
{
"items": [
{
@@ -604,27 +687,29 @@ This is used to stay up to date.
]
}
```
+
* **Returns**: nothing
-## Mark all items as read
+#### Mark all items as read
* **Status**: Implemented
* **Method**: PUT
* **Route**: /items/read
* **Parameters**:
-```jsonc
+
+```json
{
// mark all items read lower than equal that id
// this is mean to prevent marking items as read which the client/user does not yet know of
"newestItemId": 10
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: nothing
-
-# Updater
+### Updater
To enable people to write their own update scripts instead of relying on the sequential built in web and system cron, API routes and console commands have been created.
@@ -637,7 +722,8 @@ Updating should be done in the following fashion:
This [implementation in Python](https://github.com/nextcloud/news-updater) should give you a good idea how to design and run it.
-## Trigger cleanup before update
+#### Trigger cleanup before update
+
This is used to clean up the database. It deletes folders and feeds that are marked for deletion
* **Status**: Implemented in 1.601
@@ -648,9 +734,11 @@ This is used to clean up the database. It deletes folders and feeds that are mar
**New in 8.1.0**: The console command for achieving the same result is:
- php -f nextcloud/occ news:updater:before-update
+```bash
+php -f nextcloud/occ news:updater:before-update
+```
-## Get feed ids and usernames for all feeds
+#### Get feed ids and usernames for all feeds
* **Status**: Implemented in 1.203
* **Authentication**: Requires admin user
@@ -658,7 +746,8 @@ This is used to clean up the database. It deletes folders and feeds that are mar
* **Route**: /feeds/all
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"feeds": [
{
@@ -671,31 +760,37 @@ This is used to clean up the database. It deletes folders and feeds that are mar
**New in 8.1.0, Removed in 16.0.0**: The console command for achieving the same result is:
- php -f nextcloud/occ news:updater:all-feeds
-
+```bash
+php -f nextcloud/occ news:updater:all-feeds
+```
-## Trigger a feed update
+#### Trigger a feed update
* **Status**: Implemented in 1.601
* **Authentication**: Requires admin user
* **Method**: GET
* **Route**: /feeds/update
* **Parameters**:
-```jsonc
+
+```json
{
"userId": "john",
"feedId": 3
}
```
+
* **Return codes**:
- * **HTTP 404**: If the feed does not exist
+* **HTTP 404**: If the feed does not exist
* **Returns**: Nothing
**New in 8.1.0**: The console command for achieving the same result is:
- php -f nextcloud/occ news:updater:update-feed 3 john
+```bash
+php -f nextcloud/occ news:updater:update-feed 3 john
+```
+
+#### Trigger cleanup after update
-## Trigger cleanup after update
This is used to clean up the database. It removes old read articles which are not starred
* **Status**: Implemented in 1.601
@@ -706,35 +801,39 @@ This is used to clean up the database. It removes old read articles which are no
**New in 8.1.0**: The console command for achieving the same result is:
- php -f nextcloud/occ news:updater:after-update
+```bash
+php -f nextcloud/occ news:updater:after-update
+```
-# Version
+### Version
-## Get the version
+#### Get the version
* **Status**: Implemented
* **Method**: GET
* **Route**: /version
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"version": "5.2.3"
}
```
-# Status
+### Status
This API can be used to display warnings and errors in your client if the web app is improperly configured or not working. It is a good idea to call this route on like every 10th update and after the server connection parameters have been changed since it's likely that the user set up a new instance and configured the app improperly.
-## Get the status
+#### Get the status
* **Status**: Implemented in 5.2.4
* **Method**: GET
* **Route**: /status
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"version": "5.2.4",
"warnings": {
@@ -755,22 +854,24 @@ You should show the following warning and the link should be clickable:
If **incorrectDbCharset** is true you should display a warning that database charset is set up incorrectly and updates with unicode characters might fail
-# User
+### User
This API can be used to retrieve metadata about the current user.
DEPRECATED: This API is deprecated, use the Nextcloud APIs instead.
-- https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-api-overview.html#user-metadata for user data
-- `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar
-## Get the status
+* <https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-api-overview.html#user-metadata> for user data
+* `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar
+
+#### Get the status
* **Status**: Implemented in 6.0.5
* **Method**: GET
* **Route**: /user
* **Parameters**: none
* **Returns**:
-```jsonc
+
+```json
{
"userId": "john",
"displayName": "John Doe",
diff --git a/docs/api/api-v1-3.md b/docs/api/api-v1-3.md
new file mode 100644
index 000000000..e0c28906d
--- /dev/null
+++ b/docs/api/api-v1-3.md
@@ -0,0 +1,874 @@
+# External API v1-3
+
+The **News app 1.3** offers a RESTful API.
+
+## API stability contract
+
+The API level will **change** if the following occurs:
+
+* A field of an object is removed
+* A field of an object has a different datatype
+* The meaning of an API call changes
+
+The API level will **not change** if:
+
+* The app version is changed (e.g. 4.0.1.2 instead of 4.0 or 4.001)
+* A new attribute is added (e.g. each item gets a new field "something": 1)
+* The order of the JSON attributes is changed on any level (e.g. "id":3 is not the first field anymore, but the last)
+
+You have to design your app with these things in mind!:
+
+* **Don't depend on the order of object attributes. In JSON it does not matter where the object attribute is since you access the value by name, not by index**
+* **Don't limit your app to the currently available attributes. New ones might be added. If you don't handle them, ignore them**
+* **Use a library to compare versions, ideally one that uses semantic versioning**
+
+## Authentication & Basics
+
+Because REST is stateless you have to send user and password each time you access the API. Therefore running Nextcloud **with SSL is highly recommended** otherwise **everyone in your network can log your credentials**.
+
+The base URL for all calls is:
+
+ https://yournextcloud.com/index.php/apps/news/api/v1-3/
+
+All defined routes in the Specification are appended to this url. To access all feeds for instance use this url:
+
+ https://yournextcloud.com/index.php/apps/news/api/v1-3/feeds
+
+Credentials need to be passed as an HTTP header using [HTTP basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side):
+
+ Authorization: Basic $CREDENTIALS
+
+where $CREDENTIALS is:
+
+ base64(USER:PASSWORD)
+
+## How To Sync
+
+This is a small overview over how you should sync your articles with the Nextcloud News app. For more fine-grained details about the API see further down.
+
+All routes are given relative to the base API url (e.g.: <https://yournextcloud.com/index.php/apps/news/api/v1-3>)
+
+### Initial Sync
+
+The intial sync happens, when a user adds a Nextcloud account in your app. In that case you should fetch all feeds, folders and unread or starred articles from the News app. Do not fetch all articles, not only because it syncs faster, but also because the user is primarily interested in unread articles. To fetch all unread and starred articles, you must call 4 routes:
+
+* **unread articles**: GET /items?type=3&getRead=false&batchSize=-1
+* **starred articles**: GET /items?type=2&getRead=true&batchSize=-1
+* **folders**: GET /folders
+* **feeds**: GET /feeds
+
+The JSON response structures can be viewed further down.
+
+### Syncing
+
+When syncing, you want to push read/unread and starred/unstarred items to the server and receive new and updated items, feeds and folders. To do that, call the following routes:
+
+* **Notify the News app of unread articles**: PUT /items/unread/multiple {"items": [1, 3, 5]}
+* **Notify the News app of read articles**: PUT /items/read/multiple {"items": [1, 3, 5]}
+* **Notify the News app of starred articles**: PUT /items/starred/multiple {"itemIds": [1, 3, 5]}
+* **Notify the News app of unstarred articles**: PUT /items/unstarred/multiple {"itemIds": [1, 3, 5]}
+* **Get new folders**: GET /folders
+* **Get new feeds**: GET /feeds
+* **Get new items and modified items**: GET /items/updated?lastModified=12123123123&type=3
+
+## Accessing API from a web application
+
+**News 1.401** implements CORS which allows web applications to access the API. **To access the API in a webapp you need to send the correct authorization header instead of simply putting auth data into the URL!**. An example request in jQuery would look like this:
+
+```js
+$.ajax({
+ type: 'GET',
+ url: 'https://yournextcloud.com/index.php/apps/news/api/v1-3/version',
+ contentType: 'application/json',
+ success: function (response) {
+ // handle success
+ },
+ error: function () {
+ // handle errors
+ },
+ beforeSend: function (xhr) {
+ var username = 'john';
+ var password = 'doe';
+ var auth = btoa(username + ':' + password);
+ xhr.setRequestHeader('Authorization', 'Basic ' + auth);
+ }
+});
+```
+
+An example with AngularJS would look like this:
+
+```js
+angular.module('YourApp', [])
+ .config(['$httpProvider', '$provide', function ($httpProvider, $provide) {
+ $provide.factory('AuthInterceptor', ['Credentials', '$q', function (Credentials, $q) {
+ return {
+ request: function (config) {
+ // only set auth headers if url matches the api url
+ if(config.url.indexOf(Credentials.url) === 0) {
+ auth = btoa(Credentials.userName + ':' + Credentials.password);
+ config.headers['Authorization'] = 'Basic ' + auth;
+ }
+ return config || $q.when(config);
+ }
+ };
+ }]);
+ $httpProvider.interceptors.push('AuthInterceptor');
+ }])
+ .factory('Credentials', function () {
+ return {
+ userName: 'user',
+ password: 'password',
+ url: 'https://yournextcloud.com/index.php/apps/news/api'
+ };
+ })
+ .run(['$http', function($http) {
+ $http({
+ method: 'GET',
+ url: 'https://yournextcloud.com/index.php/apps/news/api/v1-3/version'
+ }).success(function (data, status, header, config) {
+ // handle success
+ }).error(function (data, status, header, config) {
+ // handle error
+ });
+ }]);
+```
+
+## Input
+
+In general the input parameters can be in the URL or request body, the App Framework doesnt differentiate between them.
+
+So JSON in the request body like:
+
+```json