Token Activation in the Mobile Application

The application should support a deeplink configured in MDES. The deeplink should contain a serialNumber parameter in the query string.

Based on this value, the application should find the matching PassKit item using the serialNumber property. Then, it should call the TMP API endpoint:

POST /issuer/push-provisioning/tokens/activations

The request should contain the token identifier. If the response field issuerMobileAppAuthResponse is APPROVED, the card has been successfully activated. For DECLINED or FAILED, the activation was not completed successfully.

Process Overview

Swift Example

import Foundation
import PassKit

enum ActivationStatus: String, Decodable {
    case approved = "APPROVED"
    case declined = "DECLINED"
    case failed = "FAILED"
}

struct TokenActivationRequest: Encodable {
    let tokenUniqueReference: String
}

struct TokenActivationResponse: Decodable {
    let tokenUniqueReference: String?
    let cardLast4Digits: String?
    let issuerMobileAppAuthResponse: ActivationStatus
    let comment: String?
}

func handleActivationDeeplink(_ url: URL) async throws {
    guard
        let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
        let serialNumber = components.queryItems?.first(where: { $0.name == "serialNumber" })?.value
    else {
        throw URLError(.badURL)
    }

    let passLibrary = PKPassLibrary()

    guard let pass = passLibrary.passes().first(where: {
        $0.serialNumber == serialNumber
    }),
    let tokenUniqueReference = pass.secureElementPass?.deviceAccountIdentifier
    else {
        throw URLError(.cannotFindHost)
    }

    let requestBody = TokenActivationRequest(
        tokenUniqueReference: tokenUniqueReference
    )

    let url = URL(string: "<https://your-tmp-api-base-url/issuer/push-provisioning/tokens/activations>")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONEncoder().encode(requestBody)

    let (data, response) = try await URLSession.shared.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }

    let activationResponse = try JSONDecoder().decode(
        TokenActivationResponse.self,
        from: data
    )

    switch activationResponse.issuerMobileAppAuthResponse {
    case .approved:
        // Card has been successfully activated.
        break

    case .declined, .failed:
        // Card activation failed.
        break
    }
}

Notes


Revision #1
Created 19 May 2026 07:35:30 by Bartłomiej Jończy
Updated 19 May 2026 07:35:58 by Bartłomiej Jończy