Flujo de desarrollo del pase de la Billetera de Google

La API de la Billetera de Google proporciona un conjunto predefinido de tipos de pases optimizados para casos de uso específicos, como tarjetas de regalo, tarjetas de embarque, entradas para eventos y mucho más. También hay un tipo de pase genérico destinado a casos de uso en los que un tipo de pase específico no está disponible.

El objetivo de este artículo es que te familiarices con los pasos básicos necesarios para crear y emitir un pase con la API de la Billetera de Google. Hay varias maneras de realizar algunos de los pasos que se detallan a continuación, pero, en términos generales, todos los tipos de pases se crean siguiendo el mismo flujo de desarrollo básico.

Si quieres obtener una explicación detallada para crear un pase, consulta las guías de apps web, de correo electrónico y SMS o de apps para Android.

Para qué sirve

La clase Pases define un conjunto de propiedades que son comunes en varios pases, de manera similar a una plantilla. Por ejemplo, si estás emitiendo entradas para un evento, la clase Pases definirá campos que son iguales en todas las entradas, como el nombre, la fecha y la hora del evento.

Cada pase que emitas debe hacer referencia a una clase Passes. También debes asignar un ID único a cada clase de pase que crees, que se usará como referencia cuando se creen pases.

Cómo se hace

Una clase Passes se define en formato JSON y se puede crear con la API de REST de la Billetera de Google, el SDK de Android o en la Billetera de Google Business Console.

Mostrar ejemplo de clase de pases

{
  "id": "ISSUER_ID.EVENT_CLASS_ID",
  "issuerName": "[TEST ONLY] Heraldic Event",
  "localizedIssuerName": {
    "defaultValue": {
      "language": "en-US",
      "value": "[TEST ONLY] Heraldic Event"
    }
  },
  "logo": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "LOGO_IMAGE_DESCRIPTION"
      }
    }
  },
  "eventName": {
    "defaultValue": {
      "language": "en-US",
      "value": "Google Live"
    }
  },
  "venue": {
    "name": {
      "defaultValue": {
        "language": "en-US",
        "value": "Shoreline Amphitheater"
      }
    },
    "address": {
      "defaultValue": {
        "language": "en-US",
        "value": "ADDRESS_OF_THE_VENUE"
      }
    }
  },
  "dateTime": {
    "start": "2023-04-12T11:30"
  },
  "reviewStatus": "UNDER_REVIEW",
  "hexBackgroundColor": "#264750",
  "heroImage": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "HERO_IMAGE_DESCRIPTION"
      }
    }
  }
}
    

Para qué sirve

Un objeto Passes define las propiedades de un pase único que se emitirá a un usuario específico. Por ejemplo, el objeto Passes de una entrada para un evento definiría campos que son exclusivos de un boleto específico, como el número de asiento o un código QR de ese boleto.

Cuando se crea un objeto Passes, la API de la Billetera de Google almacena un pase nuevo y lo asocia con tu cuenta de la entidad emisora. Este pase almacenado es una combinación de las propiedades únicas del objeto Pases y las propiedades de la plantilla de la clase Pases asociada.

También debes asignar a cada objeto Passes un ID único, que se usa para hacer referencia a él cuando se emite un pase.

Cómo se hace

Un objeto Passes se define en formato JSON y se puede crear con la API de REST de la Billetera de Google o el SDK de Android.

Mostrar ejemplo de objeto Passes

{
  "id": "ISSUER_ID.OBJECT_ID",
  "classId": "ISSUER_ID.EVENT_CLASS_ID",
  "state": "ACTIVE",
  "seatInfo": {
    "seat": {
      "defaultValue": {
        "language": "en-us",
        "value": "5"
      }
    },
    "row": {
      "defaultValue": {
        "language": "en-us",
        "value": "G"
      }
    },
    "section": {
      "defaultValue": {
        "language": "en-us",
        "value": "40"
      }
    },
    "gate": {
      "defaultValue": {
        "language": "en-us",
        "value": "3A"
      }
    }
  },
  "barcode": {
    "type": "QR_CODE",
    "value": "BARCODE_VALUE",
    "alternateText": ""
  }
}
    

Para qué sirve

Para emitir un pase a un usuario, una clase Passes y un objeto Passes deben estar codificados en un token web JSON (JWT). El formato JWT es un estándar común y abierto para representar reclamaciones entre dos partes. En el caso de emitir pases con la API de la Billetera de Google, los JWT se usan para enviar un reclamo en el que se indica que un usuario tiene derecho a acceder a un pase específico asociado con tu cuenta de entidad emisora.

