# Newstart InApp (Webhooks)

{% hint style="danger" %}
**DISCLAIMER**

*Product Information contained within this document, including technical information and functional specifications, is subject to change without notice. Naviga reserves the right to make any changes to the information in this document at any time without notice. Naviga makes no warranty, representation, or guarantee regarding the suitability of its products and services for any particular purpose.*
{% endhint %}

## Introduction

New subscriptions that have been created through InApp marketplaces rather than through the Naviga Subscribe platform are referred to as "Newstart InApp" subscriptions. This page provides an overview of the steps that must be followed in order to successfully migrate a client from the previous External Payments system to the new Webhooks system.

This will allow the client to begin processing the new InApp Newstart that will be created from an external app using PurchaseAPI, as well as the Webhooks notification that will be created from the external markets using Webhooks API.

## Before You Start

A minimum Subscribe version of *<mark style="color:red;">3.16.3.6</mark> and above* is required to use the new InApp endpoints.

## Client Implementation Steps

## 1. Client-side Market Configuration <a href="#id-2.-set-client-side-market-configuration" id="id-2.-set-client-side-market-configuration"></a>

* In order to make sure that the notifications have been correctly received, it will be necessary to set up the authentication credentials, such as API keys, access tokens, etc., that have been associated with the in-app market.<br>

  <table><thead><tr><th width="139">Market</th><th>Details</th></tr></thead><tbody><tr><td><mark style="color:blue;">Google</mark></td><td>Credentials should be in JavaScript Object Notation (<mark style="color:red;">JSON</mark>) format.</td></tr><tr><td><mark style="color:purple;">Apple V1</mark></td><td>Credentials should be in <mark style="color:red;">String</mark> format of 32 characters.</td></tr><tr><td><mark style="color:orange;">Apple V2</mark></td><td>Credentials should be in <mark style="color:red;">String</mark> format of 32 characters.</td></tr></tbody></table>

* The URL of the Webhook has to be updated in the specific marketplace console (Google, Apple V1, Apple V2) in order to receive the notification status information in the new Webhooks flow.<br>

  <table><thead><tr><th width="138">Market</th><th>Details</th></tr></thead><tbody><tr><td><mark style="color:blue;">Google</mark></td><td>POST  “Webhooks/Google/{MediaGroup}/{ClientCode}/{PaperCode}” </td></tr><tr><td><mark style="color:purple;">Apple V1</mark></td><td>POST “Webhooks/Apple/V1/{MediaGroup}/{ClientCode}/{PaperCode}”</td></tr><tr><td><mark style="color:orange;">Apple V2</mark></td><td>POST “Webhooks/Apple/V2/{MediaGroup}/{ClientCode}/{PaperCode}”</td></tr></tbody></table>

***

## 2. Newstart InApp Subscription Endpoint

For Newstarts InApp subscriptions, the new URL endpoints must be used along with the new bearer authentication.&#x20;

## Newstart InApp Subscription Endpoint

<mark style="color:green;">`POST`</mark> `{SubscribeApiUrl}/Purchases/InApp`

This endpoint is used to create a Newstart InApp subscription.

**Note:** *The parameters marked with an asterisk* (<mark style="color:red;">\*</mark>) *are mandatory and must be included in the input model.*

#### Headers

| Name                                               | Type   | Description                                   |
| -------------------------------------------------- | ------ | --------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark>    | String | JSON Web Token used for security purposes     |
| X-SourceSystem<mark style="color:red;">\*</mark>   | String | To identify the consumer or the Source System |
| X-ClientCode<mark style="color:red;">\*</mark>     | String | Client Code of the Tenant                     |
| X-PaperCode<mark style="color:red;">\*</mark>      | String | Paper Code of the Tenant                      |
| X-MediaGroupCode<mark style="color:red;">\*</mark> | String | Media Group Code of the Tenant                |

#### Request Body

