Get Sandbox Access

Paybase Developer Centre

OverviewAPI GuidesGetting StartedRecipesGig Economy PlatformsSharing Economy PlatformsMarketplacesBlockchain BusinessesEscrowSandboxRolesRulesDue DiligenceCustomersAccountsBank AccountsCardsTransactionsIntroductionInboundGetting money into the systemTransaction ReferenceAccount ReferenceInternalOutboundEscrowSplit PaymentsRefundsStrong Customer Authentication3D Secure AuthenticationIntroductionCreate a cardCreate a transactionDocument UploadStatementsWebhooksErrorsPQLAPI ReferenceAccountCreate an accountRetrieve an accountTransition account statusList all accountsAnnotate an accountDelete annotation from an accountTag an accountDelete tag from an accountBank AccountCreate a bank accountRetrieve a bank accountUpdate a bank accountTransition bank account statusList all bank accountsAnnotate a bank accountDelete annotation from a bank accountTag a bank accountDelete tag from a bank accountCardCreate a cardRetrieve a cardUpdate a cardTransition card statusList all cardsAnnotate a cardDelete annotation from a cardTag a cardDelete tag from a cardCardholderCreate a cardholderRetrieve a cardholderUpdate a cardholderTransition cardholder statusList all cardholdersAnnotate a cardholderDelete annotation from a cardholderTag a cardholderDelete tag from a cardholderCreate an authentication tokenCheckCreate a checkCustomerIndividual CustomerCreate a customerRetrieve a customerUpdate a customerSole TraderCreate a customerRetrieve a customerUpdate a customerOrganisationCreate a CustomerRetrieve a CustomerUpdate a CustomerIncorporated BusinessCreate a customerRetrieve a customerUpdate a customerBusiness PersonAdd a business personRetrieve a business personUpdate a business personDelete a business personRetrieve a customerTransition state of a customerList all customersAnnotate a customerDelete annotation from a customerTag a customerRemove tag from a customerCreate an authentication tokenTouch a customerDocumentCreate a documentRetrieve a documentList Document TypesReferenceRetrieve a referenceStatementRetrieve a statementStatusRetrieve API statusTransactionCreate inbound transactionCreate internal transactionCreate outbound transactionRetrieve a transactionTransition transaction statusList all transactionsAnnotate a transactionDelete annotation from a transactionTag a transactionDelete tag from a transaction
API version: a0406ac

Escrow

Please note, use of this functionality must be discussed with Paybase prior to implementation. We will need to give you the necessary permissions for it to function properly.

The Paybase platform enables you to offer 'conditional payments' functionality to your customers. We do this by holding the funds on the system temporarily, and only fully crediting the funds upon a separate API call.

Why use Escrow-like transactions ?

Use this flow if you want to separate fulfilling a transaction from initiating it, and if your standard use case involves regularly affecting the final settlement amount.

Some use cases for escrow include:

  • Marketplaces
    • only release funds to the seller once the recipient has confirmed the delivery.
  • Food delivery
    • only take payments once delivery is confirmed, with out-of-the-box flows to refund a certain portion of the price depending on different scenarios (i.e. food was late or items were missing).
  • Venue hire
    • ensure payment is initiated when the booking is made, easily retaining a percentage fee if the user cancels late in the day.

How does it work?

The escrow-like functionality centres around two specific parts of the transaction flow: the HELD state, and the adjustment option on the API.

Transactions that target the HELD state at creation may only be transitioned out of that state by either

  • a) fully effecting that transaction by transitioning it to EFFECTED
  • b) partially refunding the transaction by transitioning it to ADJUSTED, and providing an adjustment with adjustment amount.

How can it be implemented ?

There are two main ways to use this type of functionality on our system.

The first, which we call Escrow-lite, takes card transactions directly into the recipients Paybase account. The second, which we call Direct Escrow, involves first topping up the buyer's eMoney account on the Paybase platform, and then creating the transfer to the seller's eMoney account.

Escrow-lite

Let's run through a standard Escrow-lite flow:

First, we'll create our seller and buyer - and set up our buyer with a card, and our seller with an eMoney account to pay into.

Creating Individuals Creating Cards Creating Accounts

