Amend outbound instructions

When an exchange cannot deliver a payment due to incorrect or missing beneficiary_info details, On-Demand Liquidity allows you to amend the outbound_instructions object using the RippleNet Add payment sub state operation.

The reasons for a non-deliverable payment may be due to a missing field required by the payout outlet for KYC or compliance checks, a misspelled beneficiary's first or last name, or an address that doesn't match the address on the ID of the beneficiary picking up the payment.

The following diagram shows the flow for situations where an exchange cannot deliver a payment, and how On-Demand Liquidity handles the payment. On-Demand Liquidity provides functionality for a sender to amend the outbound_instructions for a payment.

Amend Outbound Instructions Flow

Labels for outbound instructions

The following labels are used by On-Demand Liquidity as a RECEIVING node to inform the SENDING node that a payment cannot be delivered by a payout outlet.

Depending on the label added to the RippleNet Payment Object (RPO), you can either amend the outbound_instructions for the payment and try to complete the payment, or you can recover the funds manually from the destination exchange.

Label Description
OUTBOUND_TRANSFER_FAILED_RECOVERABLY Payments with this label are in an EXECUTED payment state. When present, the SENDING node can update the outbound_instructions object with the "Add Payment Sub-State" operation, adding an AMEND sub-state to the payment. The exchange will reattempt a payout to the beneficiary. If the amended outbound_instructions result in a successful payout to the beneficiary, On-Demand Liquidity transitions the payment state to COMPLETED.
OUTBOUND_TRANSFER_FAILED_IRRECOVERABLY When set, the exchange could not make the payment to the beneficiary, and transitioned the payment to a FAILED payment state. On-Demand Liquidity adds this label when the number of AMEND retries has been exhausted. In this case, the SENDING node must recover the funds manually from the destination exchange.

Amend a payment's outbound instructions