Cuando se envía un JWT a la API de la Billetera de Google, los datos codificados se usan para identificar un pase específico y emitirlo al usuario. Si ya se emitió el pase, estos datos también permiten que la API de la Billetera de Google identifique que el pase es un duplicado, de manera que no se agregue a la Billetera de Google del usuario más de una vez.

Cómo se hace

Los JWT se definen en formato JSON según la especificación de JWT. Si quieres definir un JWT para emitir un pase con la API de la Billetera de Google, debes proporcionar la información sobre el pase que quieres emitir en la propiedad payload del JWT.

Mostrar JWT de ejemplo

{
  "iss": "issuer@example.com",
  "aud": "google",
  "typ": "savetowallet",
  "iat": 1696877738,
  "origins": [
    "www.example.com"
  ],
  "payload": {
    "eventTicketObjects": [
      {
        "id": "ISSUER_ID.LOYALTY_OBJECT_SUFFIX"
      }
    ]
  }
}
    

Para qué sirve

Todos los JWT que se envíen a la API de la Billetera de Google para emitir un pase deben firmarse con las credenciales que proporcionaste anteriormente en Google Wallet Business Console. La firma usa tus credenciales para encriptar el JWT, de modo que tus pases permanezcan seguros y para permitir que la API de la Billetera de Google autentique que los detalles del pase codificado en él son válidos y están asociados con tu cuenta de la entidad emisora.

Cómo se hace

Las bibliotecas cliente de la Billetera de Google y el SDK de Android ofrecen métodos útiles para firmar tus JWT. También hay numerosas bibliotecas de código abierto disponibles que se encargan de la complejidad de las firmas de código para que elijas.

En el caso de quienes usen la API de REST de la Billetera de Google para emitir pases, el JWT se firma con una clave de cuenta de servicio de Google Cloud. Para aquellos que utilizan el SDK de Android de la Billetera de Google, el SDK administra automáticamente la firma del JWT con la huella digital SHA-1 de tu certificado de firma de la aplicación.

Para proteger tus credenciales, los JWT deben firmarse solamente en tu servidor o con el SDK de Android de la Billetera de Google en tu aplicación.

Mostrar ejemplo de firma de código

Java

  // Create the JWT as a HashMap object
  HashMap claims = new HashMap();
  claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
  claims.put("aud", "google");
  claims.put("origins", Arrays.asList("www.example.com"));
  claims.put("typ", "savetowallet");

  // Create the Google Wallet payload and add to the JWT
  HashMap payload = new HashMap();
  payload.put("eventTicketObjects", Arrays.asList(newObject));
  claims.put("payload", payload);

  // Google Cloud service account credentials are used to sign the JWT
  Algorithm algorithm =
      Algorithm.RSA256(
          null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
  String token = JWT.create().withPayload(claims).sign(algorithm);
        

Node.JS

  // Create the JWT claims
  let claims = {
    iss: this.credentials.client_email,
    aud: 'google',
    origins: ['www.example.com'],
    typ: 'savetowallet',
    payload: {
      eventTicketObjects: [newObject]
    },
  };

  // The service account credentials are used to sign the JWT
  let token = jwt.sign(claims, this.credentials.private_key, { algorithm: 'RS256' });
        

Python

  # Create the JWT claims
  claims = {
      'iss': self.credentials.service_account_email,
      'aud': 'google',
      'origins': ['www.example.com'],
      'typ': 'savetowallet',
      'payload': {
          # The listed classes and objects will be created
          'eventTicketObjects': [new_object]
      }
  }

  # The service account credentials are used to sign the JWT
  signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
  token = jwt.encode(signer, claims).decode('utf-8')
        

Para qué sirve

Una vez que hayas creado un JWT firmado, podrás emitir tu pase a un usuario de la Billetera de Google. Para ello, se debe presentar al usuario el campo “Agregar a la Billetera de Google” botón o vínculo. Cuando un usuario hace clic en el botón o hipervínculo, el JWT firmado se envía a la API de la Billetera de Google, que luego lo desencripta con tus credenciales guardadas. Una vez que se autentique la firma de JWT, se emitirá el pase al usuario para que lo guarde en su Billetera de Google.

Cómo se hace

Para crear una cuenta “Agregar a la Billetera de Google”, haz lo siguiente: botón para una app para Android, usa el SDK de Android de la Billetera de Google, que proporciona métodos para generar el botón. Para todas las demás plataformas, incluidas la Web, el correo electrónico y los mensajes de texto, crea un hipervínculo con el formato https://pay.google.com/gp/v/save/<signed_jwt>. Siempre que sea posible, es mejor enviar este vínculo al usuario como "Agregar a la Billetera de Google". .

Para obtener más información sobre cómo usar botón, consulta los lineamientos de desarrollo de la marca de la API de la Billetera de Google

Mostrar código de ejemplo

  https://pay.google.com/gp/v/save/<signed_jwt>
        

SDK de Android

  private lateinit var walletClient: PayClient
  private val addToGoogleWalletRequestCode = 1000
  private lateinit var addToGoogleWalletButton: View

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    walletClient = Pay.getClient(this)
    addToGoogleWalletButton.setOnClickListener {
      walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)
    }
  }
        

