Skip to content

Methods for Google Pay

Daniel Marek edited this page Mar 19, 2024 · 9 revisions

A Brief overview of methods for Google Pay (googlepay@shop)

Method Description
googlepay/echo Obtaining parameters for initialisation of Google Pay.
googlepay/init Initiation of Google Pay payment for googlepay@shop.
googlepay/process Start of the processing of the Google Pay payment.

The diagram below indicates the process of Google Pay payments:

The customer pays for his order on the e-shop. The merchant offers the customer the option to pay with Google Pay, while obtaining the parameters for initialization by calling the operation googlepay/echo (0).

When the customer selects the Google Pay payment, the e-shop initiates a payment on the payment gateway using the googlepay/init operation. In response, the payment identification payId (1) is received.

Unlike the standard card payment at the gateway, the customer stays on the merchant's e-shop with the Google Pay payment, the payment gateway decrypts the necessary payment data (card number and expiration) from the payload sent within the googlepay/init operation.

The payment gateway performs so-called device fingerprint (2) for some payments. This sends the data from the customer's browser to the card issuer, who will then use this data for subsequent payment authentication. The merchant starts further processing by calling the operation googlepay/process (3). The merchant is required to make the device fingerprint on the e-shop side within a 1px iframe.

For some payments, an authentication is required from customer payment confirmation (5). Similarly as with the device fingerprint, the merchant is required to confirm the payment on the e-shop side, opening the iframe or redirecting to top.location based on the parameters received from the payment gateway.

The merchant continuously detects the status of the payment by calling the operation payment/status (4). In case the payment confirmation is required, after completing the authentication and payment authorization the customer is redirected via returnMethod to e-shop’s returnUrl. After completing the authentication and completing the payment authorization, the merchant displays the payment result to the customer.

The parameters in bold are mandatory for calls.


googlepay/echo method  

POST https://api.platebnibrana.csob.cz/api/v1.9/googlepay/echo

This operation enables obtaining of the parameters to initialise Google Pay payment. The merchant can cache the parameters and use them repeatedly to display the page with the option to pay using Google Pay.

Item Type Description
merchantId String Merchant ID assigned by the payment gateway.
dttm String Date and time the request was sent in the format YYYYMMDDHHMMSS.
signature String Request signature, encoded in BASE64.

Example of request:

{
  "merchantId":"M1MIPS0000",
  "dttm":"20220125131559",
  "signature":"base64-encoded-signature-of-payment-request"
}

Return values  

Item Type Description
dttm String Date and time of the response in the format YYYYMMDDHHMMSS.
resultCode Number The result of the operation, see the list.
resultMessage String Text description of the operation result.
initParams Object Parameters for initialising javascript for Google Pay payment, filled in if resultCode is 0.
signature String Response signature, encoded in BASE64.

Description of the parameters of the initParams object, the merchant fills in the given value in the unchanged form into js (see below) for initialization of Google Pay.

Item Type Description
apiVersion Number The version of the Google Pay API used.
apiVersionMinor NumberMinor version of Google Pay API used.
paymentMethodType String The means of payment type used in Google Pay will be pre-filled based on the payment gateway settings, for example: CARD.
allowedCardNetworks String The list of accepted card brands that Google Pay will accept from the customer will be pre-filled by the payment gateway based on the merchant's settings, for example: [ "VISA", "MASTERCARD" ].
allowedCardAuthMethods String The list of accepted card types stored within Google Pay will be pre-filled based on the payment gateway settings, for example: [ "CRYPTOGRAM_3DS" ].
assuranceDetailsRequired Boolean A flag indicating whether assuranceDetails data is required (they contain information about the authentication performed).
billingAddressRequired Boolean An indication of whether a billing address is required to be returned from Google Pay.
billingAddressParametersFormat String The format of the returned billing address will be pre-filled based on the payment gateway settings, for example: FULL.
tokenizationSpecificationType String Specifies the method of processing payment data, it will be pre-filled based on the payment gateway settings, example: PAYMENT_GATEWAY.
gateway String Google-registered payment gateway/provider identifier used to authorise the payment.
gatewayMerchantId String The merchant identifier assigned by the payment gateway is used to check the consistency of the transmitted payload.
googlepayMerchantId String Merchant ID assigned by Google upon completion of the merchant registration.
merchantName String The name of the merchant that appears in the GooglePay wallet to pay for the payment.
environment String Specifies the environment in which the payment takes place, possible values are TEST, PRODUCTION.
totalPriceStatus String The type of the transmitted price will be preset by the payment gateway to the value FINAL.
countryCode String ISO 3166-1 alpha-2 country code in which the payment is processed.

