# Applications

Version date: 8 October 2024

***

> To authorize, you need to add the header `"Authorization: Bearer ..."` (get your API KEY in your personal account on "Personal" tab).

## Endpoints

* [Create an App](#create-an-app)
* [List Apps](#list-apps)
* [Get an App](#get-an-app)
* [Archive an App](#archive-an-app)
* [Delete an App](#delete-an-app)
* [Restore an App](#restore-an-app)
* [Update an App](#update-an-app)
* [Update Credentials And Push Provider](#update-credentials-and-push-provider)
* [Get VAPID key](#get-vapid-key)

***

### Create an App

**POST** `https://core.push.express/api/b/v2/apps`

* **Description**: Creates a new app.

Request \[Firebase]:

```bash
curl --url "https://core.push.express/api/b/v2/apps"
    --request POST
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "push_provider": "firebase",
    "name": "appName",
    "link": "https://appurl.com",
    "firebase_creds": {
        "type": "service_account",
        "project_id": "123abc",
        "private_key_id": "123abc",
        "private_key": "-----BEGIN PRIVATE KEY-----\n123abc\n-----END PRIVATE KEY-----\n",
        "client_email": "firebase-viceaccount.com",
        "client_id": "12345",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/fake.iam.gserviceaccount.com",
        "universe_domain": "googleapis.com"
	}
}
'
```

Request \[Onesignal]:

```bash
curl --url "https://core.push.express/api/b/v2/apps"
    --request POST
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "push_provider": "onesignal",
    "name": "appName",
    "link": "https://appurl.com",
    "onesignal_creds": {
        "app_id": "d65749ed-e9b9-4e4a-a309-010f89bae222",
        "api_key": "appkey1223"
    }
}
'
```

Request \[APNs]:

```bash
curl --url "https://core.push.express/api/b/v2/apps"
    --request POST
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "push_provider": "apns",
    "name": "appName",
    "link": "https://appurl.com",
    "apns_creds": {
        "topic": "some.url.fqdn.style",
        "team_id": "123abc",
        "private_key_id": "123abc",
        "private_key": "-----BEGIN PRIVATE KEY-----\n123abc\n-----END PRIVATE KEY-----\n"
  }
}
'
```

Request \[PWA/Web]:

```bash
curl --url "https://core.push.express/api/b/v2/apps"
    --request POST
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "push_provider": "webpush",
    "name": "appName PWA",
    "link": "https://appurl.com",
}
'
```

Body params:

* `push_provider`, *required*. Lowercase, must be one of `firebase`, `onesignal`, `apns`, `webpush`.
* `name`, *required*. Application name, any printable characters.
* `push_provider_creds`, *required*. If transport is `firebase` - you need to insert `Firebase Admin SDK IAM key`, same as on the website, it must be a valid JSON. If transport is `onesignal` - you need to provide the key and app ID for OneSignal. If transport is `apns` - provide the APNS credentials including the topic, team ID, authentication key and authentication key ID. If the transport is `webpush`, credentials are not transmitted.
* `link`, *optional*. Link to the Play Market / App Store / etc.

Response:

* 201: New application created

```json
{"id":12345}
```

* `id`, *int*. ID of newly created application.

> If an application has successfully been created then it was automatically added to groups and schedulers which are set to include all apps.

***

### List Apps

**GET** `https://core.push.express/api/b/v2/apps`

* **Description**: Retrieves a list of all apps

> No more then 10000 records can be returned

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps?archived=false"
    --request GET
    --header "Authorization: Bearer ..."
```

Query parameters:

* `archived`, *bool, optional*. Filters archived apps if *true*, otherwise returns active apps.

Response:

* 200: List of applications retrieved

```json
[
"apps": [
    {
        "id":1234,
        "pushexpress_id": "1234-5678",
        "push_provider":"onesignal",
        "name":"appName",
        "link":"https://appurl.com",
        "groups":
        [
            {"id":1,
            "name":"groupName"
            },
            ...
        ],
        "has_firebase_creds":false,
        "has_apns_creds":false,
        "has_onesignal_creds":true, 
        "archived":false
    },
    ...
],
]
```

If user does't own any applications yet then response is an empty list.

* `id`, *int*. ID of application for API.
* `pushexpress_id`, *string*. ID of application for SDK.
* `push_provider`, `name`, `link` see [Create an App](#create-an-app).
* `groups`, *json*. List of all groups that include current app. If an app is not included into any group then `groups` is an empty list.

> PushExpress provides an opportunity to add applications to groups. Full list of groups one owns can be observed [here](https://app.push.express/app/group/) (authentification required).

* `has_firebase_creds`, `has_apns_creds`, `has_onesignal_creds`, *bool*. *True* if all components of corresponding credentials are not empty. *False* if any component missed. List of creds components for each provider type see in [Create an App](#create-an-app).
* `archived`, *bool*. *True* if app archived, *false* otherwise.

**Pagination:**

Now supports one type of pagination:

1. **Page-based pagination** - for UI with numbered pages (limited to 10K records).

**Page-based**

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps?archived=false&page=2&per_page=50"
    --request GET
    --header "Authorization: Bearer ..."
```

Query parameters:

* `archived`, *bool, optional*. Filters archived apps if *true*, otherwise returns active apps.
* `page`, *int, optional*. Page number.
* `per_page`, *int, optional*. The number of entries per page.

````

Response:
```json
{
  "apps": [
		{
			"id": 25330,
			"pushexpress_id": "25330-1269",
			"push_provider": "apns",
			"name": "abcdабвг-3",
			"link": "https://qqw.com",
			"groups": [],
			"has_firebase_creds": false,
			"has_apns_creds": true,
			"has_onesignal_creds": false,
			"archived": false
		},
        ...
	],
  "pagination": {
    "page": 2,
    "per_page": 50,
    "total_pages": 15,
    "total_count": 705
  }
}
````

* `pagination`, *object*. Pagination metadata.
* `pagination.page`, *int*. Current page number.
* `pagination.per_page`, *int*. Records per page.
* `pagination.total_pages`, *int*. Total number of pages.
* `pagination.total_count`, *int*. Total matching records.

**Limit:** Max offset = 10,000 records. UI with numbered pages \[1] \[2] \[3]. Small/medium datasets.

***

### Get an App

**GET** `https://core.push.express/api/b/v2/apps/:app_id`

* **Description**: Retrieves details of a specific app by its ID.

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id"
    --request GET
    --header "Authorization: Bearer ..."
```

Response:

* 200: Application info retrieved

```json
{
    "id":1234,
    "push_provider":"onesignal",
    "name":"appName",
    "link":"https://appurl.com",
    "groups":
    [
        {"id":1,
        "name":"groupName"
        },
        ...
    ],
    "has_firebase_creds":false,
    "has_apns_creds":false,
    "has_onesignal_creds":true, 
    "archived":false
}
```

Details on response can see in [List Apps](#list-apps)

***

### Archive an App

**POST** `https://core.push.express/api/b/v2/apps/:app_id/archive`

* **Description**: Archives a specific app by its ID. This actions is idempotent, i.e. double archiving is valid.

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/archive"
    --request POST
    --header "Authorization: Bearer ..."
```

Response:

* 204: No content

> If an application has successfully been archived then it was automatically removed from all groups and schedulers.

***

### Delete an App

**DELETE** `https://core.push.express/api/b/v2/apps/:app_id`

* **Description**: Deletes a specific app by its ID.

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/archive"
    --request DELETE
    --header "Authorization: Bearer ..."
```

Response:

* 204: No content

> If an application has successfully been deleted then it was automatically removed from all groups and schedulers.

***

### Restore an App

**POST** `https://core.push.express/api/b/v2/apps/:app_id/unarchive`

* **Description**: Restores a specific app by its ID. This actions is idempotent, i.e. double unarchiving is valid.

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/unarchive"
    --request POST
    --header "Authorization: Bearer ..."
```

Response:

* 204: No content

> To restore an application does NOT mean to restore all devices it had in the very same moment. Devices will be restored only through a process of syncronization or sdk activity.

***

### Update an App

**PUT** `https://core.push.express/api/b/v2/apps/:app_id`

* **Description**: Updates the base information of a specific app by its ID.

Request:

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id"
    --request PUT
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "name": "appName",
    "link": "https://appurl.com"
}
'
```

Response:

* 204: No content

***

### Update Credentials And Push Provider

**PUT** `https://core.push.express/api/b/v2/apps/:app_id/creds/:push_provider`

* **Description**: Updates **both** credentials and push provider for a specific app.

Request \[Firebase]:

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/creds/firebase"
    --request PUT
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "type": "service_account",
    "project_id": "123abc",
    "private_key_id": "123abc",
    "private_key": "-----BEGIN PRIVATE KEY-----\n123abc\n-----END PRIVATE KEY-----\n",
    "client_email": "firebase-viceaccount.com",
    "client_id": "12345",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/fake.iam.gserviceaccount.com",
    "universe_domain": "googleapis.com"
}
'
```

Request \[Onesignal]:

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/creds/onesignal"
    --request PUT
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "app_id": "d65749ed-e9b9-4e4a-a309-010f89bae222",
    "api_key": "appkey1223"
}
'
```

Request \[APNs]:

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/creds/apns"
    --request PUT
    --header "content-type: application/json"
    --header "Authorization: Bearer ..."
    --data '
{
    "topic": "some.url.fqdn.style",
    "team_id": "123abc",
    "private_key_id": "123abc",
    "private_key": "-----BEGIN PRIVATE KEY-----\n123abc\n-----END PRIVATE KEY-----\n"
}
'
```

Response:

* 204: No content

***

### Get VAPID key

**GET** `https://core.push.express/api/b/v2/apps/:app_id/vapidkey`

* **Description**: Retrieves vapid key of a specific app by its ID.

Request

```bash
curl --url "https://core.push.express/api/b/v2/apps/:app_id/vapidkey"
    --request GET
    --header "Authorization: Bearer ..."
```

Response:

* 200: Vapid key for app

```json
{"vapid_key_public":"BNIh3BEkoOIt15NJhbcf0XptMQOPFs9WwdRRehtb8k8WbvY9544R5yURPeX3-jN_hQbrg-KYH8-2FGeOfFs9rdQ"} 
```

***

## Error handling

All HTTP response codes 2xx SHOULD be considered as success. Requested action was executed successfully.

All HTTP response codes above 400 MUST be considered as error. Requested action failed. Retries policy should be hold according to HTTP specification.

Common API errors:

* 400 - request error. Request has invalid data. Check you request (url, headers, payload)
* 401 is returned when provided API token is invalid. Check your authentification data.
* 404 is returned when resource doesn't exist. Check your request data.

  Example: **PUT** `https://core.push.express/api/b/v2/apps/:app_id` returns 404 when provided `app_id` doesn't exist
* All HTTP response codes 5xx - other errors from proxy servers, load balancers, etc. There may or may not have some explanation in response body. These errors always require retries.

**API errors** have `content-type: application/json` header and json response body

Example: `{"error": "validation error: ...", "req_id":"<string>"}`

Response parameters:

* `req_id` *string* is a request ID. It is used by support for problem solving, please, provide it to support if problem emerged.
* `error` object, describing errors.

**Non-API errors** like 502, 504, etc., may or may not include a description.
