GoCardlessDeveloper Docs
Create a sandbox account

Reconciling Payouts#

View as Markdown

In this step of the GoCardless Embed guide you will use GoCardless' webhooks and API to reconcile your payouts.

GoCardless will pay out payments to the payout bank account you added earlier in this guide. When this happens, a "payout" record will be created which represents the transfer of funds.

We will generally send a single payout each day for each currency you collect in. However, we may split the funds into multiple payouts if there are a very large number of payments to pay out.

When a payout is sent, you will receive a webhook with resource_type "payouts" and action "paid". In addition, for each payment that has been paid out, we will send webhooks with resource_type "payments" and action "paid_out". The links[payout] attribute of that webhook will include the ID of the payout the payment appears in.

For more detailed reconciliation, the best way to understand what's inside a payout is to use the Payout Items API.

Using the Payout Items API#

The Payout Items API lets you see the individual transactions that made up the total amount of a payout.

You can think of a payout in terms of credits and debits. When we collect payments and add the money collected to their GoCardless balance - that's a credit. But there can also be debits against that balance - for example deductions for chargebacks.

When we make a payout, we bundle up all of the outstanding credits and debits into it and reset the creditor's balance to zero.

For each item in a payout, we expose:

  • an amount (which will be positive for credit, or negative for a debit) and will be in the currency the payment was taken in.
  • a type (which explains the reason for the credit or debit) and links to any relevant resources (usually a payment, links.payment).

The types of payout items in the GoCardless Embed product are:

TypeDescriptionCredit or debitLinks
Payment paid out (payment_paid_out)A payment was successfully collected from a payer and is being passed on to your payout account.Creditlinks.payment
Payment failed (payment_failed)A payment appeared to have been collected from a payer successfully, but then the bank told us that it had in fact failed, so it is being deductedDebitlinks.payment
Payment charged back (payment_charged_back)A payment was successfully collected from a payer, but then the payer contacted their bank to reverse the transaction, so it is being deductedDebitlinks.payment
Payment refunded (payment_refunded)A payment was successfully collected from a payer, and then partially or fully refunded at your request, so the refunded amount is being deductedDebitlinks.payment, links.mandate
Payer refunded (refund)A refund was sent to a payer, not related to any particular payment, so the refunded amount is being deducted.Debitlinks.mandate
Refund funds returned (refund_funds_returned)A refund made at your request, and previously deducted from a payout failed to reach the payer, so the refunded amount is being credited.Creditlinks.payment, links.mandate

To see how these can fit together in the real world, let's imagine a payout as an example:

DescriptionTypeAmount
Payment successfully collected from Nickpayment_paid_out+€20.00
Refund issued for Andrew's payment, collected last weekpayment_refunded-€5.00
Bianca's payment from last week, which was charged backpayment_charged_back-€10.00
Total****+€5.00

With the Payout Items API, you can look inside a payout and see the transactions that make it up, allowing you to explain transactions on the payer's bank statement.

When you receive a "payout paid" webhook (resource_type "payouts" and action "paid"), you can then query the Payout Items API:

require 'vendor/autoload.php';