To amend outbound instructions, configure your middleware as follows:

  1. Check for payments that require corrections to the outbound_instructions using the Get Payments operation. Pass in query parameters to return payments with an OUTBOUND_TRANSFER_FAILED_RECOVERABLY label. Make a note of any RippleNet payment_id s that match the query.

    Example: GET https://{{target.example_url_string}}/v4/payments?with_labels=OUTBOUND_TRANSFER_FAILED_RECOVERABLY

    Note:

    You should also check for payments that failed and the exchange has determined the issue cannot be fixed by amending the outbound_instructions. Use the "Get Payments" operation, passing in query parameters to return payments with an OUTBOUND_TRANSFER_FAILED_IRRECOVERABLY label.


    Here's an example of a payment with the label `OUTBOUND_TRANSFER_FAILED_RECOVERABLY` set by On-Demand Liquidity:

    Get payments (HTTP request)

    Copy
    Copied!
    GET /v4/payments?with_labels=OUTBOUND_TRANSFER_FAILED_RECOVERABLY HTTP/1.1
    Host: https://{{target.example_url_string}}
    Content-Type: application/json
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

    Get Payments (cURL request)

    Copy
    Copied!
    curl -X GET  \
    -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'  \
    -H 'Content-Type: application/json'
    https://{{target.example_url_string}}/v4/payments?with_labels=OUTBOUND_TRANSFER_FAILED_RECOVERABLY

    Response (success)
    Response has been shortened to show pertinent information.

    Copy
    Copied!
    {
    "payment_id": "98d08b9e-4885-48e4-9e09-8f457859e142",
    "contract_hash": "abc65fad5e00aac237a44f22e7919046bc2ac2df3b955",
    "payment_state": "EXECUTED",
    "internal_info": {
        "internal_id": "6b0a4263-f9b9-48f3-910d-005b6873cb5e",
        "connector_role": "RECEIVING",
        "labels": [
        {
            "label": "OUTBOUND_TRANSFER_FAILED_RECOVERABLY"
        }
        ]
    },
    "modified_at": "2020-01-08T00:58:49.129Z",
    ...

  2. Make a call to the "Add Payment Sub-State" operation. Provide the corrected outbound_instructions object and add an AMEND sub-state in the request. This call updates beneficiary information for the exchange to reattempt making the payout. You can provide a memo in the request body of your API call.

    Note:

    You must include the complete outbound_instructions object in your request body for this call.


    Add payment sub-state (HTTP request)

    Copy
    Copied!
    POST /v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142/sub_state HTTP/1.1
    Host: https://{{target.example_url_string}}
    Content-Type: application/json
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    
    {
        "sub_state": "AMEND",
        "memo": "updates recipient given names value",
        "info": {
        "outbound_instructions": {
            "outlet_id": "spei",
            "beneficiary_info":
            [
            {
                "field_name": "recipient_family_names",
                "field_value": "Minuarez"
            },
            {
                "field_name": "recipient_given_names",
                "field_value": "Jorge"
            },
            {
                "field_name": "clabe",
                "field_value": "014027000005555558"
            }
            ]
        }
        }
    }

    Add payment sub-state (cURL request)

    Copy
    Copied!
    curl -X POST  \
    -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'  \
    -H 'Content-Type: application/json'  \
    https://{{target.example_url_string}}/v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142/sub_state
    -d '{
        "sub_state": "AMEND",
        "memo": "updates recipient given names value",
        "info": {
        "outbound_instructions": {
            "outlet_id": "spei",
            "beneficiary_info":
            [
            {
                "field_name": "recipient_family_names",
                "field_value": "Minuarez"
            },
            {
                "field_name": "recipient_given_names",
                "field_value": "Jorge"
            },
            {
                "field_name": "clabe",
                "field_value": "014027000005555558"
            }
            ]
        }
        }
    }

  3. Use the Delete payment labels operation to delete the OUTBOUND_TRANSFER_FAILED_RECOVERABLY label from the RippleNet payment you just amended. It's good practice to remove the label to ensure the amended payment won't appear in a subsequent search for payments that require amendments. On-Demand Liquidity may add this label again if there's still an issue delivering this payment, and you haven't reached the retry limit.

    Format: DELETE {ripplenet_base_url}/v4/payments/{payment_id}/labels?label={label_name}

    Delete payment label (HTTP request)
    Copy
    Copied!
    DELETE /v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142/labels?label=OUTBOUND_TRANSFER_FAILED_RECOVERABLY HTTP/1.1
    Host: https://{{target.example_url_string}}
    Content-Type: application/json
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

    Delete payment label (cURL Request)

    Copy
    Copied!
    curl -X DELETE  \
    -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'  \
    -H 'Content-Type: application/json'  \
    https://{{target.example_url_string}}/v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142/labels?label=OUTBOUND_TRANSFER_FAILED_RECOVERABLY

  4. If the update to the outbound_instructions object in your RippleNet Payment Object results in a successful payout to the beneficiary, On-Demand Liquidity transitions the payment to COMPLETED . Check the status of the payment by calling the Get payment by payment ID operation using the payment_id .

    Get payment by ID (HTTP request)

    Copy
    Copied!
    GET {{target.example_url_string}}/v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142 HTTP/1.1
    Host: https://{{target.example_url_string}}
    Content-Type: application/json
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

    Get payment by ID (cURL request)

    Copy
    Copied!
    curl -X GET  \
    -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'  \
    -H 'Content-Type: application/json'  \
    https://{{target.example_url_string}}/v4/payments/98d08b9e-4885-48e4-9e09-8f457859e142

    • If the RippleNet Payment Object contains OUTBOUND_TRANSFER_FAILED_RECOVERABLY label, retry.
      If the payout attempt is unsuccessful and you can still amend the outbound instructions, On-Demand Liquidity adds an OUTBOUND_TRANSFER_FAILED_RECOVERABLY label to the RippleNet payment object and the payment remains in the EXECUTED state. Repeat steps one through four until successful or until you have reached the retry limit.
      Copy
      Copied!
      {
          "payment_id": "98d08b9e-4885-48e4-9e09-8f457859e142",
          "contract_hash": "abc65fad5e00aac237a44f22e7919046bc2ac2df3b955",
          "payment_state": "EXECUTED",
          "internal_info": {
          "internal_id": "6b0a4263-f9b9-48f3-910d-005b6873cb5e",
          "connector_role": "RECEIVING",
          "labels": [
              {
                  "label": "AMEND"
              },
              {
                  "label": "OUTBOUND_TRANSFER_FAILED_RECOVERABLY"
              }
              ]
          },
          "modified_at": "2020-01-08T00:59:23.129Z",
          ...

    • If the RippleNet Payment Object contains OUTBOUND_TRANSFER_FAILED_IRRECOVERABLY label, recover funds.
      If the payment is not successful, you have reached the amend retry limit, and the exchange determines the payment cannot be made to the beneficiary, On-Demand Liquidity adds an OUTBOUND_TRANSFER_FAILED_IRRECOVERABLY label to the payment object, and transitions the payment state to FAILED . Manually recover the funds from the destination exchange, in this case.
      Copy
      Copied!
      {
          "payment_id": "98d08b9e-4885-48e4-9e09-8f457859e142",
          "contract_hash": "abc65fad5e00aac237a44f22e7919046bc2ac2df3b955",
          "payment_state": "FAILED",
          "internal_info": {
          "internal_id": "6b0a4263-f9b9-48f3-910d-005b6873cb5e",
          "connector_role": "RECEIVING",
          "labels": [
              {
                  "label": "OUTBOUND_TRANSFER_FAILED_IRRECOVERABLY"
              },
              {
                  "label": "AMEND"
              }
              ]
          },
          "modified_at": "2020-01-08T00:59:23.129Z",
          ...