Escrow Transaction Purchase

Another version of this information is available

If you're new to Tilia services, a newer version of this information is available in the Transaction Tutorials section of these docs, which might be an easier place to start.

Sometimes it makes sense to collect funds from a user upfront and hold distribution until an agreed-upon condition is met. If the condition is met, the collected funds can be routed to the seller(s). If not, the funds can be refunded to the buyer. These sorts of two-phase interactions are what Escrow Transactions were built for, and they apply to both user-to-user and user-to-integrator purchases.

Example use cases for escrow transactions include:

  • Transactions in which product delivery happens asynchronously.
  • Payment for services rendered, where the buyer funds should be held until a seller service is completed satisfactorily.
  • Situations in which the delivery of payment is conditional upon an unknown future event.

In each of these cases, it may be useful to hold the buyer's funds, and commit or cancel the transaction at a point in the future.

  • Commit refers to executing the intent of the escrow transaction, such as allowing sellers to be paid.
  • Cancel refers to undoing the escrow transaction because an external condition caused the original invoice to no longer be necessary. In the case of cancel, the buyer's payment method is refunded in full.
attention

When creating an escrow transaction, the buyer's payment method is charged in order to place the funds in escrow. If the escrow transaction is later canceled, the buyer's payment method is refunded. In this case, the buyer will see both a charge and a refund on their account statement.

This guide walks through the process of creating an escrow transaction, and committing or canceling it.

Prerequisites

To complete this example, you'll need the following:

  • An Access Token with the requisite scopes: read_payment_methods , write_user_tokens and write_invoices
  • An account ID for the buyer. Refer to Registering Users for information on creating user accounts.
  • An account ID for the seller.
  • A web page containing the Tilia widget script. Refer to Widget Integration for instructions on setting this up.
  • A payment method. Refer to Test Payments for payment methods you can use in testing.

Capture Payment Details

In this section, you'll be using the Tilia API to retrieve information about the seller's wallet, and using the Web UI to capture information about the buyer's payment method.

Step 1: Get seller wallet info

Sellers receive payments in their Tilia wallets. Each wallet has a unique ID that can be used in building transactions.

To retrieve the seller's wallet ID, submit a GET request with the seller's' account_id to the /payment_methods endpoint.

Copy
Copied
curl --location --request GET https://payments.tilia-inc.com/v1/{account_id}/payment_methods \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

This returns all of the payment methods associated with the seller's account, including purchase-only payment methods such as credit cards. To locate the wallet, look for the payment method in which provider has a value of wallet, and the currency matches that of the transaction you are creating.

In this example, we are creating a USD transaction, so will be using the seller's USD wallet.

Copy
Copied
{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": [
        {
      "id": "fce464b4-cf9f-49c2-bdb1-2db3275d6284",
      "account_id": "7f938c50-0225-4fbe-b465-81d70934064a",
      "method_class": "registration",
      "display_string": "USD Wallet",
      "provider": "wallet",
      "psp_reference": "a900281d-5d01-4784-a412-f447389929f8",
      "psp_hash_code": "",
      "processing_currency": "USD",
      "pm_state": "ACTIVE",
      "integrator": "acme",
      "created": "2020-08-14 10:59:59",
      "updated": "2020-08-14 10:59:59",
      "wallet_balance": "2457",
      "payment_method_id": "",
      "provider_data": {
        "wallet_id": "a900281d-5d01-4784-a412-f447389929f8",
        "wallet_balance": "2457"
      }
    }
  ]
}

The wallet_id is used in setting up the purchase transaction in step 4.

Step 2: Create redirect URL

To complete a purchase, you'll need to obtain the buyer's payment information. To start, you'll pass the buyer's account ID to create a redirect URL. This URL creates a secure user session, forming the basis for calling the Tilia Purchase flow.

Copy
Copied
curl --location --request POST https://auth.tilia-inc.com/authorize/user \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Request Body

Copy
Copied
{
  "account_id": "string"
}

Sample response

Copy
Copied
{
  "status": "Success",
  "message": [],
  "codes": [],
  "payload": {
    "redirect": "https://web.tilia-inc.com/ui/appauth/19a4a2b0-364c-4cad-a895-14c57bcd4e7c"
  }
}

Step 3: Get buyer payment info

The Payment Selection flow is a web UI that allows the purchasing user to choose a payment method. If the user does not have a stored payment method, they will be able to add one. Upon completion of the flow, an array of IDs for the user's payment method(s) is passed back to you for use in creating the transaction.

Users must have a signed copy of the most recent Tilia Terms of Service (TOS) on file. If the user has not accepted the TOS, or if there is an updated version available, they are presented with a TOS screen which must be accepted before they can select a payment method.

From the widget page, call the following JavaScript to execute the purchase flow.

Copy
Copied
window.Tilia.execute({
	rootId: "< YOUR-ELEMENT-ID >",
	flow: "payment-selection",
	flowConfig: {
            // Optionally include transactionDetails to allow the user the key functionality
            // of choosing their remaining wallet balance before a second payment method.
            transactionDetails: {
                transaction_amount: "< TRANSACTION-AMOUNT >",
                currency: "USD"
            }
        },
	redirect: "< WIDGET-REDIRECT-URL >",
	onComplete: handleComplete,
	onError: handleError,
});