| Name                                                     | Type     | Description                                                                                                          |
| -------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| CustomerRegistrationId<mark style="color:red;">\*</mark> | String   | Unique identifier of a customer in Naviga System                                                                     |
| OfferId<mark style="color:red;">\*</mark>                | Integer  | Unique identifier of the offer in Naviga System                                                                      |
| OfferGroupId<mark style="color:red;">\*</mark>           | Integer  | Unique identifier of the offer group in Naviga System                                                                |
| OfferCode                                                | String   | Unique code of the offer in Naviga System                                                                            |
| AppleInfo.Receipt<mark style="color:red;">\*</mark>      | String   | <p>Receipt information for the Apple InApp market.</p><p>It is required only if it is an Apple InApp Newstart.</p>   |
| GoogleInfo.Receipt<mark style="color:red;">\*</mark>     | String   | <p>Receipt information for the Google InApp market.</p><p>It is required only if it is an Google InApp Newstart.</p> |
| Subscriber.Email                                         | String   | Email of the subscriber                                                                                              |
| Subscriber.Country                                       | String   | Country of the subscriber                                                                                            |
| Subscriber.CompanyType                                   | String   | Company type of the subscriber                                                                                       |
| Subscriber.CompanyName                                   | String   | Company name of the subscriber                                                                                       |
| Subscriber.Title                                         | String   | Title of the subscriber                                                                                              |
| Subscriber.LastName                                      | String   | Last name of the subscriber                                                                                          |
| Subscriber.FirstName                                     | String   | First name of the subscriber                                                                                         |
| PaymentTypeId<mark style="color:red;">\*</mark>          | Integer  | Unique identifier of the payment type in Naviga System                                                               |
| StartDate<mark style="color:red;">\*</mark>              | dateTime | Start date of the subscription                                                                                       |
| EmailAddress<mark style="color:red;">\*</mark>           | String   | Email address of the subscriber                                                                                      |
| Subscriber.Phone                                         | String   | Phone of the subscriber                                                                                              |
| Product.MerchantProductId                                | String   | Unique identifier of the merchant product                                                                            |
| Product.ProductQuantity                                  | Integer  | Quantity of the product required                                                                                     |
| Product.ExternalProductId                                | String   | Unique identifier of the external product                                                                            |
| Products                                                 | Array    |                                                                                                                      |
| RegistrationId                                           | Integer  | Unique identifier of a registration in Naviga System                                                                 |
| Product.ProductId                                        | Integer  | Unique identifier of the product                                                                                     |

{% tabs %}
{% tab title="200: OK Success Response" %}

```json
{
  "Code": 200,
  "Errors": [],
  "Result": {
    "EventId": 0,
    "AccountNumber": "string",
    "PaymentAuthorizationCode": "string",
    "TwoSteps": false
  },
  "SessionId": "string",
  "RequestId": "string"
}
```

{% endtab %}

{% tab title="400: Bad Request Authorization is missing" %}

```json
{
    "error": "Authorization is missing."
}
```

{% endtab %}

{% tab title="400: Bad Request X-SourceSystem is missing" %}

```json
{
    "error": "X-SourceSystem is missing."
}
```

{% endtab %}

{% tab title="401: Unauthorized Invalid Source System" %}

```json
{
    "error": "Invalid Source System."
}
```

{% endtab %}

{% tab title="500: Internal Server Error Something went wrong. Please try again later." %}

```json
{
    "error": "Something went wrong. Please try again later."
}
```

{% endtab %}

{% tab title="400: Bad Request Invalid Input" %}

```json
{
   "Code":400,
   "Errors":[
      {
         "Message":"Invalid Input.",
         "Code":"Subscriptions01",
         "Type":{
            "Id":0,
            "Code":"Validation"
         },
         "ErrorSource":null
      }
   ],
   "Result":null,
   "SessionId":"string",
   "RequestId":"string"
}
```

{% endtab %}