function processPayoutEvent($event) {
$client = new \GoCardlessPro\Client([
'access_token' => $_ENV["GOCARDLESS_ACCESS_TOKEN"],
'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$payoutId = $event->links['payout'];

$payout = $client->payouts()->get($payoutId);
echo $payout->amount;

$payoutItems = $client
->payoutItems()
->all(["params" => ["payout" => $payoutId]]);

foreach ($payoutItems as $payoutItem) {
echo $payoutItem->amount;
echo $payoutItem->type;
echo $payoutItem->links->payment;
}
}
import os
import gocardless_pro

def process_payout_event(event):
client = gocardless_pro.Client(
access_token=os.environ['GOCARDLESS_ACCESS_TOKEN'],
environment='sandbox'
)

payout_id = event['links']['payout']
payout = client.payouts.get(payout_id)
print(payout.amount)

payout_items = client.payout_items.all(params={ "payout": payout_id }).records

for payout_item in payout_items:
print(payout_item.amount)
print(payout_item.type)
print(payout_item.links.payment)
require 'gocardless_pro'

def process_payout_event(event)
client = GoCardlessPro::Client.new(
access_token: ENV['GOCARDLESS_ACCESS_TOKEN'],
environment: :sandbox
)

payout_id = event.links.payout
payout = @client.payouts.find(payout_id)
puts payout.amount

payout_items = client.payout_items.all(params: { payout: payout_id })

payout_items.each do |payout_item|
puts payout_item.amount
puts payout_item.type
puts payout_item.links.payment
end
end
import com.gocardless.GoCardlessClient;
import com.gocardless.resources.Event;
import com.gocardless.resources.Payout;
import com.gocardless.resources.PayoutItem;

public class PayoutsWebhookHandler {
public static void handlePayoutPaidEvent(Event event) {
GoCardlessClient client = GoCardlessClient
.newBuilder(System.getenv("GOCARDLESS_ACCESS_TOKEN"))
.withEnvironment(GoCardlessClient.Environment.SANDBOX)
.build();

      String payoutId = event.getLinks().getPayout();
      Payout payout = client.payouts().get(payoutId).execute();

      for (PayoutItem payoutItem : client.payoutItems().all().withPayout(payoutId).execute()) {
          System.out.println(payoutItem.getAmount());
          System.out.println(payoutItem.getType());
          System.out.println(payoutItem.getLinks().getPayment());
      }
  }

}
const gocardless = require("gocardless-nodejs");

const client = gocardless(process.env.GoCardlessAccessToken, constants.Environments.Sandbox);

async function processPayoutEvent(event) {
const payoutId = event.links.payout;
const payout = await client.payouts.find(payoutId);
console.log(payout.id);

const payoutItems = client.payoutItems.all({ payout: payoutId });

for await (let payoutItem of payoutItems) {
console.log(payoutItem.amount);
console.log(payoutItem.type);
console.log(payoutItem.links.payment);
}
}
using GoCardless;

public void HandlePayoutPaidEvent(GoCardless.Resources.Event event)
{
var client = GoCardlessClient.Create(
ConfigurationManager.AppSettings["GoCardlessAccessToken"],
GoCardlessClient.Environment.SANDBOX
);

  var payoutId = event.Links.Payout;
  var payoutResponse = await client.Payouts.GetAsync(payoutId);
  var payout = paymentResponse.Payout;
  Console.WriteLine(payout.Id);

  var payoutItemsRequest = new GoCardless.Services.PayoutItemListRequest()
  {
      Payout = payoutId
  };

  var payoutItems = client.PayoutItems.All(payoutItemsRequest);

  foreach (GoCardless.Resources.PayoutItem payoutItem in payoutItems)
  {
      Console.WriteLine(payoutItem.Amount);
      Console.WriteLine(payoutItem.Type);
      Console.WriteLine(payoutItem.Links.Payment);
  }

}
package main

import (
"context"
"fmt"
"http"

  gocardless "github.com/gocardless/gocardless-pro-go/v6"

)

func main() {
accessToken := "your_access_token_here"
config, err := gocardless.NewConfig(accessToken, gocardless.WithEndpoint(gocardless.SandboxEndpoint))
if err != nil {
fmt.Printf("got err in initialising config: %s", err.Error())
return
}
client, err := gocardless.New(config)
if err != nil {
fmt.Println("error in initialisating client: %s", err.Error())
return
}

  parseEvent := func(event gocardless.Event) {
  	payoutId := event.Links.Payout
  	ctx := context.TODO()

  	payoutListParams := gocardless.PayoutItemListParams{
  		Payout: payoutId,
  	}
  	payoutItems, err := client.PayoutItems().All(ctx, payoutListParams)

  	for _, payoutItem := range payoutItems {
  		fmt.Println(payoutItem.Amount)
  		fmt.Println(payoutItem.Type)
  		fmt.Println(payoutItem.Links.Payment)
  	}
  }

  http.HandleFunc("/webhookEndpoint", func(w http.ResponseWriter, r *http.Request) {
  	wh, err := gocardless.NewWebhookHandler("secret", gocardless.EventHandlerFunc(func(event gocardless.Event) error {
  		parseEvent(event)
  	}))
  	wh.ServeHTTP(w, r)
  })

}

For full details on the Payout Items API, head over to our reference documentation.

What's next?#

Your integration is complete. Please contact us to help you take your integration live.