Example of return values for googlepay/echo operation (googlepay@shop has merchant enabled):

{
  "dttm":"20220125131601",
  "resultCode": 0,
  "resultMessage":"OK",
  "initParams": {
    "apiVersion": 2,
    "apiVersionMinor": 0,
    "paymentMethodType": "CARD",
    "allowedCardNetworks": ["VISA", "MASTERCARD"],
    "allowedCardAuthMethods": ["CRYPTOGRAM_3DS"],
    "assuranceDetailsRequired": true,
    "billingAddressRequired": true,
    "billingAddressParametersFormat": "FULL",
    "tokenizationSpecificationType": "PAYMENT_GATEWAY",
    "gateway":"csob",
    "gatewayMerchantId":"M1MIPS0000",
    "googlepayMerchantId":"01234567890123456789",
    "merchantName":"Example.com",
    "environment":"TEST",
    "totalPriceStatus":"FINAL",
    "countryCode":"CZ"
  },
  "signature":"base64-encoded-response-signature"
 }

Example of return values for googlepay/echo operation (googlepay@shop has merchant disabled):

{
  "dttm":"20220125131601",
  "resultCode": 160,
  "resultMessage":"Payment method disabled",
  "signature":"base64-encoded-response-signature"
 }

When the merchant obtains the parameters passed in initParams in response to the googlepay/echo call, merchant will insert/generate a javascript for initialising Google Pay payments on the e-shop side, javascript can be generated according to the following template, all occurrences need to be replaced variables that are listed in the format ${variable}.

The parameters ${totalPrice} and ${currencyCode} are not part of initParams, they need to be filled in according to the processed payment . Set the amount as a total amount to two decimal places. The currency format must conform to the ISO 4217 alphabetic currency code.

function processPayment(paymentData) {
  // show returned data in developer console for debugging
  console.log(paymentData);
  // @todo pass payment data response to your gateway to process payment
}

Sample template for service javascript for Google Pay for e-shop merchant:

<script>
/**
 * Define the version of the Google Pay API referenced when creating your
 * configuration
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#PaymentDataRequest|apiVersion in PaymentDataRequest}
 */
const baseRequest = {
  apiVersion: ${apiVersion},
  apiVersionMinor: ${apiVersionMinor}
};

/**
 * Card networks supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#CardParameters|CardParameters}
 * @todo confirm card networks supported by your site and gateway
 */
const allowedCardNetworks = ${allowedCardNetworks};

/**
 * Card authentication methods supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#CardParameters|CardParameters}
 * @todo confirm your processor supports Android device tokens for your
 * supported card networks
 */
const allowedCardAuthMethods = ${allowedCardAuthMethods};

/**
 * Identify your gateway and your site's gateway merchant identifier
 *
 * The Google Pay API response will return an encrypted payment method capable
 * of being charged by a supported gateway after payer authorization
 *
 * @todo check with your gateway on the parameters to pass
 * @see {@link https://developers.google.com/pay/api/web/reference/object#Gateway|PaymentMethodTokenizationSpecification}
 */
const tokenizationSpecification = {
  type: '${tokenizationSpecificationType}',
  parameters: {
    'gateway': '${gateway}',
    'gatewayMerchantId': '${gatewayMerchantId}'
  }
};

/**
 * Describe your site's support for the CARD payment method and its required
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#CardParameters|CardParameters}
 */
const baseCardPaymentMethod = {
  type: '${paymentMethodType}',
  parameters: {
    allowedAuthMethods: allowedCardAuthMethods,
    allowedCardNetworks: allowedCardNetworks,
    assuranceDetailsRequired: ${assuranceDetailsRequired},
    billingAddressRequired: ${billingAddressRequired},
    billingAddressParameters: {
      format: '${billingAddressParametersFormat}'
    }
  }
};

/**
 * Describe your site's support for the CARD payment method including optional
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#CardParameters|CardParameters}
 */
const cardPaymentMethod = Object.assign(
  {},
  baseCardPaymentMethod,
  {
    tokenizationSpecification: tokenizationSpecification
  }
);

/**
 * The initialised google.payments.api.PaymentsClient object or null if not yet set
 *
 * @see {@link getGooglePaymentsClient}
 */
let paymentsClient = null;