The widget invokes the handleComplete callback with the result of the flow.

If the user cancels anywhere in the flow:

Copy
Copied
{
	"source": “tilia”,
	"event": “tilia.payment-selection.complete”,
	"state": “cancel”,
}

If the user completes the flow:

Copy
Copied
{
    "source": "tilia",
    "event": "tilia.payment-selection.complete",
    "state": "complete"
    "paymentMethods": [
        {
            "payment_method_id": "a787923c-4b82-4400-81e4-34f7baa849b3",
            "amount": 5000
        },
        {
            "payment_method_id": "5ee85a7a-8319-4a53-837c-5d909d184442",
            "amount": 0
        }
    ]
}

You will be able to pass in the paymentMethods array into the next step.

Create & Pay the Escrow Invoice

Now that you have the required payment information, you are ready to set up your escrow transaction, in the form of an invoice. Tilia uses the concept of invoices to describe the detailed information required to process a transaction.

Step 4: Create escrow invoice

Escrow transactions may have any number of line items transaction_type=user_to_user or transaction_type=user_to_integrator. The only difference between escrow transactions and standard invoices, with regards to line item transaction type, is the destination user or publisher receives the specified funds after the escrow commit is executed. If the escrow transaction is canceled, these funds are refunded to the buyer.

For this transaction type, you need to provide the following values:

  • account_id - the buyer's account ID
  • payment_method_id(s) - the id(s) returned by the payment selection flow. You can pass the array returned by this flow into the invoice. When using multiple payment methods, provide an amount for each payment method. A value of “0” indicates the remaining value of the transaction will be charged to that payment method. One of the payment methods must have a value of "0".
  • currency - the currency for the purchase.
  • amount - the amount of the purchase
  • source_wallet_id - your publisher wallet to be used in processing the transfer of funds. Leave this value blank to use the default (appropriate in most cases).
  • destination_wallet_id - the seller's wallet ID (retrieved in step 1).

Additionally, you will want to provide details about the item(s) being purchased, including the seller's product description, SKU, and other transaction information.

The following example is for an escrow transaction with two items, one which should be paid out to a seller recipient, and other that represents a publisher fee.

attention

This example is in USD. Therefore, all amounts are in cents. Refer to Working with Currencies for information on how currencies are used.

The example below requires an API token with the scope write_invoices.

Copy
Copied
curl --location --request POST https://invoicing.tilia-inc.com/v2/escrow \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Request Body

Copy
Copied
{
  "account_id": "<buyer_account_id>",
  "reference_type": "product_purchase_id",
  "reference_id": "purchase_id123",
  "description": "A description of the product",
  "payment_methods": [
      {"payment_method_id": "<id_from_payment_flow>"}
  ],
  "line_items": [
    {
      "amount": 500,
      "currency": "USD",
      "transaction_type": "user_to_user",
      "product_sku": "12345",
    "reference_type": "seller_listing_id",
    "reference_id": "listing123",
      "recipients": [
        {
          "amount": 500,
      "currency": "USD",
          "source_wallet_id": "<your_merchant_wallet_id>",
          "destination_wallet_id": "<seller_wallet_id>"
        }
      ]
    },
    {
      "amount": 50,
      "currency": "USD",
      "transaction_type": "user_to_integrator",
      "product_sku": "12345 fee",
    "reference_type": "seller_listing_id_fee",
    "reference_id": "listing123 fee"
    }
  ]
}

Create escrow sample response

A successful request returns the HTTP 201 Created status code along with a JSON response body containing the escrow transaction details. The response fieldpayload.id is called the escrow_id, and is used in subsequent steps.

Copy
Copied
{
  "status": "Success",
  "message": [],
  "codes": [],
  "payload": {
    "id": "esc_1rS6361ZxyOI7uTi1oIlompWKdP",
    "account_id": "a9007162-8ffc-4374-ba19-fbb72360adf2",
    "escrow_invoice_id": "10dcf0f1-d159-4199-b6d5-e2ffc6144dc2",
    "commit_invoice_id": "",
    "cancel_invoice_id": "",
    "status": "OPEN",
    "created": "0001-01-01 00:00:00 +0000 UTC",
    "updated": "0001-01-01 00:00:00 +0000 UTC"
  }
}

Step 5: Pay the escrow invoice

In the previous step, we created the escrow transaction. Next, it needs to be submitted for processing and payment.

To submit the escrow transaction for processing, POST the escrow_id to the /pay endpoint.

Copy
Copied
curl --location --request POST https://invoicing.tilia-inc.com/v2/escrow/{escrow_id}/pay \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Pay escrow sample response

A successful request returns the HTTP 200 OK status code along with a JSON response body containing the invoice details. Note that the value for status has updated from OPEN to ESCROWED.

