Skip to content

Latest commit

 

History

History
147 lines (107 loc) · 5.91 KB

notification.md

File metadata and controls

147 lines (107 loc) · 5.91 KB

Receiving Market Notification

Appsco Market will notify you on the notification URL registered in the Market Item when an order is processed and when subscription status changes.

Notification kinds

These are the notification kinds Market can send

  • order_processed - Sent when an order is successfully processed. On this notification kind you would usually want to prepare your application's environment/state to accomodate this new order - for example initialize new user account or create new application instance.
  • subscription_canceled - Sent when subscription for existing application is canceled
  • subscription_charged_successfully - Sent when subscription has been charged for one billing period
  • subscription_charged_unsuccessfully - Sent when subscription renewal was not being possible to be charged
  • subscription_expired - Sent when subscription expires
  • subscription_trial_ended - Sent when subscription trial period ends, only if subscription has the trial period
  • subscription_went_active - This will only be sent after the subscription’s first authorized transaction, or when transitioning from a past due status. Subscriptions with trial periods will never trigger this notification. Subscriptions moving out of pending (future billing date has now been reached) will always trigger this, even if the transaction is not authorized.
  • subscription_went_past_due - Sent when subscription was not being renewed successfully after the due period

They are defined in the Appsco\Market\Api\Model\Notification::KIND_* constants

Appsco Market Notifications are JWT based. It's issuer is appsco-market - the Client ID of the Appsco Market registered on Appsco Accounts. Notifications are signed with RS256 algorithm and to validate it you should obtain Market certificate using the Appsco Accounts certificateGet API method.

Notification claims

Appsco Market Notification defines following custom claims:

  • kind - The notification kind
  • order_id - The ID of the order notification is about - defined by you if you initiated the order by custom order request, otherwise generated by Appsco Market
  • app_id - The ID of the Appsco Market application the notification is about. You should store this app id for new instances in order to be able to reconfigure them
  • package_id - The ID of the Appsco Market Package the application is purchased by
  • owner_id - Appsco Accounts ID of the application owner
  • challenge - Challenge you have to reply to in order to validate your callback URL

Validation

In order to properly validate Market Notification, couple of things should be done:

  • decode JWT token
  • check if Issuer claim matches Appsco Market's Client ID - "appsco-market"
  • check the Issued At claim if token has expired
  • check the JWT signature with Market certificate
  • check if Jwt ID has already been processed

Appsco Market API Bundle appsco_market_api.notification.validator service does all these validations expect the last one - Jwt ID validation. For details check the Jwt ID validation document.

Response to Market Notification

To all Market notifications you have to response with HTTP status code 200 and empty response, except for the challenge notification when you have to respond with challenge response.

Receiving Market Notification with Market API Bundle

Use MarketClient method

    /**
     * @param string $jwtToken
     * @return \BWC\Component\Jwe\Jose
     */
    public function receiveNotification($jwtToken)

to get the Notification data model object from the passed JTW token.

Use notification validator service method

    /**
     * @param Notification $notification
     * @throws InvalidNotificationException
     * @return void
     */
    public function validate(Notification $notification);

to validate the received notification

  • issuer validity
  • expiry
  • signature

Example

use Symfony\Component\HttpFoundation\Request;

class DefaultController extends \Symfony\Bundle\FrameworkBundle\Controller\Controller
{
    public function callbackAction(Request $request)
    {
        $jwtToken = $request->request->get('jwt');
        $notification = $this->get('appsco_market_api.client')->receiveNotification($jwtToken);
        $this->get('appsco_market_api.notification.validator')->validate($notification);
        $this->jtiValidation($notification); // check if jti is repeated
        $this->processNotification($notification); // process the notification

        return new Response('');
    }
}

Challenge Reply

When you register you Market Item callback URL it has to be validated by replying to a challenge token.

use Symfony\Component\HttpFoundation\Request;

class DefaultController extends \Symfony\Bundle\FrameworkBundle\Controller\Controller
{
    public function callbackAction(Request $request)
    {
        $jwtToken = $request->request->get('jwt');
        $notification = $this->get('appsco_market_api.client')->receiveNotification($jwtToken);
        $this->get('appsco_market_api.notification.validator')->validate($notification);
        $this->jtiValidation($notification); // check if jti is repeated

        if ($notification->getChallenge()) {
            // challenge notification - have to respond with challenge response
            return new Response($this->get('appsco_market_api.client')->notificationChallengeReply($notification));
        } else {
            // notification about an order/subscription
            $this->processNotification($notification); // process the notification

            return new Response('');
        }
    }
}