/**
 * Configure your site's support for payment methods supported by the Google Pay
 * API.
 *
 * Each member of allowedPaymentMethods should contain only the required fields,
 * allowing reuse of this base request when determining a viewer's ability
 * to pay and later requesting a supported payment method
 *
 * @returns {object} Google Pay API version, payment methods supported by the site
 */
function getGoogleIsReadyToPayRequest() {
  return Object.assign(
      {},
      baseRequest,
      {
        allowedPaymentMethods: [baseCardPaymentMethod]
      }
  );
}

/**
 * Configure support for the Google Pay API
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#PaymentDataRequest|PaymentDataRequest}
 * @returns {object} PaymentDataRequest fields
 */
function getGooglePaymentDataRequest() {
  const paymentDataRequest = Object.assign({}, baseRequest);
  paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
  paymentDataRequest.merchantInfo = {
    // @todo a merchant ID is available for a production environment after approval by Google
    // See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist}
    merchantId: '${googlepayMerchantId}',
    merchantName: '${merchantName}'
  };
  return paymentDataRequest;
}

/**
 * Return an active PaymentsClient or initialise
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor}
 * @returns {google.payments.api.PaymentsClient} Google Pay API client
 */
function getGooglePaymentsClient() {
  if ( paymentsClient === null ) {
    paymentsClient = new google.payments.api.PaymentsClient({environment: '${environment}'});
  }
  return paymentsClient;
}

/**
 * Initialize Google PaymentsClient after Google-hosted JavaScript has loaded
 *
 * Display a Google Pay payment button after confirmation of the viewer's
 * ability to pay.
 */
function onGooglePayLoaded() {
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest())
      .then(function(response) {
        if (response.result) {
          addGooglePayButton();
          // @todo prefetch payment data to improve performance after confirming site functionality
          // prefetchGooglePaymentData();
        }
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.log('something went wrong ...');
        console.error(err);
      });
}

/**
 * Add a Google Pay purchase button alongside an existing checkout button
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#ButtonOptions|Button options}
 * @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines}
 */
function addGooglePayButton() {
  const paymentsClient = getGooglePaymentsClient();
  const button =
      paymentsClient.createButton({onClick: onGooglePaymentButtonClicked});
  document.getElementById('container').appendChild(button);
}

/**
 * Provide Google Pay API with a payment amount, currency, and amount status
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/object#TransactionInfo|TransactionInfo}
 * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
 */
function getGoogleTransactionInfo() {
  return {
    currencyCode: '${currencyCode}',
    totalPriceStatus: '${totalPriceStatus}',
    totalPrice: '${totalPrice}',
    countryCode: '${countryCode}'
  };
}

/**
 * g payment data to improve performance
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#prefetchPaymentData|prefetchPaymentData()}
 */
function prefetchGooglePaymentData() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  // transactionInfo must be set but does not affect cache
  paymentDataRequest.transactionInfo = {
    totalPriceStatus: 'NOT_CURRENTLY_KNOWN',
    currencyCode: '${currencyCode}'
  };
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.prefetchPaymentData(paymentDataRequest);
}

/**
 * Show Google Pay payment sheet when Google Pay payment button is clicked
 */
function onGooglePaymentButtonClicked() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();

  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.loadPaymentData(paymentDataRequest)
      .then(function(paymentData) {
        // handle the response
        processPayment(paymentData);
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.error(err);
      });
}

/**
 * Process payment data returned by the Google Pay API
 *
 * @param {object} paymentData response from Google Pay API after user approves payment
 * @see {@link https://developers.google.com/pay/api/web/reference/object#PaymentData|PaymentData object reference}
 */
function processPayment(paymentData) {
  // show returned data in developer console for debugging
  console.log(paymentData);
  // @todo pass payment data response to the payment gateway to process payment
  // encode paymentData.paymentMethodData.tokenizationData.token into base64 and send it as payload parameter within googlepay/init call
}
</script>
<script async
  src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()"></script>

googlepay/init method  

POST https://api.platebnibrana.csob.cz/api/v1.9/googlepay/init

The operation will initialise a Google Pay payment for googlepay@shop, called after obtaining a payload from Google Pay.

