Communication Protocol Details

This article defines how the payment integrator's HTTP server should be configured for server to server communication.

TLS authentication and encryption

The server API must be implemented as an HTTPS endpoint. The client will verify the server's identity through the trust of a Root CA. The client will have common name (CN) checking turned on. The server's CN or wildcards must match the hostname. The server must support TLS 1.2 as a minimum.

The server's certificate must be issued by a root certificate included in the Mozilla CA certification program. The use of a self signed certificate is supported but strongly discouraged as it increases the level of maintenance necessary to keep this connection healthy.

The server's certification shouldn't be revoked by that CA, if it is revoked, Google will contact you to get a new cert immediately.

The channel will be encrypted using the session key negotiated during the TLS handshake.

The server must support at least one of these cipher suites. Further the server should not support cipher suites outside of the following set:

  • ECDHE-ECDSA-AES128-GCM-SHA256
  • ECDHE-RSA-AES128-GCM-SHA256
  • ECDHE-ECDSA-CHACHA20-POLY1305
  • ECDHE-RSA-CHACHA20-POLY1305
  • ECDHE-ECDSA-AES128-SHA256
  • ECDHE-RSA-AES128-SHA256

Client certificate checking

TLS client authentication should only be enabled if required by the chosen application protocol (see below). Specifically, if the application-level protocol provides authentication (e.g., PGP), then TLS client authentication must be disabled. If th application-level protocol does not provide authentication (e.g., JWE), then TLS client authentication must be enabled.

Application protocol

All communication uses HTTP POST. The POST and response bodies will be JSON serialized, encoded and encrypted using one of the following approaches:

  • PGP signed and encrypted web-safe base64 (preferred). For PGP details, see PGP best practices.
  • JWE encrypted using compact serialization plus TLS client cert checking for authentication. Additionally, JWS signature verification can be added to JWE encryption. For JWE details, see JWE best practices.

Note that the clear text JSON (prior to any encryption) will be encoded to UTF-8.

See further discussion of each approach in the "Application layer authentication and encryption" section below.

HTTP paths

Integrator-hosted URLs

The calling method and major version is defined in the HTTP request's path. The path will end with a v and then the numeric major version number, a '/' and the method name. So, the last part of the path will be /<method>. If an integrator's base URL is "https://example.com/apps/", then the following requests will be sent:

Example URLs of different versions
3 associateAccount

https://example.com/apps/v3/associateAccount

1 capture

https://example.com/apps/v1/capture

Google-hosted URLs

The documentation for each Google-hosted method provides a base URL, which includes the method name and major version number. The complete URL is created by adding the caller's Payment Integrator Account ID to the end. For example, the documentation for the Google-hosted echo method specifies the URL:

https://billpaynotification.googleapis.com/secure-serving/gsp/v1/echo

If the caller's Payment Integrator Account ID is INTEGRATOR_1, they would add that to the end of the URL to form:

https://billpaynotification.googleapis.com/secure-serving/gsp/v1/echo/INTEGRATOR_1

HTTP response codes

The server application must return 200 for all requests it accepts. This includes both successful and declined requests.

If a request cannot be processed, this represents an error between Google and the payment integrator. In error situations an HTTP 200 must not be returned. You must use an error code from the table below. In order to provide more detailed diagnostic information the HTTP body can be an ErrorResponse, however it is acceptable to have an empty HTTP body as well. Error responses must not be cached or returned idempotently, as a change in system state may result in subsequent retries succeeding.

HTTP Errors And Reasons
400 BAD REQUEST / FAILED PRECONDITION

Client specified an invalid argument. Note that this should not be used for situations where an appropriate application error is available. For example, incorrect currencies should return ACCOUNT_DOES_NOT_SUPPORT_CURRENCY, not 400.

This can also be returned if the operation was rejected because the system is not in a state required for the operation's execution.

Use this if retries of the request cannot succeed until the system state has been explicitly fixed. For example, if a refund request fails because it references a capture that does not exist, retrying will not succeed until the capture exists in the integrators system.

401 UNAUTHORIZED

The request does not have valid authentication credentials for the operation. For example, invalid signatures or unknown signatures should return 401.

403 FORBIDDEN / PERMISSION DENIED

