iosnestjsapple-walletpkpass

Apple Wallet Pass registration


My NestJS server can't seem to receive the webhook registration from my apple pkpass.

I am able to generate and download the pass correctly, and I have set the (I believe) correct parameters:

{
  ...
  authenticationToken: '1234567891234567812', // This is fake ofc
  webServiceURL: 'https://api.TEST.com/passes', // fake api endpoint
  serialNumber: uuid(),
  ...
}

Then I have built a controller to try and gather the data from the registration request, but I can't seem to receive the webhook. (My controller is correctly initialized and I can test it via Postman no problem)

My controller:

@Controller('passes')
export class PassesController {
    private readonly logger = new Logger(PassesController.name);

    constructor() {}

    @Get()
    async logGet(
        @Headers() headers: any,
        @Body() body: any
    ): Promise<string> {
        this.logger.log("Received a GET call from Apple");
        this.logger.debug(`Headers: ${headers}`);
        this.logger.debug(`Body: ${body}`);
        return 'get';
    }

    @Post()
    async logPost(
        @Headers() headers: any,
        @Body() body: any,
        @Param('deviceLibraryIdentifier') id: any,
        @Param('passTypeIdentifier') pass: any
    ): Promise<string> {
        this.logger.log("Received a POST call from Apple");
        this.logger.debug(`Headers: ${headers}`);
        this.logger.debug(`Body: ${body}`);
        return 'post';
    }

    @Put()
    async logPut(
        @Headers() headers: any,
        @Body() body: any,
        @Param('deviceLibraryIdentifier') id: any,
        @Param('passTypeIdentifier') pass: any
    ): Promise<string> {
        this.logger.log("Received a PUT call from Apple");
        this.logger.debug(`Headers: ${headers}`);
        this.logger.debug(`Body: ${body}`);
        return 'put';
    }
}

Is the path that gets called different from the basic one I provide in webServiceURL or am I doing something wrong somewhere else? I cannot seem to find an interface agreement for the way that the passes are supposed to register.


Solution

  • I managed to find out how Apple posts the request, which can be seen and captured with:

    @Post('/:version/devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier/:serialNumber')
        async logPost(
            @Headers() headers: any,
            @Param('deviceLibraryIdentifier') deviceLibraryIdentifier: string,
            @Param('passTypeIdentifier') passTypeIdentifier: string,
            @Param('serialNumber') serialNumber: string,
            @Query('passesUpdatedSince') passesUpdatedSince: string,
          ): Promise<any> {
            this.logger.log('Received POST from Apple');
            this.logger.debug(`Headers: ${JSON.stringify(headers)}`);
            this.logger.debug(`Params: ${deviceLibraryIdentifier}, ${passTypeIdentifier}, ${serialNumber}`);
            this.logger.debug(`passesUpdatedSince: ${passesUpdatedSince}`);
            const date = new Date();
            return { lastUpdated: date.toISOString() };
          }