Item Type Description
merchantId String Merchant ID assigned by the payment gateway.
orderNo String The reference number of the order used for matching payments, which will also be stated on the bank statement. Numeric value, maximum length is 10 digits.
dttm String Date and time the request was sent in the format YYYYMMDDHHMMSS.
clientIp String IP address of the customer (his browser) accessing the merchant's e-shop, ipv4 or ipv6 format.
totalAmount Number Total price in hundredths of the base currency. The merchant can set a total price that reflects the shipping method based on the address obtained from Google Pay, etc. This value will be sent to the payment gateway authorization as the final total amount to be paid. The price must be equal to or less than the amount authenticated by the cardholder on Google Pay.
currency String Currency code. Allowed values: CZK, EUR, USD, GBP, HUF, PLN, RON, NOK, SEK.
closePayment Boolean Indicates whether the payment should be automatically included in the closing and paid out. Allowed values: true / false. An optional parameter since version 1.9, default value: true.
payload String Data in JSON format (paymentData.paymentMethodData.tokenizationData.token) received by the merchant in the e-shop within Google Pay is encoded by the merchant as BASE64 and then passed in the payload parameter. Payment data contains the Google Pay Payment Token required for the authorisation of the payment at the payment gateway.
returnUrl String URL address to which the client will be redirected back to the e-shop after payment is completed if the payment requires confirmation within the payment authentication. Maximum length 300 characters. When redirecting back to the e-shop, the same parameter set is passed as in the case of returning from the payment gateway when paying by card.
returnMethod String The method of returning to the e-shop URL. Allowed values POST, GET. The recommended method isPOST.
customer Object Additional purchase data related to the customer. See detailed description of the structure customer.
order Object Additional purchase data related to the order. See detailed description of the structure order.
sdkUsed Boolean Indicates whether payment authentication is performed via 3DS SDK (in case of mobile application) or not (payment via browser). Allowed values: true / false. Default value: false.
merchantData String Any auxiliary data that the merchant passes to the gateway, must be BASE64 encoded. The maximum length after encoding is 255 characters. In case of the "Marketplace" business model, the merchant must identify his retailer using the ID company number. This identifier must be enclosed in square brackets [] and can be placed arbitrarily within the merchantData item. If several retailers participate in the purchase, the ID number values are separated by a comma - e.g. [12345678,87654321].
language String Preferred language version to be used in case the payment confirmation is required. Allowed values: cs,en,de,fr,hu,it,ja,pl,pt,ro,ru,sk,es,tr,vi,hr,sl,sv.
ttlSec Number Payment life setting, in seconds, min. allowed value 300, max. allowed value 1800 (5-30 min). Default value: 1800. Payment lifetime is calculated from the moment of googlepay/init call.
signature String Request signature, encoded in BASE64.

Example of request:

{
  "merchantId":"M1MIPS0000",
  "orderNo":"51966",
  "dttm":"20220125131559",
  "clientIp":"192.0.2.2",
  "totalAmount":12300,
  "currency":"CZK",
  "payload":"base64-encoded-payload-from-googlepay",
  "returnUrl":"https://shop.example.com/return",
  "returnMethod":"POST",
  "signature":"base64-encoded-signature-of-payment-request"
}

Example of request:

{
  "merchantId":"M1MIPS0000",
  "orderNo":"51966",
  "dttm":"20220125131559",
  "clientIp":"192.0.2.2",
  "totalAmount":12300,
  "currency":"CZK",
  "closePayment": true,
  "payload":"base64-encoded-payload-from-googlepay",
  "returnUrl":"https://shop.example.com/return",
  "returnMethod":"POST",
  "customer": {
    "name":"Jan Novák",
    "email":"email@example.com",
    "mobilePhone":"+420.800300300"
  },
  "order": {
    "type":"purchase",
    "availability":"now",
    "delivery":"digital",
    "deliveryMode": "0",
    "deliveryEmail": "delivery@example.com"
  },
  "signature":"base64-encoded-signature-of-payment-request"
}

Return values  

Item Type Description
payId String Unique payment ID (assigned by the payment gateway in the googlepay/init operation, contains a 15-character string).
dttm String Date and time of the response in the format YYYYMMDDHHMMSS.
resultCode Number The result of the operation, see list.
resultMessage String Text description of the operation result.
paymentStatus Number Payment status, see payment lifecycle.
statusDetail String Detailed status of payment (detailed status), contains, for example, the reason for the payment refusal, see description.
actions Object Structure for transmitting the necessary data for performing device fingerprint. See structure actions.
signature String Response signature, encoded in BASE64.

Example of return values for googlepay/init operation -- payment successfully initialised

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131601",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 1,
  "signature":"base64-encoded-response-signature"
 }

Example of return values for googlepay/init operation -- payment successfully initialised, including parameters for device fingerprint:

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131601",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 1,
  "actions": {
    "fingerprint": {
      "browserInit": {
        "url":"https://example.com/3ds-method-endpoint"
      }
    }
  },
  "signature":"base64-encoded-response-signature"
 }