Copy
Copied
{
  "status": "Success",
  "message": [],
  "codes": [],
  "payload": {
    "id": "esc_1rS6bdXtag1BPuL1u64hAwDUuk0",
    "account_id": "a9007162-8ffc-4374-ba19-fbb72360adf2",
    "escrow_invoice_id": "53bb4391-1f46-4d14-a229-e2458ca95d12",
    "commit_invoice_id": "",
    "cancel_invoice_id": "",
    "status": "ESCROWED",
    "integrator": "acme",
    "created": "2021-04-20 22:20:16.966098 +0000 UTC",
    "updated": "2021-04-20 22:20:16.966098 +0000 UTC"
}

The value for status will be one of (ESCROWED, ESCROW-FAILED):

  • ESCROWED , indicating the escrow transaction has been successfully paid.
  • ESCROW-FAILED , indicating the escrow transaction could not be paid. In this case, fetching the escrow invoice and inspecting its failure_reason returns additional information.

You can check the status of an escrow transaction by calling GET https://invoicing.tilia-inc.com/v2/escrow/{escrow_id}.

Step 6: Handle the escrow completion event

At each phase of the life cycle, escrow transactions emit a webhook escrow-transaction-updatethat contains the same information as the response from the API call /pay, /commit, and /cancel API calls.

Refer to Escrow transaction webhook for details.

Although this step is not mandatory, we recommend implementing a webhook to notify you about changes to the transaction's status.

For more information about developing and registering webhook handlers, visit Webhooks.

Commit or Cancel the Escrow

In the previous steps, we executed the escrow transaction, which captured funds from the buyer's payment method and placed them into escrow. Funds will remain in escrow until the escrow is committed or canceled.

Step 7: Commit or cancel escrow

To complete the transaction, you will need to either commit or cancel the escrow. If the escrow is committed, funds are released to the seller(s). If cancelled, funds are returned to the buyer's original payment method.

Commit the escrow invoice

To commit the escrow transaction, POST the escrow_id to the /commit endpoint. This will result in the user-to-user and user-to-integrator proceeds being transfered.

You may only commit an escrow transaction in status ESCROWED

Copy
Copied
curl --location --request POST https://invoicing.tilia-inc.com/v2/escrow/{escrow_id}/commit \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Commit escrow sample response

A successful request returns the HTTP 200 OK status code along with a JSON response body containing the details. This changes the escrow transaction to status COMMITTED.

Copy
Copied
{
  "status": "Success",
  "message": [],
  "codes": [],
  "payload": {
    "id": "esc_1rS7ZIi4RdNzOh1M0f10NrnI4mp",
    "account_id": "a9007162-8ffc-4374-ba19-fbb72360adf2",
    "escrow_invoice_id": "f69e1a2e-ed01-4c13-8ed9-fb4775c575e6",
    "commit_invoice_id": "aae3b9e9-4fc5-41f4-957e-f0354cf089a1",
    "cancel_invoice_id": "",
    "status": "COMMITTED",
    "integrator": "acme",
    "created": "2021-04-20 22:28:10.17897 +0000 UTC",
    "updated": "2021-04-20 22:28:10.818466 +0000 UTC"
  }
}

Cancel the escrow transaction

To cancel the escrow transaction, POST the escrow_id to the /cancel endpoint. This will result in the buyer's payment method being refunded, and the user-to-user and user-to-integrator proceeds not being transferred.

You may only cancel an escrow transaction in status ESCROWED

Copy
Copied
curl --location --request POST https://invoicing.tilia-inc.com/v2/escrow/{escrow_id}/cancel \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Cancel escrow sample response

A successful request returns the HTTP 200 OK status code along with a JSON response body containing the details. This changes the escrow transaction to status CANCELLED.

Copy
Copied
{
  "status": "Success",
  "message": [],
  "codes": [],
  "payload": {
    "id": "esc_1rS7ZIi4RdNzOh1M0f10NrnI4mp",
    "account_id": "a9007162-8ffc-4374-ba19-fbb72360adf2",
    "escrow_invoice_id": "f69e1a2e-ed01-4c13-8ed9-fb4775c575e6",
    "commit_invoice_id": "",
    "cancel_invoice_id": "1d99190c-5288-4ce8-97ee-0947f010cc56",
    "status": "CANCELLED",
    "integrator": "acme",
    "created": "2021-04-20 22:28:10.17897 +0000 UTC",
    "updated": "2021-04-20 22:28:10.818466 +0000 UTC"
  }
}

Step 8: Handle the escrow completion event

At each phase of the life cycle, escrow transactions emit a webhook escrow-transaction-updatethat contains the same information as the response from the API call /pay, /commit, and /cancel API calls.

Refer to Escrow transaction webhook for details.

Common Behavior

All escrow and invoice calls require scope: read_invoices and write_invoices to fetch and execute respectively.

You can always get the overall state of an escrow transaction by calling

GET https://invoicing.tilia-inc.com/v2/escrow/{escrow_id}

You can check the internal details of a particular phase of the escrow transaction by calling

GET https://invoicing.tilia-inc.com/v2/invoice/{escrow_invoice_id}

GET https://invoicing.tilia-inc.com/v2/invoice/{commit_invoice_id}

GET https://invoicing.tilia-inc.com/v2/invoice/{cancel_invoice_id}