Remittance Advice
12 minute read
What you’ll learn
- Key concepts and terms
- Key object relationships
- How to work with GraphQL and Webhooks
- Further financial information available
Important
If you are an existing Marketplacer customer, Remittance Advices may not be turned on, you can enable this setting through the Marketplacer Operator Portal.Key Terms
Before launching in to the the use of the API and Webhooks related to remittance advices, it’s worth covering some of the key concepts we’ll be working with:
Term | Description |
---|---|
Operator | The business entity that runs the marketplace and is the merchant of record for the transactions that occur on the marketplace. The GraphQL features described in this article can only be employed by Operators. |
Seller | Business entity that places products for sale on the marketplace. A Seller is responsible for fulfilling Invoices on an Order, a Seller can only have 1 Invoice per Order. The seller will be remitted (paid) by the Operator when they fulfil their invoices. |
Order | An Order is the “marketplace-level” object that acts as the container for a customer’s entire purchase. An Order object in Marketplacer will always have at least 1 Invoice attached to it, (1 invoice per seller) |
Invoice | An Invoice is the part of the overall customer order that an individual Seller has to fulfil. An Order will always have at least 1 Invoice (1 per Seller participating in the Order) |
Invoice Amendment | Following the completion of an Order (and therefore the creation of Invoices) there may be reasons why those individual Invoices need to be amended, (for example when a customer requires a refund). In such cases an Invoice will have associated Invoice Amendments. An Invoice can have 0 or more Invoice Amendments. |
Remittance | Remittance is both a Marketplacer workflow and a GraphQL object type. From a workflow perspective it is used to ensure that Invoices have been adequately fulfilled, and that Sellers should then be paid (remitted). |
Remittance Advice | Remittance Advices group multiple Remittances together under 1 “advice”. Prior to this feature you had to rely solely on the relationship between a Remittance and an Invoice / Invoice Amendment (a Remittance can only relate to 1 Invoice or Invoice Amendment) which made things like reporting problematic. With the release of Remittance Advices, it is now easy to see the relationships between multiple Remittances and the Invoice (and Invoice Amendments) that they are related to. |
Remittance Action | This is a GraphQL object type that models the payout actions to occur, e.g. the use of Hyperwallet to pay a Seller. |
Remittance Event | This is a GraphQL object type that models the events on an Remittance Action. e.g. did the action to pay a seller via Xero succeed or fail? |
Payment Release | Payment Release is a step in the remittance workflow that is undertaken by the Operator. This step is in place to ensure that Operators are only paying their Sellers when they are happy that the Seller’s Invoice has been fulfilled. This step can be performed in the Operator portal or using the remittancesRelease mutation |
Object Relationships
To help contextualize some of the concepts outlined above, please refer to the relationship diagram below, (note you can fully explore the Marketplacer GraphQL schema yourself here):
Remittance Workflow
The workflow below represents a “happy path” through the remittance flow, with specific call outs to the various APIs (numbered) that can be used to automate.
From the above flow it’s worth further clarifying 2 key stages:
- Remittance Object creation
- Remittance Advice creation
Remittance Object Creation
Invoices
A remittance
object will be created for an invoice when:
- An Invoice has no outstanding line items
- An invoice has at least one dispatched line item
The remittance
object contains the calculated remittance and commission amounts for the entire invoice based on the configuration in Marketplacer
Invoice Amendments
The completion of the cancellation or refund process results in an invoiceAmendment
object, the following conditions must be met for a remittance object to be created for an invoice amendment:
- Invoice amendment parent invoice have been remitted
Once again referring to the object relationships (above), we can say a remittance
object can be associated to single:
invoice
invoiceAmendment
Remittance Advice Creation
The daily remittance batch process runs every night to create remittance advices. One remittance advice is created per Seller and contains all the remittance
objects (see section above) identified as remittable. The following conditions must be met for a remittance advice object to be created:
- Invoice remittance delay has passed
- Invoice payment has been released
- Seller has remittance account details populated
seller.missingRemittanceDetails
=false
- If using Hyperwallet, Hyperwallet details are populated:
seller.missingHyperwalletDetails
=false
- If using Xero, Xero details are populated:
seller.missingXeroDetails
=false
Daily Remittance Cycle Failures
If there are any issues related to the processing of Invoices as part of the daily remittance cycle, then it is up to the Operator to resolve these issues. In order to understand what those issues may be you can:
- Use the Operator Portal to look at the Remittances Report and review the Unprocessed Remittances.
- Use the GraphQL
remittances
query to interrogate the `pendingReasons`` field
GraphQL Examples
Stepping through the above workflow, we’ll cover off the queries and mutations you can use at each step that are directly related to remittances and remittance advices. Note that all of these examples can be found in the Insomnia and Postman collections.
Entry Criteria
The examples that follow require that the following conditions have been met before hand:
- An order has been created
- For more information on creating orders with GraphQL, please refer to this article
- The Seller has received that order (as Invoice)
- The Seller has dispatched all the line items on the invoice
1. Release Payment
This step can be performed by the Operator using the Operator portal, or it can be achieved via API. If you want to use the API, the first thing to do would be to query for all unreleased remittances, you can do this using the remittances
query to search for unreleased remittances as shown below:
query {
remittances(
released: false,
createdSince: "2023-04-10")
{
nodes {
amountCents
id
pendingReasons
released
createdAt
invoice {
id
legacyId
totalCents
remittedAt
}
}
}
}
This query relies upon the fact that remittance
objects have been created, and are in an unreleased state (released
= false
).
In our example we have 2 unreleased remittances:
{
"data": {
"remittances": {
"nodes": [
{
"amountCents": 3896,
"id": "UmVtaXR0YW5jZS01MDg=",
"pendingReasons": [
"Payments have not been released.",
"The remittance delay has not yet passed."
],
"released": false,
"createdAt": "2023-04-12T11:51:41+10:00",
"invoice": {
"id": "SW52b2ljZS0xMDQxNQ==",
"legacyId": 10415,
"totalCents": 4995,
"remittedAt": null
}
},
{
"amountCents": 3896,
"id": "UmVtaXR0YW5jZS01MDk=",
"pendingReasons": [
"Payments have not been released.",
"The remittance delay has not yet passed."
],
"released": false,
"createdAt": "2023-04-12T11:58:59+10:00",
"invoice": {
"id": "SW52b2ljZS0xMDQxNg==",
"legacyId": 10416,
"totalCents": 4995,
"remittedAt": null
}
}
]
}
}
}
You can see that both remittances have 2 pendingReasons
why they cannot be processed:
- Payments have not been released (we’ll fix that shortly!)
- The remittance delay has not passed
To release the payment for both remittances we can use the remittancesRelease
mutation as follows:
mutation {
remittancesRelease(input:
{
remittanceIds:
[
"UmVtaXR0YW5jZS01MDg="
"UmVtaXR0YW5jZS01MDk="
]}){
remittances {
id
}
}
}
If you re-run the remittances
query we used previously, you will not have these remittances returned (as they have now been released).
2. Querying Pending Reasons
As per the workflow you can query remittances at any time to understand what state they are in and whether there are any pending reasons as to why they have not been processed.
We have already seen an example of this query, so we don’t need to cover it again in too much detail, however it it worth mentioning that it does include a number of filters, including but not limited to:
createdSince
timestampreleased
- we have used this already to bring back unreleased remittancesprocessed
- only return remittances when an Remittance Advice has been generatedretailerIds
- you can supply an array of Retailer (aka Seller) Ids to limit your result setpendingReasons
- you can filter by the possible pending reasons a remittance may have for not being processed
For a full lits list of all the possible filters that can be used, please refer to the inline docs for the remittances
query, you can find these in either:
- Graphql Voyager
- GraphDoc
- Or in your chosen API client, e.g. Insomnia
3. Remittance Advice Webhook
Webhooks can be employed to notify interested parties when Remittance Advices are:
- Created
- Updated
Note: There is no delete webhook as remittances are financial objects and therefore immutable and cannot be deleted.
An example of a webhook query that can be used to shape a Remittance Advice Webhook payload can be found below:
query ($id: ID!) {
node(id: $id) {
... on RemittanceAdvice {
legacyId
attachments {
id
}
createdAt
id
paidAt
paymentReference
remittances {
id
}
seller {
id
}
totalCents
totalFormatted
totalPaidCents
totalPaidFormatted
}
}
}
4. Querying Remittance Advices
A remittanceAdvice
object has the following fields:
Field Name | Description | Defined By |
---|---|---|
attachments | Supporting documents related to actions on a remittance advice | Operator |
createdAt | When the remittance advice was created | Marketplacer |
id | Unique identifier of the remittance advice object | Marketplacer |
legacyId | Human readable version of the id | Marketplacer |
paidAt | When the remittance advice was paid | Operator |
paymentReference | Any external payment references to the payment | Operator |
remittanceActions | Collection of actions taken to make payment via 3rd party system (e.g. Hyperwallet) | Marketplacer |
remittances | Collection of remittance objects that make up the remittance advice | Marketplacer |
seller | The seller to which the remittance advice relates | Marketplacer |
totalCents | The suggested total of the remittance advice - denominated in the lowest unit of your currency, e.g. cents or pence | Marketplacer |
totalCentsFormatted | The suggested total of the remittance advice, given as a formatted string for your currency | Marketplacer |
totalPaidCents | The amount paid to the seller - denominated in the lowest unit of your currency, e.g. cents or pence | Marketplacer |
totalPaidFormatted | The amount paid to the seller, given as a formatted string for your currency | Marketplacer |
The take-away point here, (and as the name suggests) is that Remittance Advices are just an “advice” given to the Operator, it is up to the Operator to mark them as having been paid, and indeed what to pay.
You can see from the Defined By column in the above table just what fields can be updated by the Operator.
Before we do that though, let’s run a quick query to return all the Remittance Advices created since a particular date, where totalPaid
is 0:
query {
remittanceAdvices(
createdSince: "2023-01-20T14:36:28+11:00"
totalPaid: 0
) {
nodes {
id
createdAt
paidAt
totalPaidCents
totalCents
remittances {
id
released
amountCents
}
seller {
id
businessName
}
totalCents
}
}
}
This will return a payload similar to the following, (in this case we just get 1 Remittance Advice):
{
"data": {
"remittanceAdvices": {
"nodes": [
{
"id": "UmVtaXR0YW5jZUFkdmljZS0yOA==",
"createdAt": "2023-01-09T10:36:18+11:00",
"paidAt": null,
"totalPaidCents": 0,
"totalCents": 2699,
"remittances": [
{
"id": "UmVtaXR0YW5jZS0zMzc=",
"released": true,
"amountCents": 2699
}
],
"seller": {
"id": "U2VsbGVyLTg5",
"businessName": "ACME Inc."
}
}
]
}
}
}
There are a few observations with this response:
- There is only 1 remittance related to this advice (there can be multiple)
- The payment on the remittance has been released
- The Advice has not been paid:
paidAt
is null andtotalPaidCents
is 0
5. Mark Remittance Advice as Paid
Following on from the last step we now want to mark the Remittance as Advice as being paid, we can do this using the remittanceAdviceUpdate
mutation:
mutation{
remittanceAdviceUpdate(input:
{
remittanceAdviceId: "UmVtaXR0YW5jZUFkdmljZS0zMA=="
paidAt: "2023-03-20T14:36:28+11:00"
totalPaidCents: 2699
})
{
remittanceAdvice{
paidAt
}
}
}
This is quite a simplistic use of remittanceAdviceUpdate
, for example you can additionally use it to attach supporting docs related to the update you provide. For a full description of the inputs you can supply, refer to the RemittanceAdviceUpdateMutationInput
type found here.
Also note that if you are using the RemittanceAdvice
webhook, an update event will trigger when you call remittanceAdviceUpdate
.
Further financial information
This final section can be used as a reference to understand the fields available on each object that contain financial information. For example, if you require data beyond remittance per invoice to reconcile your payouts you will likely need to obtain some of the attributes below.
As an example, if you need to obtain exactly how much of the remittance is shipping you would likely include shippingCostCents
for the entire invoice or postageCents
for each lineItem.
Object | Field | Description |
---|---|---|
Remittance Advice | commissionAmountTotalCents | The total value of the commission within this remittance advice. This value should be equal to the sum of all remittance.commissionAmountCents |
totalCents | The total amount of the remittance advice. This value should be equal to the sum of all remittance.amountCents | |
totalPaidCents | Total paid to the seller on this remittance advice denominated in your lowest currency unit (cents, pence etc.) Only populated if the operator uses remittanceAdviceUpdate . This value is updated by the operator, it is not system generated | |
Remittance | amountCents | The remittance amount for a single invoice or invoice amendment |
commissionAmountCents | The commision amount for a single invoice or invoice amendment | |
Invoice | commissionAmountCents | Sum of all lineItems.commissionAmountCents |
commissionAmountTaxCents | Sum of all lineItems.commissionAmountTaxCents | |
discountCents | Sum of all lineItems.discountCents + any invoice discounts provided on orderCreate .Only populated if adjustments are included in orderCreate . | |
merchantFeeCents | Merchant fee set per invoice by operator. Only populated if merchant fee is configured. | |
merchantFeeTaxTotalCents | Tax for merchant fee set per invoice by operator. Only populated if merchant fee is configured. | |
shippingCostCents | Sum of all lineItems.postageCents | |
taxShippingCents | Sum of all postage tax on line items | |
subTotalCents | The invoice subtotal, excluding discounts and postage. Tax is included for tax inclusive marketplaces | |
taxTotalCents | Sum of (taxShippingCents + taxShippingCents + merchantFeeTaxTotalCents + commissionAmountTaxCents ) | |
totalCents | Total cost of the invoice, which includes subtotals and cost of shipping if applicable | |
LineItem | commissionAmountCents | Commission amount calculated by platform on order creation |
commissionAmountTaxCents | Total commission tax amount for the line item | |
discountCents | The discount applied to the item. Negative value. This only occurs when promotions are used with orderCreate . | |
itemAmountCents | Total cost per item | |
postageCents | The postage total on the item(s) | |
subTotalCents | The item subtotal, excluding discounts and postage. Tax is included for tax inclusive marketplaces | |
taxTotalCents | The tax on the item. Includes both postage and item tax | |
totalCents | Total cost of the items, which includes subtotals and cost of shipping if applicable | |
InvoiceAmendment | commissionAmountTotalCents | Only populated if the operator uses refundRequestApprove mutation |
commissionTaxTotalCents | Only populated if the operator uses refundRequestApprove mutation | |
lineItemAmountTotalCents | Only populated if the operator uses refundRequestApprove mutation | |
lineItemTaxTotalCents | Only populated if the operator uses refundRequestApprove mutation | |
remittanceAmountTotalCents | Only populated if the operator uses refundRequestApprove mutation | |
remittanceTaxTotalCents | Only populated if the operator uses refundRequestApprove mutation | |
remittanceCents | The remittance adjustment value of the invoice amendment | |
taxCents | The tax adjustment value of the invoice amendment | |
totalCents | Total adjustment value of the invoice amendment | |
InvoiceAmendmentLineItem | commissionAmountCents | Only populated if the operator uses refundRequestApprove mutation |
commissionTaxCents | Only populated if the operator uses refundRequestApprove mutation | |
lineItemAmountCents | Only populated if the operator uses refundRequestApprove mutation | |
lineItemTaxCents | Only populated if the operator uses refundRequestApprove mutation | |
remittanceAmountCents | Only populated if the operator uses refundRequestApprove mutation | |
remittanceTaxCents | Only populated if the operator uses refundRequestApprove mutation | |
amountCents | The amount (per item) that this line item is adding to the amendment | |
taxCents | Tax on the line item | |
totalCents | The total that this line item is adding to the amendment |