Example of return values for googlepay/init operation -- payment successfully initialised, including parameters for initialising the 3DS SDK for payment authentication:

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131601",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 1,
  "actions": {
    "fingerprint": {
      "sdkInit": {
        "directoryServerID":"A000000003",
        "schemeId":"Visa",
        "messageVersion":"2.2.0"
      }
    }
  },
  "signature":"base64-encoded-response-signature"
 }

In the event of an invalid request, the payment gateway returns a response containing a description of the error. A detailed description is provided on the page API Integration.


googlepay/process method  

POST https://api.platebnibrana.csob.cz/api/v1.9/googlepay/process

The operation will start the processing of the Google Pay payment.

Item Type Description
merchantId String Merchant ID assigned by the payment gateway.
payId String payID obtained when creating a Google Pay payment using the googlepay/init operation.
dttm String Date and time the request was sent in the format YYYYMMDDHHMMSS.
fingerprint Object Additional data for payment authentication. See structure fingerprint.
signature String Request signature, encoded in BASE64.

Example of request: (googlepay@shop, payment performed from the customer's browser)

The merchant passes the customer's browser parameters in the request.

{
  "merchantId":"M1MIPS0000",
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131615",
  "fingerprint": {
    "browser": {
      "userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36",
      "acceptHeader":"text/html,application/xhtml+xml,application/xml;",
      "language":"en",
      "javascriptEnabled":false
    }
  },
  "signature":"base64-encoded-request-signature"
}

Example of request: (googlepay@shop, payment performed from a mobile application with integrated 3DS SDK)

The merchant passes parameters in the request after the 3DS SDK has been initialised.

{
  "merchantId":"M1MIPS0000",
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131615",
  "fingerprint": {
    "sdk": {
      "appID":"198d0791-0025-4183-b9ae-900c88dd80e0",
      "encData":"encrypted-data",
      "ephemPubKey": "encoded-public-key",
      "maxTimeout": 5,
      "referenceNumber":"sdk-reference-number",
      "transID":"7f101033-df46-4f5c-9e96-9575c924e1e7"
    }
  },
  "signature":"base64-encoded-request-signature"
}

Return values  

Item Type Description
payId String Unique payment ID (assigned by the payment gateway in the googlepay/init operation, contains a 15-character string).
dttm String Date and time of the response in the format YYYYMMDDHHMMSS.
resultCode Number The result of the operation, see list.
resultMessage String Text description of the operation result.
paymentStatus Number Payment status, see payment lifecycle.
statusDetail String Detailed status of payment (detailed status), contains, for example, the reason for the payment refusal, see description.
actions Object The structure for transmitting the necessary data for the execution of confirmation within payment authentication. See structure actions.
signature String Response signature, encoded in BASE64.

Example of return values for googlepay/process operation (without having to make a payment authentication confirmation)

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131618",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 2,
  "signature":"base64-encoded-response-signature"
 }

Example of return values for googlepay/process operation (including parameters for confirmation within the payment authentication in the customer's browser)

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131618",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 2,
  "actions": {
    "authenticate": {
      "browserChallenge": {
        "url":"https://example.com/challenge-endpoint"
      }
    }
  },
  "signature":"base64-encoded-response-signature"
 }

Example of return values for googlepay/process operation (including parameters for confirmation within the payment authentication using the 3DS SDK)

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131618",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 2,
  "actions": {
    "authenticate": {
      "sdkChallenge": {
        "threeDSServerTransID":"eeddda80-6ca7-4b22-9d6a-eb8e84791ec9",
        "acsReferenceNumber":"3DS_LOA_ACS_201_13579",
        "acsTransID":"7f3296a8-08c4-4afb-a3e2-8ce31b2e9069",
        "acsSignedContent":"base64-encoded-acs-signed-content"
      }
    }
  },
  "signature":"base64-encoded-response-signature"
 }

The result of authentication and subsequent authorization must be found by a subsequent call to payment/status. Processing times may vary depending on whether payment confirmation is required as part of its authentication:

  • if no confirmation is required, the recommended call time is 2-3 seconds after calling googlepay/process, if the payment status is still 2 (payment in progress), it is recommended to call periodically at intervals of 5 seconds (the total authorization time depends on the processing of the request in VISA/MC systems and in the worst case it can be up to 60 seconds).
  • if confirmation is required, it may take several minutes for the customer to confirm the payment and the card issuer completes the authentication. In this case, we recommend calling payment/status periodically at longer intervals, e.g. 30 seconds.
Clone this wiki locally