The caller does not have permission to execute the specified operation.

404 NOT FOUND

Some requested entity such as payment or user was not found.

409 CONFLICT / ABORTED

The operation was aborted, typically due to a concurrency issue like sequencer-check failures, transaction aborts, etc. This code should be used in situations where an idempotency key is being reused with different parameters.

429 RESOURCE EXHAUSTED / TOO MANY REQUESTS

Some system resource has exhausted.

499 CANCELLED

The operation was cancelled (typically by the caller).

500 INTERNAL ERROR

Internal errors. This means some invariants expected by underlying system has been broken.

501 UNIMPLEMENTED

Operation is not implemented, supported or enabled in this service.

503 UNAVAILABLE

The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying.

504 GATEWAY TIMEOUT / DEADLINE EXCEEDED

Deadline expired before operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire.

Error results must never be cached or idempotently returned.

Application layer authentication and encryption

As noted above, the HTTPS POST and response bodies will be encoded using either PGP signing and encryption, or JWE encryption. This section describes those two alternatives in detail.

PGP Signed and Encrypted Bodies

In this approach, the client will sign and encrypt the JSON body using PGP. The PGP-encoded payload will then be web-safe base64 encoded and put into the HTTP body. The client may choose to include signatures generated by multiple private PGP keys for a single request. Further, the client may choose to encrypt to multiple public PGP keys for a single request. The public PGP keys will be exchanged at initial set up time.

The server must verify that every request is signed by Google's private PGP key.

For PGP details, see PGP best practices.

HTTP Content-type (PGP)

PGP-encoded HTTP POST requests and responses must use the content type application/octet-stream.

HTTP Body Encoding (PGP)

As noted above, clear text JSON will be PGP encrypted and then web-safe base64 encoded. Below is a bash example of how this encoding should work. The example below assumes you have a linux machine available and GnuPG install

First create a temporary gpg home directory.

export GNUPGHOME=/tmp/gpghome
mkdir --mode=700 $GNUPGHOME

Now generate an RSA PGP key:

gpg --batch --gen-key <<EOF
Key-Type: RSA
Key-Length: 2048
Name-Real: example@google.com
Name-comment: Example Key
Name-Email: example@google.com
Expire-Date: 14
%commit
EOF

Now create an example JSON object, we'll use an echo request.

JSON_ECHO_REQUEST=$(cat <<EOF
{
  "requestHeader": {
    "protocolVersion": {
      "major": 1,
      "minor": 0,
      "revision": 0
    },
    "requestId": "$RANDOM",
    "requestTimestamp": "$(date +'%s')000"
  },
  "clientMessage": "v1.echo message"
}
EOF
)

Finally encrypt and encode the example JSON. Note: the sed lines turn base64 encoding into URL-safe base64 encoding.

echo $JSON_ECHO_REQUEST  \
| gpg --encrypt --recipient example@google.com --sign \
| base64 -w 0 \
| sed 's/\+/-/g' \
| sed 's#/#_#g' > /tmp/encrypted_json_echo

This resulting file can then be decrypted by first decoding the base64 data and then decrypting the resulting binary.

cat /tmp/encrypted_json_echo \
| sed 's/-/+/g' \
| sed 's#_#/#g' \
| base64 --decode \
| gpg --decrypt --recipient example@google.com

JWE Encrypted Bodies

In this approach, the client will encrypt the JSON body using JSON Web Encryption (JWE). In this approach, the entire body of the POST or response will be a JWE token, using JWE's "Compact Serialization" option. Both sender and receiver must support JWE compression (i.e., zip="DEF"). We will use asymmetric (public key) encryption, and the public JWE keys will be exchanged at initial set up time. Additionally, JWS signature verification can be used along with JWE where the content is signed before encryption and verified after decryption. JWS too uses asymmetric keys; private key for signining and public key for verification.

For JWE details, see JWE best practices.

HTTP Content-type (JWE)

JWE-encoded HTTP POST requests and responses must use the content type application/jose.

Testing Connectivity

Once an payment integrator account is set up with Google, connectivity can be tested by calling the Google-hosted echo endpoint.

This script uses the Google-hosted Sandbox environment echo method to test baseline connectivity: gsp_sandbox_echo.sh