Error Handling

This guide will focus on:

  • Common errors that may occur at the point of transaction creation (where these errors will be returned with some form of a 4xx status in the create-transaction response) and updating the transaction accordingly
  • Handling validation errors that occur at the time of calling the place-order endpoint, and updating the transaction object accordingly. The default status of a newly created real estate transaction is draft where there's an expectation that one or more properties may be updated before the transaction is sent to the title agency or signers. This is why the majority of data validations on the transaction object are executed at the point in time where the place-order endpoint is called.
  • When {{api_base_url}} is referenced below, this is generic variable syntax representing either the Fairfax/Testing URL or the Production API URL. If you would like access to Fairfax please contact the customer success or support team.
  • When {{transaction_id}}is referenced below, this is generic variable syntax representing a transaction ID which is represented by ot_xxxxxxx. The transaction ID is returned in the create-transaction response, represented by the id property.

Common errors and error handling workflows

  • Omitting the signers array will return a different error depending on the parameters and sequence of API calls utilized. If a request is sent to the create-transaction endpoint with draft:false in the body and no signers are included, the following will be returned:
{
    "errors": [
        "Need at least 1 signer"
    ]
}
  • If transactions are created in a draft state and then a request is sent to the activate-draft-business-transaction endpoint without any signers on the transaction, the following will be returned. A valid email is the only required field associated with the signers array:
{
    "errors": [
        "Customer email not present"
    ]
}
  • White Text Tags (WTT) work asynchronously. When the [create-transaction] endpoint is called with (https://dev.proof.com/reference/create-business-transaction) "draft": false in the request body, the server tries to execute two operations at once (creating the transaction, and then sending to the signer(s)). The server doesn't know if tags were successfully applied until some time after the related request (ex. create-transaction) resolves. If a POST request is sent to the create-transaction endpoint with "draft": false in the body, and any included documents are set with the esign requirement, the following will be returned. To avoid this, create a draft transaction and then activate it in a subsequent request.
{
    "errors": [
        "Esign required yet no Signer Designations specified in Document Bundle"
    ]
}

Errors specific to the Real Estate API

  • Omitting the transaction_type, or misspelling the transaction type will return a 422 status with the following message
{
    "errors": [
        "Invalid Value for transaction_type"
    ]
}
  • Including a contact with a role other than the accepted values (escrow_officer, loan_officer, real_estate_agent, title_agent, closer, other) will return the following message:
{
    "errors": [
        "Invalid value for argument role."
    ]
}
  • Omitting the signers array or the documents array will not return errors in the create-transaction response, but if place-order is called on a transaction without any associated signers or documents, it will return the following message indicating the transaction is missing a customer(signer) email. A valid email is the only required field associated with signers.
{
    "errors": [
        "Customer email not present"
    ]
}
  • In a collaborative transaction (where the transaction progresses from lender to title agency), the error below will only surface if the title agency attempts to send the transaction with no lender or title documents associated.
{
    "errors": [
        "At least one document needs to be enabled for notarization or identity confirmation"
    ]
}
  • If a transaction is missing a required property such as the signer(s) array, the transaction can be updated by calling the update-transaction endpoint and passing the desired data in it's appropriate format.

PUT {{api_base_url}}/mortgage/v2/transactions/{{transaction_id}}

{
  "signers": [{
    "email":"[email protected]",
    "first_name": "Signer",
    "last_name": "One",
    "phone": {
        "number": "1123456789",
        "country_code": "1"
    }
  }]
}
  • When the refinance or purchase_buyer_loan transaction types are utilized, the API is expecting a valid enote on the transaction which can be added via the add-enote endpoint or via uploading the enote in the Proof lender UI. The following error will be returned when there's an attempt to send a transaction (via the place-order endpoint) to the signer without an enote.
{
    "errors": [
        "eNote Required"
    ]
}

For any use case where the API user would like to avoid running into this validation (ie, if the enote is signed/vaulted externally from Proof and not included in the transaction object), passing paper_note_consent: true in the create-transaction payload will skip this enote validation regardless of the transaction type.

If the content of a transaction body includes all required fields with valid syntax, calling the place-order endpoint on the transaction will return a 200 response.

The place-order response body includes the status and detailed_status properties which should be used to monitor and understand the transaction lifecycle.

Common statuses include sent_to_title_agency, sent (indicating the transaction was sent to the signer(s)), and clear_to_close (indicating the transaction was sent to Proof Closing Operations, which is an optional interim step before the docs are sent out to the signer).

Integration Design and Exception Handling

API integrations should be designed in a manner so that unexpected/undesired responses are handled gracefully as opposed to failing silently. Some benefits of catching and handling errors include:

  • The error responses returned from our API includes useful information that can be consumed and acted upon by the application comprising the integration.
  • Errors occurring at runtime for crucial operations (ie placing an order or activating a draft transaction) can be identified as an exception, and this information can be surfaced client-side if user feedback caused the error (ex. if a user submits an invalid phone number on a client-side form that calls the Proof API on the backend).
  • Logging Proof headers will include a helpful value that can be utilized by Proof technical support to more easily find the relevant request/response cycle in our logs. This key/value pair is currently represented by the X-Amz-Trace-Id key. For example:

While the exact syntax and grammatical formatting for error handling is unique depending on the programming language utilized, some generic examples are included below.

Ruby:

  • Utilizing conditional flows (ie if/else) statements to capture non-200 level HTTP status codes.
if response.code.eql?("200")
	# can print a success message to the console or anything else desired here
    puts "success, created transaction #{formatted_response["id"]}" 
else
	@failure_message = formatted_response["errors"]
end

Javascript

  • Try/catch blocks
    The general paradigm is similar across languages such as .NET and Node. Language-specific syntax is available within the documentation associated with the respective language or framework. Some great examples of handling Javascript errors are available here

This is a generic example of Javascript error handling from Mozilla's documentation:

(() => {
  try {
    try {
      throw new Error("oops");
    } catch (ex) {
      console.error("inner", ex.message);
      throw ex;
    } finally {
      console.log("finally");
      return;
    }
  } catch (ex) {
    console.error("outer", ex.message);
  }
})();

// Logs:
// "inner" "oops"
// "finally"

ASP.NET
More info on .NET error handling is available here.

try
{
    // the operation the system is attempting, such as adding documents to a transaction 
    // or updating signer contact information
}
catch (Proof.Errors.Validation ex)
{
    // If there was a problem with the request, it's helpful to give the
    // end user feedback why their request failed, or at a minimum, capture the error and log 
    // it appropriately so the error can be located and investigated easily at a later date.

    Console.WriteLine($"Failed validation: {ex.Error.Message}");
}
catch (Proof.Errors.ApiError ex)
{
    // Catch the error returned from the Proof API
    Console.WriteLine($"Unexpected Proof Error: {ex.Error.Message}");
}