Result codes

Processing payments is a complex and long chain of interactions between many actors involved, and there's a long list of things that can go wrong there. Thankfully, our team at Payrails has seen a lot in their years of experience and is here to help you navigate this complex field.

One of the main challenges we have is to understand exactly what happened in a payment transaction. Unfortunately, there's not yet a standard of responses from PSPs, and each of them has its own way to inform you about these results. For example, some of them opt for a numeric list of possible responses, others choose to inform you through HTTP status codes, others through a string field, and a big etcetera.

Payrails comes to your help here! Every time we integrate a new PSP, we work together with them to map from their list of response codes to ours, so that we can provide you with only one list of possible results regardless of which PSP was used for processing the transaction.

These response codes can be found in the result field of each of your Payment Operations. You can also check the responseCode field to check what was the original response code from the PSP, before Payrails converted it into a generic result.

For example, here's how the Get an execution by ID response would look for a failed execution because of insufficient funds in the card:

{
  "id": "fe67fc45-ce47-4fc8-a283-22d03ae68b77",
  "status": [
    ...
    {
      "code": "authorizeFailed",
      "time": "2022-04-22T17:53:36.814Z",
      "errors": [
        {
          "id": "8b631f4e-35c4-41c5-8ce9-5f2c74eb5659",
          "title": "execution.payment-method.failed",
          "detail": "The payment method produced a non-successful status."
        }
      ]
    }
  ],
  ...
}

And here's the notification for the same execution:

{
  "event": "executionActionCompleted",
  "time": "2022-04-22T17:53:36.814Z",
  "details": {
    "action": "authorize",
    "execution": {
      "workflowCode": "d5454c2f-ae5e-44f3-8edf-f6dad64f005f",
      "id": "fe67fc45-ce47-4fc8-a283-22d03ae68b77",
      "merchantReference": "order_3573894940903"
    },
    "success": false,
    "errors": [
      {
        "id": "8b631f4e-35c4-41c5-8ce9-5f2c74eb5659",
        "title": "execution.payment-method.failed",
        "detail": "The payment method produced non-successful status."
      }
    ]
  }
}

The following is a list of all possible result codes from Payrails, grouped by type:

Success

CodeDescription
SuccessThe requested operation was performed successfully.
AcceptedThe operation was requested but not executed yet, it was scheduled for execution on the provider side. This is usually followed by waiting for a notification callback or a status querying with some waiting policy.

Pending actions

Next, also a type of happy path but with some type of pending action before they can be completed.

CodeDescription
PendingThe operation is waiting for an action to be completed. Could be the user receiving a push notification on their phone, the bank reviewing a transaction, etc.
HTTPRedirectRequiredThis is a special type of Pending, where there's an HTTP redirection that needs to be made for the user to complete the process, i.e. 3DS, external wallets, etc. This result comes always with redirection data in the response body, i.e. a redirect URL and a set of parameters.
FormRedirectRequiredSame as HTTPRedirectRequired, but with a Form redirection.

Unknowns

Let's discuss the most worrying ones next, the ones where we don't know what actually happened. Any of these results should be considered a high priority to alert and analyze as soon as possible.

CodeDescription
UnknownReceived a response, but could not be interpreted by us. Could be caused by a change in implementation on any side.
UnexpectedProviderResponseReceived a response, but it was not any of the ones that we expected for the type of operation being executed.
ProviderUnknownErrorSame as Unknown but from the provider's side calling another part, i.e. acquirer.

Connection issues

Next, equally important to analyze and optimize if possible, are the connection and timeout-related codes.

CodeDescription
ProviderConnectionErrorThere was a problem reaching the provider services. Could be caused by an actual connection problem, or that the provider is down or not responding.
TimeoutThere was a timeout waiting for a response from the provider. In this case, the connection could actually be established, but there was no timely response.
ProviderTimeoutSame as Timeout but the connection that failed was between the provider and another actor, i.e. acquirer.

General rejections

Next, let's look at the payment rejection results, which depending on the provider and other factors, may go from completely generic to very specific.

CodeDescription
GenericRejectionThe provider (or any of the actors in the chain) rejects the transaction but does not specify a specific reason. This code is often referred to as "do not honor".
FraudRiskThe transaction is rejected because there's a risk of fraud. The check could have been done by any of the players in the chain.
DuplicateOperationPayment is rejected because it would be a duplicate of another one. We should check if we were actually retrying it or if it was a mistake.
OperationNotAllowedOperation is not allowed, usually related to the current status of the transaction, i.e. trying to capture an already canceled payment.
LimitExceededSome limit was exceeded by the provider or the issuer. Usually a configurable value on their systems for preventing fraud.

Payment instrument rejections

Next, a special type of payment rejections, the payment instrument related rejections.

CodeDescription
InstrumentNotAllowedOperation is not allowed for the instrument, i.e. trying to use a debit card when it should be credit.
InvalidInstrumentThe instrument is not valid for any reason not specified. In some cases the provider groups other responses into this one (insufficient balance, expired, blocked, etc.)
InsufficientBalanceThe selected instrument doesn't have enough balance to perform the operation.
BlockedInstrumentThe instrument is currently blocked. Could be a temporary state because it's pending approval for example, but could be permanent like when cards are blocked because they were stolen.
ExpiredInstrumentThe instrument is expired. In case it was a card, it reached the expiration date. In case it was a token, it may have been revoked or was initially issued for a short time.

Configuration issues

Next, we have the parameter or configuration errors. These could be similar to the rejections but could be caused by a problem with formatting, missing required parameters, etc.

CodeDescription
ValidationErrorBefore sending the transaction to the provider, we performed a parameter validation and it failed. This code comes together with a list of errors specifying the fields and problems.
ParamsErrorAfter sending the transaction to the provider, they decided not to execute it because of a problem with the parameters we sent. Could be a required field is missing, incorrectly formatted, etc.
ProviderConfigErrorWhen sending the transaction to the provider, they refused to process it because we are missing something required for the operation, e.g. merchant ID, client secret, etc.
InvalidSignatureFor providers that require a signature in the requests, there's a specific result for when the signature was actually invalid.
AuthenticationErrorA special case of ParamsError, but specifically about an error when authenticating on the provider services.
AuthenticationRequiredNeeded authentication parameters were not provided and are required to continue.

Payer Authentication

Next, we have the payer authentication error, which can either arise from a missing or incorrect PIN or a 3DS check that didn't occur. It's important to distinguish these ones, that are payer specific, from the server credentials authentication errors.

CodeDescription
PayerAuthenticationRequiredCredentials were not provided by the user.
PayerAuthenticationFailedIncorrect or invalid credentials were provided by the user.

Internal issues

Last but not least, if something went very wrong during the operation and there was actually an internal server error, we need to indicate it. And, of course, fix it as soon as possible!

CodeDescription
InternalServerErrorThere was an error in our system while trying to process the operation. This will trigger an alert for the Payrails team to act immediately.