Now we've got everything we need to handle the transaction, we'll create our purchase inbound card transaction direct to the sellers account, targetting the HELD state. We'll need the customerId and cardId of the buyer and the accountId of the seller. We'll make a call to createInboundTransaction as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.createInboundTransaction({
  accountId: "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
  paymentInstrumentId: "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  amount: "500",
  method: "card",
  purpose: "PURCHASE",
  targetStateId: "HELD",
  options: {
    card: {
      cvv: "123"
    }
  }
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import json
import requests

requests.post(
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  data = json.dumps({
    "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
    "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
    "amount": "500",
    "method": "card",
    "purpose": "PURCHASE",
    "targetStateId": "HELD",
    "options": {
      "card": {
        "cvv": "123"
      }
    }
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$client = new \GuzzleHttp\Client();
$client->request(
  "post",
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  [
    "body" => "{
      \"accountId\": \"account/b98774fc-3c41-43bc-bd03-13e327dcfbbb\",
      \"paymentInstrumentId\": \"card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e\",
      \"amount\": \"500\",
      \"method\": \"card\",
      \"purpose\": \"PURCHASE\",
      \"targetStateId\": \"HELD\",
      \"options\": {
        \"card\": {
          \"cvv\": \"123\"
        }
      }
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
curl -X POST \
"https://api-json.sandbox.paybase.io/v1/txs/inbound"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
    "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
    "amount": "500",
    "method": "card",
    "purpose": "PURCHASE",
    "targetStateId": "HELD",
    "options": {
      "card": {
        "cvv": "123"
      }
    }
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:38:53.021Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "HELD",
  "createdAt": "2019-02-25T17:38:53.021Z",
  "updatedAt": "2019-02-25T17:38:53.021Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  "purpose": "PURCHASE",
  "flow": "INBOUND",
  "method": "card"
}

This has successfully charged the buyer's card, but not yet fully credited to the seller's bank Account.

If we want to fully credit the funds, we'll transition the transaction to EFFECTED as below:

1
2
3
4
5
6
7
8
9
10
11
12
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.transitionTransaction({
  id: "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  toStateId: "EFFECTED"
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
import requests

requests.patch(
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  data = json.dumps({
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "EFFECTED"
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$client = new \GuzzleHttp\Client();
$client->request(
  "patch",
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  [
    "body" => "{
      \"id\": \"tx/a6af0aa7-2749-4715-b652-27c49b923421\",
      \"toStateId\": \"EFFECTED\"
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
curl -X PATCH \
"https://api-json.sandbox.paybase.io/v1/tx/state"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "EFFECTED"
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:38:53.021Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "EFFECTED",
  "createdAt": "2019-02-25T17:38:53.021Z",
  "updatedAt": "2019-02-26T12:42:14.052Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  "purpose": "PURCHASE",
  "flow": "INBOUND",
  "method": "card"
}

If there was a problem however, we'll transition the transaction to ADJUSTED, providing an amount to refund a certain portion of the transaction. (In this scenario £1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.transitionTransaction({
  id: "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  toStateId: "ADJUSTED",
  options: {
    adjustment: {
      adjustmentAmount: "100"
    }
  }
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import requests

requests.patch(
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  data = json.dumps({
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "ADJUSTED",
    "options": {
      "adjustment": {
        "adjustmentAmount": "100"
      }
    }
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$client = new \GuzzleHttp\Client();
$client->request(
  "patch",
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  [
    "body" => "{
      \"id\": \"tx/a6af0aa7-2749-4715-b652-27c49b923421\",
      \"toStateId\": \"ADJUSTED\",
      \"options\": {
        \"adjustment\": {
          \"adjustmentAmount\": \"100\"
        }
      }
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
9
10
11
12
13
curl -X PATCH \
"https://api-json.sandbox.paybase.io/v1/tx/state"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "ADJUSTED",
    "options": {
      "adjustment": {
        "adjustmentAmount": "100"
      }
    }
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:38:53.021Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-26T12:42:14.052Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "-100",
      "type": "REFUND",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "ADJUSTED",
  "createdAt": "2019-02-25T17:38:53.021Z",
  "updatedAt": "2019-02-26T12:42:14.052Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  "purpose": "PURCHASE",
  "flow": "INBOUND",
  "method": "card"
}

The transition added a negative adjustment of £1, which will have been refunded directly to the buyer's card.

Key points for this flow:

  • Funds always flow directly from the buyer's card to the seller's emoney account.
  • Any refunded funds will be sent directly back to the buyer's card.
  • Lessened requirements on CDD for the buyer.

Direct Escrow

The Direct Escrow flow is very similar to the above flow, except the HELD transaction is instead a transaction between two Paybase Accounts.

As above, we'll first start by creating our buyer and seller customer records, and give an account to the seller and a card to the buyer. Additionally in this flow, the buyer requires an eMoney account.

Creating Individuals Creating Cards Creating Accounts

Now we've got everything we need to handle the transaction, we'll create our deposit inbound card transaction into the buyer's account.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.createInboundTransaction({
  accountId: "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
  paymentInstrumentId: "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  amount: "500",
  method: "card",
  purpose: "PURCHASE",
  targetStateId: "EFFECTED",
  options: {
    card: {
      cvv: "123"
    }
  }
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import json
import requests

requests.post(
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  data = json.dumps({
    "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
    "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
    "amount": "500",
    "method": "card",
    "purpose": "PURCHASE",
    "targetStateId": "EFFECTED",
    "options": {
      "card": {
        "cvv": "123"
      }
    }
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$client = new \GuzzleHttp\Client();
$client->request(
  "post",
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  [
    "body" => "{
      \"accountId\": \"account/09302e2a-4100-457a-9919-a6b9d4d34d04\",
      \"paymentInstrumentId\": \"card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e\",
      \"amount\": \"500\",
      \"method\": \"card\",
      \"purpose\": \"PURCHASE\",
      \"targetStateId\": \"EFFECTED\",
      \"options\": {
        \"card\": {
          \"cvv\": \"123\"
        }
      }
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
curl -X POST \
"https://api-json.sandbox.paybase.io/v1/txs/inbound"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
    "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
    "amount": "500",
    "method": "card",
    "purpose": "PURCHASE",
    "targetStateId": "EFFECTED",
    "options": {
      "card": {
        "cvv": "123"
      }
    }
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:38:53.021Z",
      "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "EFFECTED",
  "createdAt": "2019-02-25T17:38:53.021Z",
  "updatedAt": "2019-02-25T17:38:53.021Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  "purpose": "DEPOSIT",
  "flow": "INBOUND",
  "method": "card"
}

The buyer now has the balance in their Paybase eMoney account to create the A2a transfer, targetting HELD so that the funds won't be fully creditted till later.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.createInboundTransaction({
  fromAccountId: "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
  toAccountId: "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
  amount: "500",
  method: "transfer",
  purpose: "PURCHASE",
  targetStateId: "HELD"
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json
import requests

requests.post(
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  data = json.dumps({
    "fromAccountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
    "toAccountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
    "amount": "500",
    "method": "transfer",
    "purpose": "PURCHASE",
    "targetStateId": "HELD"
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$client = new \GuzzleHttp\Client();
$client->request(
  "post",
  "https://api-json.sandbox.paybase.io/v1/txs/inbound",
  [
    "body" => "{
      \"fromAccountId\": \"account/09302e2a-4100-457a-9919-a6b9d4d34d04\",
      \"toAccountId\": \"account/b98774fc-3c41-43bc-bd03-13e327dcfbbb\",
      \"amount\": \"500\",
      \"method\": \"transfer\",
      \"purpose\": \"PURCHASE\",
      \"targetStateId\": \"HELD\"
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
9
10
11
12
curl -X POST \
"https://api-json.sandbox.paybase.io/v1/txs/inbound"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "fromAccountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
    "toAccountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
    "amount": "500",
    "method": "transfer",
    "purpose": "PURCHASE",
    "targetStateId": "HELD"
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
      "amount": "-500",
      "type": "INTENT",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "HELD",
  "createdAt": "2019-02-25T17:40:48.031Z",
  "updatedAt": "2019-02-25T17:40:48.031Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "purpose": "PURCHASE",
  "flow": "INTERNAL",
  "method": "transfer"
}

If we want to fully credit the funds, we'll transition the transaction to EFFECTED as below:

1
2
3
4
5
6
7
8
9
10
11
12
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.transitionTransaction({
  id: "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  toStateId: "EFFECTED"
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
import requests

requests.patch(
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  data = json.dumps({
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "EFFECTED"
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$client = new \GuzzleHttp\Client();
$client->request(
  "patch",
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  [
    "body" => "{
      \"id\": \"tx/a6af0aa7-2749-4715-b652-27c49b923421\",
      \"toStateId\": \"EFFECTED\"
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
curl -X PATCH \
"https://api-json.sandbox.paybase.io/v1/tx/state"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "EFFECTED"
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
      "amount": "-500",
      "type": "INTENT",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "EFFECTED",
  "createdAt": "2019-02-25T17:40:48.031Z",
  "updatedAt": "2019-02-26T12:42:14.052Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "purpose": "PURCHASE",
  "flow": "INTERNAL",
  "method": "transfer"
}

If there was a problem however, we'll transition the transaction to ADJUSTED, providing an adjustment to refund a certain portion of the transaction. (In this scenario £1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { v1 } from '@paybase/client';

const client = v1('<- API Key ->', { sandbox: true });

const { accessToken } = await client.createCustomerAuthenticationToken({
  id: "<- Sending Customer ID ->"
});

const result = await client.transitionTransaction({
  id: "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  toStateId: "ADJUSTED",
  options: {
    adjustment: {
      adjustmentAmount: "100"
    }
  }
}, { apiKey: accessToken });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import requests

requests.patch(
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  data = json.dumps({
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "ADJUSTED",
    "options": {
      "adjustment": {
        "adjustmentAmount": "100"
      }
    }
  }),
  headers = {
    "Content-Type": "application/json",
    "X-Token": "<X-Token goes here>"
  }
).json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$client = new \GuzzleHttp\Client();
$client->request(
  "patch",
  "https://api-json.sandbox.paybase.io/v1/tx/state",
  [
    "body" => "{
      \"id\": \"tx/a6af0aa7-2749-4715-b652-27c49b923421\",
      \"toStateId\": \"ADJUSTED\",
      \"options\": {
        \"adjustment\": {
          \"adjustmentAmount\": \"100\"
        }
      }
    }",
    "headers" => [
      "Content-Type" => "application/json",
      "X-Token" => "<X-Token goes here>",
    ]
  ]
);

1
2
3
4
5
6
7
8
9
10
11
12
13
curl -X PATCH \
"https://api-json.sandbox.paybase.io/v1/tx/state"  -H "Content-Type: application/json" \
  -H "X-Token: <X-Token goes here>" \
  -d '{
    "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
    "toStateId": "ADJUSTED",
    "options": {
      "adjustment": {
        "adjustmentAmount": "100"
      }
    }
  }'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "adjustments": [
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "500",
      "type": "INTENT",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-25T17:40:48.031Z",
      "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
      "amount": "-500",
      "type": "INTENT",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-26T12:42:14.052Z",
      "accountId": "account/b98774fc-3c41-43bc-bd03-13e327dcfbbb",
      "amount": "-100",
      "type": "REFUND",
      "rate": "1.00000000"
    },
    {
      "createdAt": "2019-02-26T12:42:14.052Z",
      "accountId": "account/09302e2a-4100-457a-9919-a6b9d4d34d04",
      "amount": "100",
      "type": "REFUND",
      "rate": "1.00000000"
    }
  ],
  "tags": [],
  "annotations": {},
  "id": "tx/a6af0aa7-2749-4715-b652-27c49b923421",
  "stateId": "ADJUSTED",
  "createdAt": "2019-02-25T17:40:48.031Z",
  "updatedAt": "2019-02-26T12:42:14.052Z",
  "fromOwnerId": "customer/5b6a1e90-b801-46f5-a3b5-074b6c773333",
  "toOwnerId": "customer/28958679-e8a8-47a8-967c-f979ae8509a2",
  "paymentInstrumentId": "card/c9c2c3d9-d90d-4ea4-b3b4-d3e1454c5d9e",
  "purpose": "PURCHASE",
  "flow": "INBOUND",
  "method": "card"
}

Key points for this flow:

  • Funds are first deposited into the buyer's own eMoney account, before then being transferred to the seller's eMoney account separately as an account-to-account transfer.
  • Any refunded funds will be sent to the buyer's eMoney account, which will be immediately available for further transactions or withdrawals.
  • Greater CDD requirements for the buyer due to holding funds for them.