The purpose of FPS is to transfer money between different Amazon Payments account holders. This fact makes it more difficult to develop and test FPS applications than the other services we explore in this book because it involves dealing with real money.
To allow developers to create FPS applications without risking disastrous side-effects from bugs or misunderstandings, Amazon provides two distinct FPS environments: production and sandbox. You can interact with one environment or the other by using the appropriate environment endpoint URIs.
The production environment is the real deal. Transactions performed in this environment will transfer money between official Amazon Payments accounts, draw on credit card or bank accounts, incur transaction fees, and experience all the real-world delays inherent in dealing with external financial systems. To perform test transactions in this environment, you will need third-party customers, clients, or colleagues who are willing to help you out by transferring their money.
Amazon recommends that developers avoid running their application in the FPS production environment until it has been thoroughly tested and proven in the sandbox, and we are inclined to agree. The code and examples in this chapter will only use the sandbox environment.
Table 10-5 shows the URI endpoints to access the different components of the production environment.
Table 10-5. FPS production endpoints
Resource | URI |
---|---|
Account Management web site | https://payments.amazon.com |
API | https://fps.amazonaws.com/ |
UI Pipeline | https://authorize.payments.amazon.com/cobranded-ui/actions/start |
The sandbox environment is a fully-functional FPS system for development and testing that does not transfer real money or incur real transaction fees. The sandbox makes it possible to test all aspects of FPS, from API operations and third-party CBUI pipeline requests, to account management using fake accounts. Here are some of the key sandbox features you can use of to test your application’s interaction with FPS and assess the experience from the perspective of your customers:
Perform all API operations available in the production environment.
Transfer fake money between Amazon Payments sandbox accounts and incur fake fees. To allow you to test transaction limits, Personal sandbox accounts have a $500 sending and receiving limit, while Business sandbox accounts have a $500 sending and $2000 receiving limit. If you link a bank account to either of these accounts the limits are removed.
Add fake credit card and bank checking accounts to your Amazon Payments Sandbox account. These payment methods are automatically verified by the service.
Configure the branding of your sandbox UI pipeline to see how it looks to third parties.
Register new Amazon Payments sandbox accounts with fake email addresses, so you can interact with your application as if you were a third-party customer or client.
Manage third-party accounts in Amazon’s web interface to test the user’s experience.
Table 10-6 shows the URI endpoints to access the different components of the sandbox environment. These URIs are similar to the production URIs, except that they all contain the word “sandbox.”
Table 10-6. FPS sandbox endpoints
Resource | URI |
---|---|
Account Management web site | https://payments-sandbox.amazon.com |
API | https://fps.sandbox.amazonaws.com/ |
UI Pipeline | https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start |
The sandbox environment includes some special features that can help in testing your FPS application. To begin with, transaction times in the sandbox sometimes differ from what you would experience in the real world.
Amazon Payments account balances are transferred immediately, or synchronously, as it would in production.
Credit card transfers are delayed by only a second or so.
Checking account transfers are delayed by only 60 to 120 seconds; in production they can take 5 to 7 days.
In the sandbox you can simulate the error conditions caused by a customer’s faulty Amazon Payments account by using the following predefined sender payment instruction tokens in a transaction.
Error Condition | Sender Token |
---|---|
Email address not verified | J5B1P2Q4VIA2V3ZB475M6MQFSK9EZDARCCFV4UV7VTDB9ZVX6LEE3XRXFHTBEXI1 |
Suspended account | H7PSM2Z9A53NVQFId834IIFM1G8JI1RKQUTK1MPAGMFZASSGFDV3RCDU4ZMNFIK4 |
Closed account | Z1VR1HA7R7LXXSM7243F34ACQDPEZMLD8V5QSSE4GU654MCZLIHICW8MTXC1TLF9 |
You can simulate the error conditions caused by a recipient’s faulty Amazon Payments accounts by using the following pre-defined recipient payment instruction tokens.
Error Condition | Recipient Token |
---|---|
Email address not verified | J4B1S2L4V7AEV3RBB7596ZQFXKUEZ9AHCCHV3UVVV7DBFZKX6IEP3XNXQHTTECIC |
Suspended account | H5PS82X9AC31VQPIQ83BILFMBGGJI1RAQURKPMP9GLFZNS1GFQVVRCTUFZM4FFKT |
Closed account | Z5VRRHX7RZL4XS57Z43H32ACPDAEZ4LC8V3QFSEAG365TM3ZLIHXCWXM1XCKTDF5 |
Finally, you can simulate transaction errors by using transfer amount values that follow one of the following formatting patterns:
The FPS web service API is made available through two interfaces: Query and SOAP. In this book we will use the Query API.
The FPS implementation presented in this chapter uses the Query API functionality implemented in the AWS Ruby module. The AWS module includes the methods we presented in Query API Implementation” in Chapter 2: these perform authentication, transmission, and response checking of Query API requests.
Amazon uses version identifiers to label different versions of
most of their service APIs. By assigning each API version its own
identifier, Amazon can continue to develop and change the APIs without
without breaking AWS client implementations that use the older
versions. The most recent FPS API version available for use in this
book was 2007-01-08
.
In this chapter we will gradually build up a complete
implementation class called FPS,
which you can use to interact with the FPS service. Example 10-1 defines a basic Ruby code stub that defines
the FPS
class, to which we will add
API implementation methods as we proceed through the Chapter 10, Chapter 11 and Chapter 12. Save this code to a file named FPS.rb in the same directory as the
AWS
module file AWS.rb, defined in Chapter 2.
Example 10-1. FPS class stub: FPS.rb
require 'AWS' class FPS include AWS # Include the AWS module as a mixin ENDPOINT_URI = URI.parse("https://fps.sandbox.amazonaws.com/") PIPELINE_URI = URI.parse("https://authorize.payments-sandbox.amazon.com"+ "/cobranded-ui/actions/start") API_VERSION = '2007-01-08' SIGNATURE_VERSION = '1' HTTP_METHOD = 'POST' # 'GET' # FPS API implementation methods will go here... end
This class will rely on the communication library implementation
defined in the AWS
module, which it
includes as a mixin module. A mixin is a feature of Ruby that makes
the variables and methods defined in a module available to a
class.
The FPS class defines four constant values: the ENDPOINT_URI
constant defines a URI that
will be used as the target for FPS service requests; the PIPELINE_URI
represents the target for
requests to the FPS CBUI Pipeline web site; the API_VERSION
and SIGNATURE_VERSION
constants define which API
and Signature versions this implementation is compatible with; and the
HTTP_METHOD
constant defines
whether the class will use POST or GET request messages by
default.
All response messages returned by the FPS query interface include an XML document that contains two important elements directly under the document’s root element: RequestId and Status.
If your request was accepted by the service, the RequestId element will contain a 39-character string value that uniquely identifies the request in the FPS system. If you experience difficulties with the service, you can provide this identifier value to Amazon support staff, who can investigate the issue.
. . .
<Status>Success</Status>
<RequestId>3361b659-3b3d-4741-9435-ac4573374448:0</RequestId>
</ns3:GetPaymentInstructionResponse>
And here is a portion of an XML response document after a failed operation:
<ns3:GetPaymentInstructionResponse
xmlns:ns3='http://fps.amazonaws.com/doc/2007-01-08/'>
. . .
<Status>Failure</Status>
<Errors>
<Errors>
<ErrorType>Business</ErrorType>
<IsRetriable>false</IsRetriable>
<ErrorCode>TokenAccessDenied</ErrorCode>
<ReasonText>Your access to this token is denied.</ReasonText>
</Errors>
</Errors>
<RequestId>3837655c-9fe9-4fba-8fb2-ac738bc70127:0</RequestId>
</ns3:GetPaymentInstructionResponse>
Notice that the response document from a failed operation
includes a Status element with a value of Failure
, and that it contains an Errors
element with more information about the reason for the
failure.
The FPS Query API interface represents errors differently from the other Query-based service interfaces discussed in this book. When an FPS API operation fails, instead of returning an HTTP response message with an HTTP error code and further details in the response body, it returns an HTTP 200 success message with an XML error document.
To recognize when an error has occurred, we must therefore parse the contents of every response message received from the FPS service to determine whether or not an operation has succeeded. We cannot rely on the HTTP status code to give us a hint.
The XML error messages returned by the service will always include four elements; these are listed in Table 10-7.
Table 10-7. Elements in FPS XML error messages
Name | Description |
---|---|
ErrorType | Indicates whether the error was caused by a system problem or a mistake in the request’s business logic. In general, business errors are the fault of the client, whereas system errors are the fault of FPS. |
IsRetriable | Indicates whether the error may be temporary, in
which case it may make sense to retry the request later.
This value will be true
or false . |
ErrorCode | A predefined error code that indicates what went wrong, see Appendix B for a list of FPS error codes. |
ReasonText | An explanation for why the error occurred. |
To make it easier for our FPS client implementation to detect
errors, we will define an extra method specifically for this service
that will perform query requests and check the resulting XML
document for errors. Example 10-2 defines
the method do_fps_query
, which
uses the standard AWS do_query
method to send a request to the service and then performs the extra
work of parsing the result document and checking its status. If the
operation did not succeed, the method raises an FpsServiceError
.
Example 10-2. Do FPS query: FPS.rb
def do_fps_query(parameters) response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters) xml_doc = REXML::Document.new(response.body) if xml_doc.elements['*/Status'].text != 'Success' raise FpsServiceError.new(xml_doc) end return xml_doc end
Because the structure of an XML error message returned by FPS
is different from the structure of errors from other the other AWS
services, we will use a specialized error class to interpret these
errors. Example 10-3 defines a class
called FpsServiceError
that
extends Ruby’s default RuntimeError
object to store the additional error response information
made available by FPS.
Example 10-3. FpsServiceError class: FPS.rb
class FpsServiceError < RuntimeError attr_accessor :code, :reason, :type, :retriable def initialize(xml_doc) errors = xml_doc.elements['*/Errors/Errors'] code = errors.elements['ErrorCode'].text reason = errors.elements['ReasonText'].text type = errors.elements['ErrorType'].text retriable = errors.elements['IsRetriable'].text == 'true' # Initialize the RuntimeError superclass with the descriptive message super(code + " - " + reason) end end
This class is initialized with an XML document from which it
retrieves the value of the four common elements in an FPS XML error
response document. These values are made accessible from outside the
class through the code
, reason
, type,
and retriable
accessors.
FPS API transaction operations are idempotent. This means that even if a particular API transaction request message is sent to the service multiple times, it will only ever be acted upon once. This feature is very important in a financial service because it removes the risk that network or application glitches will result in transactions being repeated by mistake. When FPS receives a transaction request message with parameters that are identical to a message it has already received, it will do nothing but return the original response message to the client.
To make each of your transaction requests unique, the API operations require that you provide a caller reference value of up to 50 characters that uniquely identifies each request. This string reference value should be generated by your application in a way that ensures it will always be unique. Your application may be able to use an order code as a unique reference value for each transaction or a sequence number from a database. This feature allows your application to obtain response information for requests when the original response failed to arrive due to networking problems.
Because FPS operations are idempotent, you must be careful not to accidentally reuse the caller reference values you provide with your requests. If you reuse reference values and happen to perform a similar transaction to one from the past, you will receive the original response message in return. This could lead you to believe that a new transaction had occurred, when you were actually seeing the result of an old transaction.