{% tab title="400: Bad Request Failed To Add External Subscription" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "Failed To Add External Subscription",
      "Code": "Subscriptions422",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endtab %}

{% tab title="400: Bad Request Existing External Subscription" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "Existing External Subscription",
      "Code": "Subscriptions421",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endtab %}

{% tab title="400: Bad Request Invalid Receipt Info" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "Invalid Receipt Info",
      "Code": "Subscriptions420",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endtab %}

{% tab title="400: Bad Request Failed To Verify Receipt Info" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "Failed To Verify Receipt Info",
      "Code": "Subscriptions417",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endtab %}

{% tab title="400: Bad Request Invalid Apple Token Secret" %}
{% code overflow="wrap" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "Invalid Apple Token Secret. Token secret cannot be null or empty",
      "Code": "Subscriptions435",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endcode %}
{% endtab %}

{% tab title="400: Bad Request offer does not exist" %}

```json
{
  "Code": 400,
  "Errors": [
    {
      "Message": "The offer does not exist or it is not available.",
      "Code": "Subscriptions29",
      "Type": {
        "Id": 0,
        "Code": "Validation"
      },
      "ErrorSource": null
    }
  ],
  "Result": null,
  "SessionId": null,
  "RequestId": null
}
```

{% endtab %}

{% tab title="400: Bad Request start date cannot be null" %}

```json
{
   "Code":400,
   "Errors":[
      {
         "Message":"The start date cannot be null",
         "Code":"Subscriptions451",
         "Type":{
            "Id":0,
            "Code":"Validation"
         },
         "ErrorSource":null
      }
   ],
   "Result":null,
   "SessionId":"string",
   "RequestId":"string"
}
```

{% endtab %}

{% tab title="401: Unauthorized Invalid authorization" %}

```json
{
    "error": "Invalid authorization."
}
```

{% endtab %}
{% endtabs %}

***

## 3. Naviga Implementation Steps