Una vez que el usuario haya guardado el pase emitido, este aparecerá en la app de la Billetera de Google junto con cualquier otro pase que haya guardado.

Cómo crear objetos Passes y clases Passes en el JWT

Las Clases de Pases y los Objetos de Pase se pueden crear con anticipación mediante la API de REST de la Billetera de Google o el SDK de Android. Una vez que se crean, se usan para emitir pases con una referencia a su ID.

Como alternativa, también puedes crear clases Pases y objetos Pases "justo a tiempo" incorporando el JSON directamente en el JWT que se usa para emitir el pase a un usuario. En este método, la API de la Billetera de Google crea las clases Passes y los objetos Passes cuando se envía el JWT firmado con la función Agregar a la Billetera de Google botón o vínculo.

Por ejemplo, a continuación se muestra un JWT con una clase Passes nueva y un objeto Passes definido con las propiedades payload.eventTicketClasses y payload.eventTicketObjects. Ten en cuenta que estas propiedades son arrays, por lo que pueden aceptar una o más clases Passes o objetos Passes. También puedes especificar solo un nuevo objeto Passes en el JWT que haga referencia a una clase Passes existente por su ID.

Mostrar JWT de ejemplo

  {
    "iss": "issuer@example.com",
    "aud": "google",
    "typ": "savetowallet",
    "iat": 1696877738,
    "origins": [
      "www.example.com"
    ],
    "payload": {
      "eventTicketClasses": [{
        "id": "ISSUER_ID.EVENT_CLASS_ID",
        "issuerName": "[TEST ONLY] Heraldic Event",
        "localizedIssuerName": {
          "defaultValue": {
            "language": "en-US",
            "value": "[TEST ONLY] Heraldic Event"
          }
        },
        "logo": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "LOGO_IMAGE_DESCRIPTION"
            }
          }
        },
        "eventName": {
          "defaultValue": {
            "language": "en-US",
            "value": "Google Live"
          }
        },
        "venue": {
          "name": {
            "defaultValue": {
              "language": "en-US",
              "value": "Shoreline Amphitheater"
            }
          },
          "address": {
            "defaultValue": {
              "language": "en-US",
              "value": "ADDRESS_OF_THE_VENUE"
            }
          }
        },
        "dateTime": {
          "start": "2023-04-12T11:30"
        },
        "reviewStatus": "UNDER_REVIEW",
        "hexBackgroundColor": "#264750",
        "heroImage": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "HERO_IMAGE_DESCRIPTION"
            }
          }
        }
      }],
      "eventTicketObjects": [{
        "id": "ISSUER_ID.OBJECT_ID",
        "classId": "ISSUER_ID.EVENT_CLASS_ID",
        "state": "ACTIVE",
        "seatInfo": {
          "seat": {
            "defaultValue": {
              "language": "en-us",
              "value": "5"
            }
          },
          "row": {
            "defaultValue": {
              "language": "en-us",
              "value": "G"
            }
          },
          "section": {
            "defaultValue": {
              "language": "en-us",
              "value": "40"
            }
          },
          "gate": {
            "defaultValue": {
              "language": "en-us",
              "value": "3A"
            }
          }
        },
        "barcode": {
          "type": "QR_CODE",
          "value": "BARCODE_VALUE",
          "alternateText": ""
        }
      }]
    }
  }