{% hint style="success" %}
*For detailed implementation steps of the Newstart InApp migration from the old ExternalPayments system to the new Webhooks system, please refer to the internal*  [*Confluence*](https://naviga-hub.atlassian.net/wiki/spaces/SUB/pages/9408020481/Newstart+InApp+Migration+for+migrate+from+ExternalPayments) *documentation.*
{% endhint %}

### 3.1 Migration of data from External Payments DB to Subsvc DB

Naviga Implementation team should migrate the data for existing InApp subscriptions from the old External Payments database to the new tables in the Subsvc database.

### 3.2. MG2 Control DB

#### 3.2.1. Market-based API Settings

<table><thead><tr><th width="129">Market</th><th width="313">Setting name</th><th>Details</th></tr></thead><tbody><tr><td><mark style="color:blue;">Google</mark></td><td>Google.VerifyReceiptCredential</td><td>The client provides the credentials in <mark style="color:red;">JSON</mark> format. The value differs depending on the newspaper client.</td></tr><tr><td><mark style="color:purple;">Apple V1</mark></td><td>Apple.VerifyUrl</td><td>The universal URL endpoint for verification of receipts. The value remains the same for all clients.</td></tr><tr><td> <mark style="color:purple;">Apple V1</mark></td><td>Apple.VerifySecret</td><td>The client provides the credentials in <mark style="color:red;">String</mark> format of 32 characters. The value differs depending on the newspaper client.</td></tr><tr><td><mark style="color:orange;">Apple V2</mark></td><td>Apple.AppleTokenSecretWebhooksApi</td><td>The purchase request to Subscribe will have inputs from Apple received by the client in their app. These inputs are required to be converted into JWT using a key. The key must be shared to Naviga to be able to decrypt the JWT information.</td></tr><tr><td></td><td></td><td></td></tr></tbody></table>

**Note**: The Secret Key is only used for initial Purchase request. It is not required for managing notifications from Apple.

Sample Purchase Request for Apple V2 with signed object:

```
InApp Purchase requestBody for Apple:
{
"OfferId": 2730,
    "OfferGroupId": 42,
    "OfferCode": null,
    "AppleInfo": {
        "Receipt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7IlNpZ25lZFRyYW5zYWN0aW9uSW5mbyI6ImV5SjBlWEFpT2lKS1YxUWlMQ0poYkdjaU9pSklVekkxTmlKOS5leUp6YVdkdVpXUkVZWFJsSWpveE56VXlNakU1TlRJNUxqSXdPQ3dpWTNWeWNtVnVZM2tpT2lKVlUwUWlMQ0ppZFc1a2JHVkpaR1Z1ZEdsbWFXVnlJam9pWTI5dExuTjFZbk5qY21saVpYSXVibUYyYVdkaElpd2lhVzVCY0hCUGQyNWxjbk5vYVhCVWVYQmxJam9pVUZWU1EwaEJVMFZFSWl3aVpYaHdhWEpsYzBSaGRHVWlPakUzTlRJeU1UazRNalVzSW5CMWNtTm9ZWE5sUkdGMFpTSTZNVGMxTWpJeE9UVXlOU3dpY0hKdlpIVmpkRWxrSWpvaVkyOXRMbTF2Ym5Sb2JIa3VZV05qWlhOeklpd2ljWFZoYm5ScGRIa2lPakVzSW05eWFXZHBibUZzVkhKaGJuTmhZM1JwYjI1SlpDSTZNakF3TURBd01EazFPVFl5T0RBMk9Dd2liM0pwWjJsdVlXeFFkWEpqYUdGelpVUmhkR1VpT2pFM05USXlNVGsxTWpVc0luTjFZbk5qY21sd2RHbHZia2R5YjNWd1NXUmxiblJwWm1sbGNpSTZJakl4TlRFNE1EUTVJaXdpY0hKcFkyVWlPakV1T1Rrc0ltbHpWWEJuY21Ga1pXUWlPbVpoYkhObExDSjNaV0pQY21SbGNreHBibVZKZEdWdFNXUWlPaUl5TURBd01EQXdNVEExTURnd05qVTBJaXdpZEhKaGJuTmhZM1JwYjI1SlpDSTZNakF3TURBd01EazFPVFl5T0RBMk9Dd2laVzUyYVhKdmJtMWxiblFpT2lKVFlXNWtZbTk0SWl3aWRIbHdaU0k2SWtGMWRHOHRVbVZ1WlhkaFlteGxJRk4xWW5OamNtbHdkR2x2YmlKOS5mQktxU1lFWW9reHVGTFRSRmNfeW4tcHlMVk5WWV9NRGV4VlZneUNNbm1BIiwiU2lnbmVkUmVuZXdhbEluZm8iOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpJVXpJMU5pSjkuZXlKaGRYUnZVbVZ1WlhkUWNtOWtkV04wU1dRaU9pSmpiMjB1Ylc5dWRHaHNlUzVoWTJObGMzTWlMQ0p5Wlc1bGQyRnNVSEpwWTJVaU9qRXVPVGtzSW5KbFkyVnVkRk4xWW5OamNtbHdkR2x2YmxOMFlYSjBSR0YwWlNJNk1UYzFNakl4T1RVeU5Td2ljSEp2WkhWamRFbGtJam9pWTI5dExtMXZiblJvYkhrdVlXTmpaWE56SWl3aVpXNTJhWEp2Ym0xbGJuUWlPaUpUWVc1a1ltOTRJaXdpWVhWMGIxSmxibVYzVTNSaGRIVnpJanAwY25WbExDSnZjbWxuYVc1aGJGUnlZVzV6WVdOMGFXOXVTV1FpT2pJd01EQXdNREE1TlRrMk1qZ3dOamdzSW1OMWNuSmxibU41SWpvaVZWTkVJaXdpY21WdVpYZGhiRVJoZEdVaU9qRTNOVEl5TVRrNE1qVjkuT3NXM3hPY0N3YkFyM1VXQVJRamVkaTJNUmt2aGM4NWJfS0hGMGp2dWZOdyJ9LCJleHAiOjE3NzcyMzAzMzB9.kapdRElideTPwycic4rtEVO8r5Kc40JfORZOxuTVjiU"
    },
    "GoogleInfo": null,
    "Subscriber": null,
    "EmailAddress": "pragatipandey@tester.com",
    "StartDate": "2011-07-25T00:00:00",
    "PaymentTypeId": 31,
    "CustomerRegistrationId": "auth0|66bf2d31c464ebb623db0573",
    "RegistrationId": 0,
    "Products": null,
    "PianoInfo": null

```

#### 3.2.2. API Settings

<table><thead><tr><th width="318">Setting </th><th>Details</th></tr></thead><tbody><tr><td>Flow.Purchase.InApp.Redirect</td><td><p>The value should be set for a specific client. The default value has been set to 1 (true).</p><ul><li>If the value has been set to 0 (false), the Purchase API will process the Newstart subscription.</li><li>If the value has been set to 1 (true), the request will be redirected to the Subscriptions API to process the Newstart subscription.</li></ul></td></tr><tr><td>InAppNotification.NotificationRetryLimitWebhooksApi</td><td><p>Whenever the system finds that the processed status of an InApp notification does not indicate "OK," it will attempt to process the notification again.</p><p>This setting determines the maximum number of times that the notification can be reprocessed.</p></td></tr></tbody></table>

### 3.3. Event Types Configuration <a href="#id-6.-set-configuration-for-eventtypes-table" id="id-6.-set-configuration-for-eventtypes-table"></a>

Set the following information in the \[*EventTypes*] and \[*NewspaperEventProcessorAssignments*] tables based on the specific market to be configured:

* Set the configuration for the event type, GOOGLEVERIFYRECEIPT (1195), to have *active* = 1 (true) and *triggers\_post* = 1 (true).
  * It should also be associated with NewspaperEventProcessorAssignments, with the 'EventProcessorId' value set to *41 (Google)*.
* Set the configuration for the event type, APPLEVERIFYRECEIPT (1194), to have *active* = 1 (true) and *triggers\_post* = 1 (true).
  * It should also be associated with NewspaperEventProcessorAssignments, with the 'EventProcessorId' value set to *43 (Apple)*.

### 3.4. Bearer Authentication <a href="#id-8.-generate-new-bearer-authentication-for-the-client" id="id-8.-generate-new-bearer-authentication-for-the-client"></a>

A new bearer authentication should be generated for the client. The bearer token should have PurchaseAPI resource added with the 'write' access.

### 3.5. Set up Hangfire with OnPremise API

Hangfire is integrated into the OnPremise API, which manages background jobs and scheduled tasks.

#### Prerequisites

1. The below-listed MG2 Control API settings should be in place.<br>

   <table><thead><tr><th width="318">Setting</th><th>Details</th></tr></thead><tbody><tr><td>OnPremiseStorageConnectionString</td><td>This setting is used to define the "DB Connection string" in order to designate a specific database as a repository for managing queue(s).<br><br>Example value:<br><em><mark style="color:blue;">Data Source=IP;Initial Catalog=MG2_Control;User Id=xxxxx;Password=xxxxx;</mark></em></td></tr><tr><td>SubConConnectionString</td><td><p>This is a global setting that specifies the connection string for connecting to the Subsvc DB.<br><br>Example value:</p><p><em><mark style="color:blue;">Data Source=IP;Initial Catalog=subsvc_SomeClient_test;Persist Security Info=True;User ID=xxxxx;pwd=xxxxx;</mark></em></p></td></tr><tr><td>MG2API</td><td><p>This setting is used as the base URL for calling the Subscribe APIs.<br><br>Example value:<br><em><mark style="color:blue;">http://aws-test.subscriberconcierge.com/</mark></em></p><p>   </p></td></tr></tbody></table>

2. Before configuring Hangfire, the following stored procedures must exist:
   * *<mark style="color:blue;">dbo.OnPremise\_InAppRetryNotification\_GetData</mark>*
   * *<mark style="color:blue;">dbo.OnPremise\_StopExternalSubscriptions\_GetData</mark>*

#### Hangfire Setup:

#### 3.5.1. Retry Notification endpoint

Hangfire will generate a task cycle that will run every time as specified in the input model's instructions.

> <mark style="color:green;">**POST**</mark><mark style="color:green;">:</mark> <https://aws-test.subscriberconcierge.com/Notifications/InApp/Retry/Configure>

**Sample Input Model:**

{% code fullWidth="false" %}

```json
{
  "RunEveryDayAtHour": 19, -> Hour Time UTC
  "RunEveryDayAtMinute": 30, ->  Minute Time UTC
  "TaskKey": "testKey1234" -> Unique Key
}
```

{% endcode %}

The task will retry failed market notifications by calling the Webhooks API Retry endpoint (<mark style="color:green;">**POST**</mark>: <mark style="color:blue;"><https://aws-test.subscriberconcierge.com/Notifications/{id}/Retry></mark>) with the same request Headers used in the request.

#### 3.5.2. External Subscription endpoint

Hangfire will generate a task cycle that will run every time as specified in the input model's instructions.

> <mark style="color:green;">**POST**</mark><mark style="color:green;">:</mark> <https://aws-test.subscriberconcierge.com/Notifications/InApp/Retry/Configure>

**Sample Input Model:**

{% code fullWidth="false" %}

```json
{
  "RunEveryDayAtHour": 19, -> Hour Time UTC
  "RunEveryDayAtMinute": 30, ->  Minute Time UTC
  "TaskKey": "testKey1234" -> Unique Key
}
```

{% endcode %}

This task searches the Subscribe database for external subscriptions with an active status (L) and a stop date prior to the current date (< today). It then calls the SubscriptionsAPI endpoint  (<mark style="color:green;">**POST**</mark>: <mark style="color:blue;"><https://aws-test.subscriberconcierge.com/ExternalSubscription/{0}/Stop></mark>) with the same request Headers used in the request to stop each external subscription.

External markets such as GooglePlay or Apple may notify of an expiry date in the future; in this case, wait for this Hangfire task to be processed, which will stop the subscription at the appropriate time.

#### 3.5.3. Remove Created Task

To remove a Notification or External Subscription task that has been created, call the Webhooks API endpoint mentioned below.

> <mark style="color:red;">**DELETE**</mark><mark style="color:red;">:</mark> <https://aws-test.subscriberconcierge.com/Notifications/InApp/Retry/Remove/{taskKey}>

**Sample Input Model:**

{% code overflow="wrap" fullWidth="false" %}

```json
taskKey input parameter is nullable. If taskKey is null then taskKey = MediaGroupCode_ClientCode_PaperCode
```

{% endcode %}

### 3.6. OnPremise API Website Configuration <a href="#id-13.-important-step-onpremiseapi-web-site-configuration" id="id-13.-important-step-onpremiseapi-web-site-configuration"></a>

Hangfire is an open-source framework that helps to create and process background jobs, and the Hangfire server operates within the OnPremise API because this is an ASP.NET Framework web site hosted on IIS.

The Hangfire server is subject to the same events as a website (such as Application\_Start, Application\_End, etc.), causing it to simply shut down if the website becomes inactive.

For OnPremise API website configuration, please refer to the [Confluence](https://naviga-hub.atlassian.net/wiki/spaces/SUB/pages/9408020481/Newstart+InApp+Migration+for+migrate+from+ExternalPayments#13.-Important-step%3A-OnPremiseApi-Web-site-Configuration) documentation.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.navigaglobal.com/naviga-subscribe/additional-resources/subscribe-apis/inapp-api-reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
