# Overview

Flash Payments Developer API documentation

## General information

Flash Payments API is [GraphQL](http://graphql.github.io/learn/queries/)-based, offering simple and developer-friendly querying experience. All data is exchanged in JSON format.

Flash Payments API playground is located here: <https://api.uat.flash-payments.com.au/>

### Complete API docs

This documentation website **does not have full list of API** fields and methods. This is intentional. The full list of the API calls you can performs and the data fields you can send/receive is listed in the [API Playground](https://api.uat.flash-payments.com.au/) (click "**DOCS**" on the right hand side).

## High level feature overview

You can search, visualise, or extract your data using our [FlashConnect](https://connect.uat.flash-payments.com.au/) interface.

### Instant local Australian deposit (aka pay-in)

Once registration is complete, a dedicated BSB and Virtual Account Number (VAN) for use within Australia will be assigned to you.

{% hint style="warning" %}
IMPORTANT: Your Australian VAN will be restricted to local Australian transfers. For international payments (aka FX payments), we offer different solutions.
{% endhint %}

Any funds deposited to your VAN would increase your Flash Payments balance. We store and retain the reference attached to each deposit (e.g., an invoice number) to support your reconciliation or reporting needs.

By default, only you can deposit into your VAN. Third-party deposits are also supported, but this feature must be enabled separately

Deposits are typically processed in real time, but depending on the bank, there may be a delay of up to 24 hours.

You can configure webhook notifications to receive alerts for every deposit made to your VAN. Please visit [FlashConnect](https://connect.uat.flash-payments.com.au/) to set up your deposit webhook.

You can manually reject unwanted deposits via the [FlashConnect](https://connect.uat.flash-payments.com.au/) interface. The funds will be returned to the original sender bank account.

### Local Australian withdrawal (aka pay-out)

The Flash Payments API enables you to withdraw funds from your Flash Payments balance. By default, only you are authorized to receive these withdrawals. Third-party withdrawals (also known as payouts) are available upon request and require separate activation.

If your payout involves a foreign exchange (FX) payment, it must be processed using the Australian Direct Entry system in accordance with legal requirements. Processing time may vary from immediate to a few hours. Other payouts are credited instantly.

If a payout fails, you will receive a webhook notification detailing the reason for the failure.

The payout remitter name is configurable. You can give us the remitter name as `withdrawal.sender` data property. This is especially useful for FX-linked payouts. If a Brazilian mama Katarina Oreiro sends money to her son in Australia, he will see his mom's name in the bank statement - "Payment from Katarina Oreiro".

Payouts can also be done via the [FlashConnect](https://connect.uat.flash-payments.com.au/) interface.

### Send or receive money internationally

You can send your Flash Payments balance internationally via our API and benefit from instant delivery to many countries with local instant payment systems (e.g. Philippines)

To initiate a payment, you must pre-create the sender and recipient via the API.

All entities in our database, including withdrawals, payments, senders, and recipients, can store your system’s unique identifier. Please refer to the `externalId` field in the [API docs](https://api.uat.flash-payments.com.au/).

Payment delivery times depend on the recipient's country. While many are processed quickly, some may take additional time. You’ll be notified via webhook whenever the payment status changes.

You can send funds through an international payment to your Flash Payments account. A webhook notification will be triggered when we detect payments from other countries.

### Security

The API token you generate expires in 4 hours. You can always use `logout` GraphQL mutation to expire it earlier.

You can't reset your own password until we verify your identity.

The [FlashConnect](https://connect.uat.flash-payments.com.au/login) interface supports Google and One-Time-Password logins.

Webhooks have cryptographic signatures.

IP address whitelisting feature is available from FlashConnect interface allowing login to our APIs from only preapproved addresses that you specify.

API rate limiting is in place to ensure stable performance of our service and prevent its potential abuse.

## How to start

1. Contact with us via [this page](https://flash-payments.com/connect) or by clicking the Intercom button on the bottom right of this page.
2. Explain what kind of services you are looking from Flash Payments.
3. We will examine your needs and explain how to get access to our UAT environment.

For more detailed instructions head to the [Basics](/basics/why-graphql) page.

## Important notes

### Breaking changes

While we will endeavour to not introduce any breaking changes they might still occur in the future. In that case we will communicate about the upcoming changes via your registered email.


# Why GraphQL

General information how to start using Flash Payments API

{% hint style="info" %}

### Assumptions

The examples below assume you are a verified customer of Flash Payments and have been enabled for API access.
{% endhint %}

### GraphQL Playground

All the GraphQL queries can be sent via the [GraphQL Playground](https://api.uat.flash-payments.com.au/) or as a HTTP POST request to `https://api.uat.flash-payments.com.au`. Example:

```bash
echo '{
  "query":
    "{
       quote(input: {
         fromCurrency: AUD, toCurrency: USD, size: 9.9, currency: AUD
       })
       {
         bid ask symbol timestamp inverted
       }
     }"
}' | curl -X POST 'https://api.uat.flash-payments.com.au' \
-H 'authorization: Bearer YOUR_TOKEN' \
-H 'content-type: application/json' \
-d @-
```

All the responses are JSON and have at least one property `data` and optional property `errors`.

```javascript
{
  "data": { ... },
  "errors": [ ... ]
}
```

{% hint style="info" %}

### Tip

In GraphQL Playground query editor press `Cmd+Space` or `Ctrl+Space` or `Opt+Space` or `Alt+Space` or `Shift+Space` to show context help and possible options.
{% endhint %}

Some of the GraphQL query parameters are required, others are optional. To understand if a variable/property is required you would need to check the API schema.

* Go to the [GraphQL Playground](https://api.uat.flash-payments.com.au/) and click the button "**DOCS**" on the right.
* Browse through queries, mutations, input and output types. Find a variable/property which have an exclamation mark at the end. E.g. `fromCurrency: FromCurrency!`.
* The exclamation mark denotes that the variable/property is mandatory.

### Data cleansing is your responsibility

{% hint style="danger" %}
Do not ever send us `"N/A"` or `"NA"` or `"NULL"` or `"null"` or `"nil"` or any other dummy string values in any of the API fields.
{% endhint %}

### The user-agent HTTP header

It is a good idea to always send custom `user-agent` HTTP header value when doing requests to Flash Payments API. Here is why:

* In case of troubleshooting we will be able to trace and mitigate your support questions **faster**.
* You might be **blocked** by our automated firewall if your user agent is something generic like `curl`, `Java-http-client`, `python-requests`, `Ruby`, etc.

### 429 Too many requests

Our API have smart monitoring and it may temporarily block your IP if it detects system misuse. For more information, please refer to the [Rate limiting](https://developer.flash-payments.com/other/rate-limiting) page.


# Sending data as JSON

Here is how to send your data to us as JSON instead of embedding it into the GraphQL queries.

For your initial tests, it may be easier and more practical to send data by **embedding values** directly into the GraphQL queries and mutations, as shown in the example below.

```bash
echo '{
  "query":
    "{
       quote(input: {
         fromCurrency: AUD, toCurrency: USD, size: 9.9, currency: AUD
       })
       {
         bid ask symbol timestamp inverted
       }
     }"
}' | curl -X POST 'https://api.uat.flash-payments.com.au' \
-H 'authorization: Bearer YOUR_TOKEN' \
-H 'content-type: application/json' \
-d @-
```

At the same time, to enable efficient and accurate handling of complex queries in code, we support sending GraphQL queries as JSON objects that consist of two properties: `"query"` and `"variables"`. Here is how you can do it:

* Declare the `$input` variable in the QraphQL `"query"` string. The technology also requires you to declare the type of your input(s). See the `QueryInput` in the example below.
* Provide the `"variables"` object with the `"input"` property. The value of it must be a JSON object structured exactly as the `QueryInput` type.

{% hint style="warning" %}
Only include the top-level input argument in your GraphQL queries. Including additional types may lead to compatibility issues when schema changes are deployed in production.

If you're using third-party tools or libraries to construct GraphQL queries, be aware that they may generate unsupported structures. We recommend avoiding GraphQL libraries to reduce this risk.
{% endhint %}

```bash
echo '{
  "query":
    "query ($input: QuoteInput!) {
       quote(input: $input) { bid ask symbol timestamp inverted }
     }",
  "variables": { 
    "input": { "fromCurrency": "AUD", "toCurrency": "USD", "size": 9.9, "currency": "AUD" }
  }
}' | curl -X POST 'https://api.uat.flash-payments.com.au' \
-H 'authorization: Bearer YOUR_TOKEN' \
-H 'content-type: application/json' \
-d @-
```

Here is a screenshot of how a typical mutation looks like in the API Playground:

![](/files/-Lzjy2n2_PPrKKTwwYau)

Same request as cURL:

```bash
echo '{
  "query":
    "mutation ($input: RecipientInput!) {
      createRecipient(input: $input) { code message recipient { id } }
    }",
  "variables": {
    "input": {
      "firstName": "Test",
      "lastName": "Lastest",
      "currency": "PHP",
      "accountIdType": "PH_CASH",
      "mobile": "+63 9121231234",
      "phCashoutNetwork": "MLHUILLIER",
      "address": {
        "building": "12th Floor Centerpoint Building",
        "street": "Julia Vargas Avenue corner Garnet Street",
        "suburb": "Pasig",
        "state": "manila",
        "country": "PH",
        "postcode": "1605"
      }
    }
  }
}' | curl 'https://api.uat.flash-payments.com.au' \
-H 'authorization: Bearer YOUR_TOKEN' \
-H 'content-type: application/json' \
-d @-
```


# Authentication

Get your access token

Before doing any other API calls you have to obtain an auth token. It's a standard JWT token carrying the following payload:

```javascript
{
  ...

  "iat": 1620967717,
  "exp": 1621054117
}
```

{% hint style="info" %}
Tip: Use this handy website to parse the token contents: [jwt.io](https://jwt.io/)
{% endhint %}

The token lifetime is **4 hours** at this time. We might change this value in the future.

{% hint style="warning" %}
Warning! You can't log in more than once per second. This limit is in place to maintain platform stability.
{% endhint %}

To be more future-proof, it is recommended to parse the token payload and compare current time to the token's expiration time. JavaScript code:

```javascript
const seconds = JSON.parse(Buffer.from(token.split(".")[1], "base64url")).exp;
if (Date.now() >= seconds*1000) {
  // get new token
}
```

{% hint style="warning" %}
This `login` mutation is a subject to change in the future.
{% endhint %}

### Getting a token

1. After we enable you, go to the [API Playground](https://api.uat.flash-payments.com.au/), click **"DOCS"** on the right to explore the possibilities.
2. Find there the `login` mutation. Execute it to obtain your access token. For example:\
   `mutation { login(input: {email: "YOUR_EMAIL" password: "YOUR_PWD"}) {token message} }`
3. Click the **"HTTP HEADERS"** on the bottom and add this: `{"authorization": "Bearer YOUR_TOKEN"}`. Replace the `YOUR_TOKEN` with the token you just got.
4. Execute any other queries.

Here is an example of the login query.

{% hint style="warning" %}
We suggest always sending your queries and related data separately using the "QUERY VARIABLES" tab in the [API playground](https://api.uat.flash-payments.com.au/) or programmatically by [submitting the variables as JSON](https://developer.flash-payments.com/basics/sending-data-as-json).
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>const bodyJSON = {
</strong>  variables: {
    input: {
      email: "you@example.com",
      password: "12345678",
    },
  },
  query: `
mutation ($input: LoginInput!) {
  login(input: $input) {
    token message code success
  }
}`,
};
</code></pre>

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: LoginInput!) {
  login(input: $input) {
    token
    message
    code
    success
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "email": "you@example.com", 
    "password": "12345678" 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "login": {
      "token": "YOUR_TOKEN",
      "message": "OK",
      "code": "SUCCESS",
      "success": true
    }
  }
}
```

{% endtab %}
{% endtabs %}

If using [API Playground](https://api.uat.flash-payments.com.au/) then click the "HTTP HEADERS" on the bottom left and paste there the following (replace the `YOUR_TOKEN` with the value you have just received form the above mutation):

```javascript
{
  "authorization": "Bearer YOUR_TOKEN"
}
```

### Affiliation

Clients that have contractual agreements with more than one subsidiary of Flash Payments, can use the optional field `affiliation` to control which account to log into.

The `affiliation` field accepts one of two constant values - `FP_AUS` or `FP_LUX` -  which are passed unquoted.

```javascript
{
  "input": { 
    "email": "you@example.com", 
    "password": "12345678",
    "affiliation": FP_AUS 
  }
}
```

If the `affiliation` value does not correspond to an existent account, authentication will fail with code `UNREGISTERED` even if an account exists with another affiliation and the credentials are correct.

If the user has multiple affiliations and the field `affiliation` is omitted, authentication will fail with code `NEED_AFFILIATION`.


# Required fields

Here is how to identify the mandatory input fields for your GraphQL queries and mutations.

Most documentation examples utilise typical GraphQL input data for successfully executing queries.

It's strongly encouraged that you always submit complete and accurate data, as this reduces our compliance team's reviewing efforts and, as a result, speeds up transactions and provides a great experience for your customers.

At the same time, we recognise that gathering complete customer information can be technically challenging, particularly regarding country-specific address details or account information. As a result, our API documentation emphasises the **required** input fields based on the principle of minimal necessity.&#x20;

Please pay attention to the exclamation mark ( `!` ) next to the field type in the API schema specification from the "Docs" section of our API Playground. Those are the required fields as it's demonstated on the screenshot below:

<figure><img src="/files/4qJMKmX502qEgro43uWo" alt=""><figcaption></figcaption></figure>

Please always verify that you have all required data to initiate a successful mutation or query.


# Webhooks

Two types of the webhooks

The primary triggers for all webhooks are **status** changes in payments, withdrawals, deposits, or conversions. For example, a webhook is sent when a withdrawal status changes from `PENDING` to `CONFIRMED`.

There are two types of webhooks in Flash Payments.

* [Regular webhooks](/basics/webhooks/regular-webhooks) - a URL would need to be saved to your [FlashConnect](https://connect.uat.flash-payments.com.au/) settings. Supports all types of events.
  * You can browse the history of all the webhook HTTP requests and your server responses, their JSON bodies and headers.
  * If there is no response we will show you what exactly the problem is: DNS issue, networking issue, 5XX response, etc.
  * You can receive webhooks when a deposit lands to your Virtual Account Number (VAN).
* [Ad hoc webhooks](/basics/webhooks/adhoc-webhooks) - you would need to provide a callback URL per each payment/withdrawal/conversion while creating them.

The webhooks HTTP POST calls will follow all the [standard HTTP redirects](https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections) (3XX codes).

### Security

#### Cryptographic signature

All webhook HTTP requests carry a cryptographic signature. [Ad hoc](/basics/webhooks/adhoc-webhooks) and [regular webhooks](/basics/webhooks/regular-webhooks) do it slightly different though.

#### Headers

Each request will contain at least these 4 headers:

```
content-type: application/json
user-agent: FlashFX
flashfx-request-id: [A unique ID of this particuar event]
flashfx-signature: [The cryptographic signature]
```

#### Flash Payments webhook request IP address

All webhook HTTP requests would be coming from these IP addresses:

* UAT environment: `52.64.185.170` and `13.210.129.208`
* Production environment: `52.62.138.234` and `52.65.3.195`

### Example payloads

**Deposits**

<details>

<summary>deposit_initiated</summary>

<pre class="language-json"><code class="lang-json"><strong>{
</strong>  "event": "deposit_initiated",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "currency": "AUD",
  "externalReference": "2233445566",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "statusMessage": "Deposit initiated",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
  "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
<strong>    "bsb": "809387",
</strong><strong>    "accountNo": "1839394"
</strong>  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
</code></pre>

</details>

<details>

<summary>deposit_reviewing</summary>

<pre class="language-json"><code class="lang-json"><strong>{
</strong>  "event": "deposit_reviewing",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "currency": "AUD",
  "externalReference": "2233445566",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "statusMessage": "Awaiting manual compliance",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
  "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
    "bsb": "809387",
    "accountNo": "1839394"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
</code></pre>

</details>

<details>

<summary>deposit_cleared</summary>

<pre class="language-json"><code class="lang-json"><strong>{
</strong>  "event": "deposit_cleared",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "currency": "AUD",
  "externalReference": "2233445566",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "statusMessage": "Deposit cleared",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
  "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
    "bsb": "809387",
    "accountNo": "1839394"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
</code></pre>

</details>

<details>

<summary>deposit_cancelled</summary>

```json
{
  "event": "deposit_cancelled",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "currency": "AUD",
  "externalReference": "2233445566",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "statusMessage": "Cancelled by: john@example.com : ",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
    "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
    "bsb": "809387",
    "accountNo": "1839394"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>deposit_refunding</summary>

```json
{
  "event": "deposit_refunding",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "refundAmount": 99,
  "currency": "AUD",
  "externalReference": "2233445566",
  "refundReason": "Client refund request",
  "statusMessage": "Deposit refunded",
  "refundedAt": "2026-03-03T03:28:43.936Z",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
    "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
    "bsb": "809387",
    "accountNo": "1839394"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>deposit_refunded</summary>

```json
{
  "event": "deposit_refunded",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "603f0198770d6595e3c83e0d",
  "amount": 100,
  "totalFee": 1,
  "refundAmount": 99,
  "currency": "AUD",
  "externalReference": "2233445566",
  "refundReason": "Client refund request",
  "statusMessage": "Deposit refunded",
  "refundedAt": "2026-03-03T03:28:43.936Z",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "recipient": {
    "accountName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387"
  },
    "sender": {
    "accountName": "ACME Inc",
    "companyName": "ACME Inc",
    "bankName": "Bank ACME",
    "bankCountry": "AU",
    "bsb": "809387",
    "accountNo": "1839394"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

**Withdrawals**

<details>

<summary>withdrawal_initiated</summary>

```json
{
  "event": "withdrawal_initiated",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "externalId": "12344321",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_reviewing</summary>

```json
{
  "event": "withdrawal_reviewing",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "statusMessage": "Awaiting manual compliance"
  "externalId": "12344321",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_pending</summary>

```json
{
  "event": "withdrawal_pending",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "statusMessage": "Sent to recipient bank"
  "externalId": "12344321",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_completed</summary>

```json
{
  "event": "withdrawal_completed",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "externalId": "12344321",
  "statusMessage": "Transaction Confirmed",
  "clearedAt": "2021-03-03T03:25:12.792Z",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_failed</summary>

```json
{
  "event": "withdrawal_failed",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "externalId": "12344321",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_refunded</summary>

```json
{
  "event": "withdrawal_refunded",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "refundAmount": 2000,
  "currency": "AUD",
  "externalId": "12344321",
  "refundReason": "No account or incorrect account number",
  "statusMessage": "Payout reversal",
  "refundedAt": "2026-03-04T15:21:11.920Z",
  "clearedAt": "2026-03-03T03:25:12.792Z",
  "recipient": {
    "displayName": "John Smith",
    "bsb": "012620",
    "accountNo": "89900998"
  },
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "John Smith",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

<details>

<summary>withdrawal_cancelled</summary>

```json
{
  "event": "withdrawal_cancelled",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "51711af8c078ba061f623531",
  "amount": 2000,
  "totalFee": 1,
  "currency": "AUD",
  "externalId": "12344321",
  "rejectCode": "CANCELLATION_REQUESTED_BY_PARTICIPANT",
  "rejectedAt": "2025-07-24T21:41:14.581Z"
  "statusMessage": "The transaction is rejected upon request.",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

**Payments**

<details>

<summary>currency_converted</summary>

```json
{
  "event": "currency_converted",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "externalId": "12344321"
}
```

</details>

<details>

<summary>payment_complete</summary>

```json
{
  "event": "payment_complete",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "externalId": "12344321"
}
```

</details>

<details>

<summary>payment_failed</summary>

```json
{
  "event": "payment_failed",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "externalId": "12344321"
}
```

</details>

<details>

<summary>payment_cancelled</summary>

```json
{
  "event": "payment_cancelled",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "externalId": "12344321"
}
```

</details>

<details>

<summary>payment_created</summary>

```json
{
  "event": "payment_created",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 3500,
  "fromCurrency": "EUR",
  "toAmount": 2501.94,
  "toCurrency": "AUD",
  "subClient": {
    "id": "203af01936410fd5d5e3c8f14d",
    "fullName": "ACME Inc",
    "accountNo": "1839394",
    "bsb": "809387",
    "externalId": "111222333"
  }
}
```

</details>

**Conversions**

<details>

<summary>conversion_initialised</summary>

```json
{
  "event": "conversion_initialised",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "rate": 0.41104,
  "externalId": "12344321"
}
```

</details>

<details>

<summary>conversion_pending</summary>

```json
{
  "event": "conversion_pending",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "rate": 0.41104,
  "externalId": "12344321"
}
```

</details>

<details>

<summary>conversion_converted</summary>

```json
{
  "event": "conversion_converted",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "rate": 0.41104,
  "externalId": "12344321"
}
```

</details>

<details>

<summary>conversion_failed</summary>

```json
{
  "event": "conversion_failed",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "rate": 0.41104,
  "externalId": "12344321"
}
```

</details>

<details>

<summary>conversion_cancelled</summary>

```json
{
  "event": "conversion_cancelled",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "60711af8c078ba061f623531",
  "fromAmount": 1000,
  "fromCurrency": "AUD",
  "toAmount": 411.04,
  "toCurrency": "EUR",
  "rate": 0.41104,
  "externalId": "12344321"
}
```

</details>

**Sub-clients**

<details>

<summary>subclient_initiated</summary>

```json
{
  "event": "subclient_initiated",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "INITIATED",
  "externalId": "123456789"
}
```

</details>

<details>

<summary>subclient_active</summary>

```json
{
  "event": "subclient_active",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "ACTIVE",
  "externalId": "123456789"
}
```

</details>

<details>

<summary>subclient_unapproved</summary>

```json
{
  "event": "subclient_unapproved",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "UNAPPROVED",
  "externalId": "123456789"
}
```

</details>

<details>

<summary>subclient_failed_kyc</summary>

```json
{
  "event": "subclient_failed_kyc",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "FAILED_KYC",
  "externalId": "123456789"
}
```

</details>

<details>

<summary>subclient_deactivated</summary>

```json
{
  "event": "subclient_deactivated",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "DEACTIVATED",
  "externalId": "123456789"
}
```

</details>

<details>

<summary>subclient_disabled</summary>

```json
{
  "event": "subclient_disabled",
  "eventScheduledAt": "2026-03-03T01:25:11.984Z",
  "id": "695257f8c8754a74ad671c48",
  "fullName": "John Doe",
  "status": "DEACTIVATED",
  "externalId": "123456789"
}
```

</details>

**Adverse Media Search**

<details>

<summary>ams_initialised</summary>

```json
{
  "event": "ams_initialised",
  "eventScheduledAt": "2026-03-03T08:23:14.521Z",
  "id": "6820a4f3e1c2b5d8f0123456",
  "name": "John Smith",
  "country": "AU",
  "status": "INITIALISED"
}
```

</details>

<details>

<summary>ams_pending</summary>

```json
{
  "event": "ams_pending",
  "eventScheduledAt": "2026-03-03T08:23:15.108Z",
  "id": "6820a4f3e1c2b5d8f0123456",
  "name": "John Smith",
  "country": "AU",
  "status": "PENDING"
}
```

</details>

<details>

<summary>ams_completed</summary>

```json
{
  "event": "ams_completed",
  "eventScheduledAt": "2026-03-03T08:26:42.774Z",
  "id": "6820a4f3e1c2b5d8f0123456",
  "name": "John Smith",
  "country": "AU",
  "status": "COMPLETED"
}
```

</details>

<details>

<summary>ams_failed</summary>

```json
{
  "event": "ams_failed",
  "eventScheduledAt": "2026-03-03T08:26:42.774Z",
  "id": "6820a4f3e1c2b5d8f0123456",
  "name": "John Smith",
  "country": "AU",
  "status": "FAILED"
}
```

</details>

**Request for Information (RFI)**

<details>

<summary>rfi_created</summary>

```json
{
  "event": "rfi_created",
  "eventScheduledAt": "2026-05-28T09:00:01.115Z",
  "id": "61f3a2c8d1e9b7a4c5d6e7f8",
  "statusMessage": "We are waiting for your replies",
  "deadline": "2026-06-04T09:00:00.000Z",
  "depositIds": [],
  "withdrawalIds": ["61f3a2c8d1e9b7a4c5d6e7aa"],
  "paymentIds": [],
  "createdAt": "2026-05-28T09:00:00.000Z",
  "updatedAt": "2026-05-28T09:00:00.000Z"
}
```

</details>

<details>

<summary>rfi_assessing</summary>

```json
{
  "event": "rfi_assessing",
  "eventScheduledAt": "2026-05-28T11:42:13.512Z",
  "id": "61f3a2c8d1e9b7a4c5d6e7f8",
  "statusMessage": "We are assessing the information you provided",
  "deadline": "2026-06-04T09:00:00.000Z",
  "depositIds": [],
  "withdrawalIds": ["61f3a2c8d1e9b7a4c5d6e7aa"],
  "paymentIds": [],
  "createdAt": "2026-05-28T09:00:00.000Z",
  "updatedAt": "2026-05-28T11:42:13.512Z"
}
```

</details>

<details>

<summary>rfi_closed</summary>

```json
{
  "event": "rfi_closed",
  "eventScheduledAt": "2026-05-29T02:10:44.901Z",
  "id": "61f3a2c8d1e9b7a4c5d6e7f8",
  "statusMessage": "We assessed the information you provided",
  "deadline": "2026-06-04T09:00:00.000Z",
  "depositIds": [],
  "withdrawalIds": ["61f3a2c8d1e9b7a4c5d6e7aa"],
  "paymentIds": [],
  "createdAt": "2026-05-28T09:00:00.000Z",
  "updatedAt": "2026-05-29T02:10:44.890Z"
}
```

</details>

<details>

<summary>rfi_cancelled</summary>

```json
{
  "event": "rfi_cancelled",
  "eventScheduledAt": "2026-05-28T14:05:09.220Z",
  "id": "61f3a2c8d1e9b7a4c5d6e7f8",
  "statusMessage": "This request has been withdrawn and no longer needs a response",
  "deadline": "2026-06-04T09:00:00.000Z",
  "depositIds": [],
  "withdrawalIds": ["61f3a2c8d1e9b7a4c5d6e7aa"],
  "paymentIds": [],
  "createdAt": "2026-05-28T09:00:00.000Z",
  "updatedAt": "2026-05-28T14:05:09.210Z"
}
```

</details>


# Ad hoc webhooks

How to secure your callback endpoints

When [sending a payment](/fx/payments/send-funds), [creating a local withdrawal](/moving-funds/payouts/withdraw-funds) or [ordering a conversion](/fx/conversions) you can provide us a webhook (callback) URI - `callbackUri`. We will call it when a payment or withdrawal status changes.

We recommend API clients to generate and add `?signature=ASecretPerPaymentKey` query to your `callbackUri` to make sure it's Flash Payments calling your webhook endpoint. For example:

```
https://my-webhooks.example.com/flash-payments?signature=oZaDlmfXbdXSKCnuWrvos2ImVBFX2Ru5
```

To avoid storing the signatures in a database we recommend generating them on the fly using a strong hash function or any kind of cryptography.

## Example

{% hint style="info" %}
This is just an example. Feel free to sign your URLs the way you want.
{% endhint %}

You would need to implement two functions.

1. Function to generate "signature".
2. Function to verify the "signature".

### Generating signatures

Node.js pseudo code to generate a signature in your integration code.

```javascript
const secret = "abcdefg";
function generateSignature(string) {
  return require("node:crypto")
    .createHmac("sha256", secret) // your secret key
    .update(string)
    .digest("base64");
}

const signature = generateSignature(stringIdFromMyDatabase);
const callbackUri = 
  "https://my-webhooks.example.com/flashfx?signature=" + signature;
const externalId = stringIdFromMyDatabase;

// Use both callbackUri and externalId when creating transfers with Flash Payments API
```

The code above creates a `callbackUri` and `externalId` variables. Use both of them when creating a transfer in Flash Payments API.

### Verifying signatures

Node.js pseudo code of your webhook HTTP request handler.

```javascript
function myCallbackEndpointHandler(req, res) {
  const signature = req.query.signature;
  const stringIdFromMyDatabase = req.body.externalId;
  
  if (generateSignature(stringIdFromMyDatabase) !== signature) {
    console.error("Security warning! Webhook endpoint received bad data", req);
    res.sendStatus(500);
    return;
  }
  
  // continue with the webhook processing
}
```


# Regular webhooks

How to setup web hooks for your integration

### Event notifications with webhooks

Flash Payments uses webhooks to notify your application when a transaction event happens in your account. This includes status update of your withdrawal, clearing of the incoming deposit, and more.

With webhooks, you can subscribe to the events of interest to trigger a subsequent action within your integration.

There are two steps to begin using webhooks. Building a custom endpoint on your server and registering it via the [FlashConnect](https://connect.uat.flash-payments.com.au/) settings.

### Building webhook endpoint

Each time a transaction event happens, we will send a HTTP POST request to your endpoint(s) that are subscribed to that event. The payload with event data is in the JSON format and can be used immediately. Every webhook endpoint must acknowledge the request, and as we strongly advise, verify the webhook signature.

**Acknowledging request**

To acknowledge the receipt of the event, your endpoint must return 2xx HTTP status code. All other response codes, including 3xx codes, indicate that you did not receive the event.

If we do not receive 200 HTTP status code, we will make up to 3 more request attempts. There is 6, 60 and 600 seconds delay between each delivery attempt respectively. If all request attempts fail, we mark webhook request as failed and will no longer try to deliver it.

Each webhook request has a `flashfx-request-id` header with a string that uniquely identifies a webhook event. For example, if there are multiple delivery attempts for the webhook event, each request will hold the same `flashfx-request-id`. This can be used to check if the webhook event was already processed by your application.

We advise that you acknowledge webhook request as early as possible.

**Securing the request**

To ensure that webhook was sent by Flash Payments and not a third party, we include the cryptographic signature in each request’s `flashfx-signature` header.

Before you can verify a signature, you need to retrieve your endpoint’s secret from webhook settings in the [FlashConnect](https://connect.uat.flash-payments.com.au/). Each registered endpoint has a unique secret that is used to sign a payload delivered to you on each event. Steps to verify signature:

1. Extract signature from the request header
2. Compute HMAC with SHA256 function. Use your endpoint secret as key and JSON payload string as a message.
3. Compare signature in the header to the computed signature.

Here is a Node.js pseudo code to generate and compare signatures

```javascript
const secret = "my-webhook-secret";
function generateSignature(string) {
  return require("node:crypto")
    .createHmac("sha256", secret) // your secret key
    .update(string)
    .digest("base64");
}
```

And verifying signature

```javascript
function myCallbackEndpointHandler(req, res) {
  const signature = req.headers["flashfx-signature"];
  const payload = req.body;
  
  if (generateSignature(payload) !== signature) {
    console.error("Security warning! Webhook endpoint received bad data", req);
    res.sendStatus(500);
    return;
  }
  
  // proceed with the webhook processing
}
```

**Testing your endpoint**

To make sure your webhook endpoint is setup correctly, you can make a test HTTP request from the [FlashConnect](https://connect.uat.flash-payments.com.au/) webhook settings. Click the **"Send Test”** button. You should receive a dummy request, which will need to be acknowledged the same way as your real webhook requests.

Then go to the history of the webhook requests and find the test request and response there.

### Subscribing to the events

Webhook requests come with event data. You can see all available event types in the [FlashConnect ](https://connect.uat.flash-payments.com.au/)settings. To subscribe, select which events you would like to receive and specify your endpoint. Please note, your endpoint must adhere to the HTTPS protocol for security reasons.


# API change log

History of changes to this API schema

## 2026-06-25

### Added

New properties `sender.bsb` and `sender.accountNo` for the `Deposit` type: [deposits](/moving-funds/deposits) now show the sender's Australian bank account BSB and Acc#.

New `sender.bsb` and `sender.accountNo` properties to all [deposit webhooks](/basics/webhooks#deposit_initiated) payloads.

## 2026-06-24

### Changes

Improved validation of the company name fields `legalName`, `tradingAsName`, and `companyName` in the [createSubClient](/accounts/virtual-account-numbers/create-sub-clients), [createSender](/moving-funds/senders#create-an-individual-sender), [updateSender](/moving-funds/senders#update-sender), [createRecipient](/moving-funds/recipients#create-an-individual-recipient), [updateRecipient](/moving-funds/recipients#update-recipient), [createInstitution](/moving-funds/institutions#creating-institutions), and [updateInstitution](/moving-funds/institutions#updating-institution-example) mutations. These fields must now be 2–256 characters long and can no longer contain the `<`, `=`, or `>` characters.

## 2026-06-17

### Added

New RFI status `CANCELLED` and a new [`rfi_cancelled`](/basics/webhooks#rfi_cancelled) webhook event.&#x20;

Our compliance team can now withdraw their request for information when it is no longer needed — the RFI moves to `CANCELLED`, you are notified by email and webhook, no response is required, and any linked deposits, withdrawals, or payments are left unaffected.<br>

New [Address Cleanser API](/compliance/address-cleanser). You can now validate and standardise physical addresses against multiple geocoding providers directly via the API — useful before processing payments and for keeping your address data consistent.

* New [`cleanseAddress`](/compliance/address-cleanser/cleanse-an-address) mutation — submits an address for cleansing. The result is returned synchronously with a suggested recommendation (`approve`, `review`, `reject`) and a score.
* New [`addressCleanserRequest`](/compliance/address-cleanser/query-address-cleanser-requests) and [`addressCleanserRequests`](/compliance/address-cleanser/query-address-cleanser-requests) queries — retrieve your past requests with optional filters by recommendation and date range.

Charged per request — 1,000 requests per month are free. Please contact support to have this API enabled for your account.

## 2026-06-12

### Added

New [Request for Information (RFI)](/compliance/request-for-information) API. When our compliance review flags one of your transactions, we raise an RFI — you can now receive, answer, and decline RFIs programmatically instead of (or alongside) the secure form sent by email.&#x20;

* New [`rfi`](/compliance/request-for-information/query-rfis#retrieving-a-single-rfi) and [`rfis`](/compliance/request-for-information/query-rfis#retrieving-all-rfis) queries — retrieve your RFIs with optional filters by status and date range.
* New [`answerRfiQuestion`](/compliance/request-for-information/answer-rfi-questions) mutation — answers a single RFI question with text and/or documents. Files are sent inline as base64; no separate upload step.
* New [`declineRfi`](/compliance/request-for-information/decline-an-rfi) mutation — declines an RFI when you cannot provide the requested information.
* Three new [webhook events](/basics/webhooks#rfi_created): `rfi_created`, `rfi_assessing`, `rfi_closed`. Dispatched for every RFI regardless of whether it is answered via the API or via the email form.

The RFI API is available to all clients — no enablement step is required.

## 2026-06-10

### Added

New [`members`](/other/account-members) query. You can now programmatically retrieve the users registered on your client account — their contact details, roles, access controls and statuses — information previously only available via the Flash Connect portal.

* Optional [`MembersQueryInput`](/other/account-members#filtering-members) filters: `status`, `roles`, `access`. A member matches if it holds at least one of the listed values.
* Results are always scoped to your own client account.

## 2026-04-14

### Added

New Adverse Media Search (AMS) API. You can now screen individuals and organisations against web-based adverse media sources directly via the API.

* New [`adverseMediaSearch`](/compliance/adverse-media-search/run-ams-request) mutation — submits a search for an individual or organisation. The scan runs in the background; use the returned `id` to track progress.
* New [`amsRequest`](/compliance/adverse-media-search/query-ams-requests#retrieving-a-single-ams-request) and [`amsRequests`](/compliance/adverse-media-search/query-ams-requests#retrieving-all-your-ams-requests) queries — retrieves your AMS requests with optional filters by status, date range, name, and country.
* Four new [webhook events](/basics/webhooks#ams_initialised): `ams_initialised`, `ams_pending`, `ams_completed`, `ams_failed`.

Please contact support to have this API enabled for your account.

## 2026-04-10

### Added

New [`confirmationOfPayee` ](/compliance/confirmation-of-payee)mutation. Confirmation of Payee (CoP) is a name-verification service for Australian domestic accounts. You can use it to check whether the recipient's name matches the account details held by their financial institution. The service currently supports Australian BSB accounts.&#x20;

## 2026-03-18

### Added

Two new objects to [`updateSubClient`](/accounts/virtual-account-numbers/disable-activate-and-update-sub-clients) mutation. You can change a sub-client's `address` and `postalAddress`. The updated address will be re-verified, so please make sure to include all its components, even if some fields, like the `country`, remain unchanged.

## 2026-03-05

### Added

New `rail` and `railService`  properties to  `Withdrawal` and `Deposit` payloads. You can now see exactly which payment infrastructure (such as NPP or BECS) and specific schemes (such as NPP IFTI) are used to route your transactions.

## 2026-03-03

### Added

New `currnecy` property to the `StatementQueryInput`, which allows you to retrieve any currency balance, not just the default `AUD`.

## 2026-02-26

### Added

New `eventScheduledAt` property to all [webhook](/basics/webhooks) payloads.

## 2025-12-31

### Added

New sub-client (aka Virtual Account Number, VAN) [statuses](/accounts/virtual-account-numbers/sub-client-statuses).

Previously a sub-client could be in 2 statuses: `ACTIVE` and `DEACTIVATED`.

Now there are 6: `INITIATED`, `ACTIVE`, <mark style="color:orange;">`UNAPPROVED`</mark>, `DEACTIVATED`, `FAILED_KYC`, `DISABLED`.

A set of new webhook events become available. See [here](/basics/webhooks#subclient_initiated). A webhook is sent when a sub-client status gets changed.

## 2025-12-30

### Added

A new `rejectCode` when we [cancel](/moving-funds/payouts/rejection-codes) your payout - `SOURCE_OF_FUNDS_INADEQUATE`. You'll receive it if we sent you an RFI (request for information) but your response contained a low quality data.

Please note, that a sibling property `statusMessage` will be hand crafted so that you know what exactly is wrong with your RFI reply (within the legal bounds). Please use the text to improve your KYC processes.

## 2025-11-14

### Added

A new `rejectCode` when we [cancel](/moving-funds/payouts/rejection-codes) your payout - `DATA_ENQUIRY_RESPONSE_INADEQUATE`. You'll receive it if we sent you an RFI (request for information) but your response contained a low quality data.

Please note, that a sibling property `statusMessage` will be hand crafted so that you know what exactly is wrong with your RFI reply (within the legal bounds). Please use the text to improve your KYC processes.

## 2025-11-10

### Added

The FX Payments `createPayment` can accept sender and recipient as JSON objects now too.

This means that when you need to do an orchestrated FX payment you need to submit only one HTTP request (`createPayment`) instead of 3  (`createSender`, `createRecipient`, and `createPayment`).

## 2025-10-31

### Added

A high demand long awaited feature. You don't need to pre-create senders/recipients before submitting a payout using `createWithdrawal` .

This means that when you need to do a remittance payment (aka payout) you need to submit only one HTTP request (`createWithdrawal`) instead of 3  (`createSender`, `createRecipient`, and `createWithdrawal`).

Example:

```javascript
const bodyJSON = {
  variables: {
    input: {
      amount: 1000, 
      recipient: {                  // <- this is new !!!
        bsb: "370370",
        accountNo: "123123123",
        companyName: "Acme Pty Ltd",
        currency: "AUD",
        accountIdType: "BSB",
        address: { street: "1 Main St SYDNEY NSW 2000", country: "AU" },
      },
      sender: {                     // <- this is new too !!!
        companyName: "Acme LLC",
        address: { street: "1 Jon St PORTLAND VA 54321", country: "US" },
      },
    },
  }, 
  query: ` 
mutation ($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success code message withdrawal { id }
  }
}`,
};

```

## 2025-10-24

### Changed

Enum `WithdrawalReason` is renamed to `TransactionReason`. The `reason` field inside `CreateWithdrawalInput` and `Withdrawal` type now uses `TransactionReason` instead of `WithdrawalReason`.

## 2025-08-07

### Changed

The validation logic for the `bic` field in the `createRecipient` mutation has been relaxed:

* When `accountIdType` is set to `IBAN`, `BSB`, or `PAYID`, the `bic` field is **not required** any more.
* When `accountIdType` is set to `ABA`, `CLABE`, `IFSC`, `CNAPS`, `SORT_CODE`, or `ACC_NO`, the `bic` field is still **required**.

## 2025-07-26

### Added

Three new fields to the `Withdrawal` type:

* `clearedAt` - the timestamp when the withdrawal become `CONFIRMED`.
* `rejectedAt` - the timestamp when the it was rejected by Flash Payments. See the `rejectCode` and `statusMessage` fields to understand the rejection reason.
* `refundedAt` - the timestamp when it was refunded. Very rare situation.

## 2025-07-25

### Added

The new optional field called `reason` was added to the `createWithdrawal` mutation and `Withdrawal` type.

If you have a payment/transaction/payout **purpose** - you must submit it to us via the API. See all the possible purpose codes (aka reason values) in the [GraphQL playground](https://api.flash-payments.com) (click the link in the header of this website), look inside the "docs" by the word "reason". You need to find the GraphQL enum called `WithdrawalReason`.

## 2025-07-24

### Added

An optional `affiliation` field has been added to the `login` mutation.\
This field accepts the `Affiliation` enum values `FP_AUS` or `FP_LUX`, allowing users to specify which Flash Payments subsidiary account to access when multiple contractual agreements exist. It is only required if your have more than one such agreement with us.

## 2025-05-02

### Removed (BREAKING)

Removed `depositDetails` query as deprecated and non-functioning since March 2024.

## 2025-01-24

### Changed

Improved validation rules for the following mutations: [createSender](/moving-funds/senders#create-a-sender), [updateSender](/moving-funds/senders#update-sender), [createInstitution](/moving-funds/institutions#creating-institutions), [createSubClient](/accounts/virtual-account-numbers#creating-a-sub-client), [createWithdrawal](/moving-funds/payouts/withdraw-funds), and [createPayment](/fx/payments/send-funds)\
Affected fields: `idDoc.docNumber` `idDoc.issuer` `legalName` `businessNumber` `legalName` `externalId`. These fields allow only the ASCII characters now.

Also, the first, last, and middle names are limited to 75 chars now.

Also, FQDN-like names will be rejected. Examples: "Aaron x.com", "Ben.eu", "Visit as at URL:example.com/about", etc.

## 2025-01-18

### Added

New fields have been added to the [createSender](/moving-funds/senders#create-a-sender), [updateSender](/moving-funds/senders#update-sender), and [createSubClient](/accounts/virtual-account-numbers#creating-a-sub-client) mutations. You can now provide `idDoc.country`, `idDoc.issueDate`, and `idDoc.expiryDate`. The `idDoc.issuer` field now only stores additional information about the issuer, while `idDoc.country` holds the country code of the country that issued the document.\
To avoid creating a breaking change, we currently allow you to provide `idDoc.country` and/or `idDoc.issuer`. In the future, we plan to make `idDoc.country` a **required** field.

## 2024-12-09

### Added

New [updateSubClient](/accounts/virtual-account-numbers#update-sub-clients) mutation. You can change a sub-client's `externalId` now, but nothing else.

## 2024-10-22

### Added

New the [Conversions](/fx/conversions) feature.

* New mutation `createConversion`. New queries `conversion` and `conversions`.
* The `FromCurrency` enum used to have only one item `AUD`. Now there are 8: `AUD CAD CHF EUR GBP NZD SGD USD`.
* New property for the `Quote` type: `applicability`. It indicates if the quote can be used for *payments* or *conversions*.

## 2024-10-11

### Fixed

The `bankInfo` [query](https://developer.flash-payments.com/reference-data/bank-information) was not returning information about BICs and IBANs. It works now.

## 2024-10-01

### Changed (BREAKING)

Improved validation of `recipient`, `sender`, `withdrawal`, `institution` related mutations. From now on `email`, `companyName`, `legalName`, `businessNumber`, `externalReference` must include only the ASCII characters.

## 2024-05-18

### Removed (BREAKING)

Removed `AccountIdType.PH_CASH`, `Recipient.phCashoutNetwork` with `RecipientInput.phCashoutNetwork` and the corresponding enum type `PhCashoutNetwork` from the GraphQL schema. These were not working for more than a year.

## 2024-05-17

### Removed (BREAKING)

Removed `AccountIdType.RIPPLE`, `Recipient.rippleAddress` with `Recipient.destTag` from the GraphQL schema. These were deprecated 2.5 years ago.

## 2024-04-16

### Removed (BREAKING)

Removed `Sender.isRipple` and `CurrencyIso3.XRP` from the GraphQL schema. These were deprecated 2.5 years ago.

## 2024-03-13

### Added

New [static codes and standard status messages](https://developer.flash-payments.com/reference-data/rejection-codes) introduced for rejected (aka cancelled) withdrawals. When withdrawals [get cancelled](https://developer.flash-payments.com/withdrawals/withdrawal-statuses) you can clearly see why using the new `rejectCode` and `statusMessage`. Available in the `Withdrawal` type and sent to your application via the [withdrawal\_cancelled](https://developer.flash-payments.com/webhooks#withdrawal_cancelled) webhook.

## 2024-02-05

### Changed

Improved [`updateRecipient`](https://developer.flash-payments.com/recipients#update-recipient) to respond with appropriate error message when trying to change the recipient's `accountIdType` which is not allowed by design.

## 2023-11-01

### Added

Added [`instructingInstitution`](/moving-funds/payouts/withdraw-funds#instructing-institutions) to the `CreateWithdrawalInput.`

## 2023-10-25

### Removed (BREAKING)

* Fields `acceptingInstructionInstitutionSenderId` and `acceptingMoneyInstitutionSenderId` were removed from the `CreateWithdrawalInput`.

### Added

* Instead `instructingInstitutionId` was added. (A new API for creating "institutions" is coming soon, but at the moment they can be created via the Flash Connect.)

## 2023-08-22

### Added

* [`statement`](/accounts/master-balance/statement) query.
  * This query returns the same data as the Download CSV button on the Account Statement page of the [Flash Connect](https://connect.flash-payments.com). It explains every change of you primary balance.
  * Currently it returns exactly 1 day of data. We plan to make date range selection more flexible in the future.

## 2023-08-04

### Changes

* Changed links from [flash-fx.com](https://flash-fx.com/) to [flash-payments.com](https://flash-payments.com/) domain. Old domain will continue working unit future notice.

## 2023-07-28

### Changes

* Our system always allowed `accountNo` to have letter. However, our API forced digits only. So, from now on, when you use `createRecipient`, your `accountNo` can have both letters and digits.

## 2023-05-25

### Changes

* Improved mobile phone validation. Now if mobile starts with "00" it's treated as if it starts with "+".
* Quote size accepts positive numbers only.

### Changes (BREAKING)

* The `recipient.mobile` and `sender.mobile` can accept only **valid** international phone numbers.

## 2023-03-15

### Added

* Added the `withdrawal_pending` [webhook](/basics/webhooks). Invoked after the transaction is sent to the recipient bank for processing.
* Added [example](https://developer.flash-fx.com/webhooks#withdrawal_pending) for the `withdrawal_pending` [webhook](/basics/webhooks).

## 2023-03-03

### Added

* `idempotencyKey` to `createPayment` input.
* `idempotencyKey` to `createWithdrawal` input.
* New [sub-client](/accounts/virtual-account-numbers) status - `UNAPPROVED`.

## 2023-02-23

### Added

* Fixed the `withdrawal_reviewing` [webhook](/basics/webhooks). It was never sent before even though declared on the Flash Connect website.
* Added [example](https://developer.flash-fx.com/webhooks#withdrawal_reviewing) for the `withdrawal_reviewing` [webhook](/basics/webhooks).

## 2023-02-08

### Removed (BREAKING)

* Removed the auto-creation of `id` for embedded senders and recipients. This means that if you (or FlashFX system) have created withdrawals and payments without explicitly providing sender or recipient ID then from now on the `sender.id` or `recipient.id` will be `null`. But, if you create payments or withdrawals via this API then you will always have `payment.sender.id` or `withdrwal.recipient.id`.

## 2022-09-06

### Added

* Missing `expireAt` property to the `Quote` object returned by the `quote` query.

## 2022-09-02

### Added

* New `REVIEWING` status to deposit and withdrawal status enum.
  * *`REVIEWING` : deposit*/withdrawal *is being internally checked by our compliance team before proceeding.*
  * Added corresponding [webhook](/basics/webhooks) event types: `deposit_reviewing` and `withdrawal_reviewing`.

## 2022-08-25

### Added

* New [webhook](/basics/webhooks) event type: `deposit_initiated` to notify that we received a deposit but not yet cleared it.
  * Previously only the `deposit_cleared` was sent and customers had no idea we are holding (reviewing) the deposit.
  * The `deposit_cleared` will be sent immediately as we approve (clear) the deposits. So, no changes here.

## 2022-07-01

### Added

* New item in `deposit` and related webhooks:
  * `recipient` - deposit recipient information as specified by deposit sender for this transaction:
    * `accountName`
    * `accountNo`
    * `bsb`
* New item in `deposit.sender:`
  * `bankName`
* New mutation to refund deposits:
  * `refundDeposit(id:ID! input:RefundDepositInput): RefundDepositReply`

## 2022-04-22

### Changes

* Additional validation for `dob` field introduced for Senders, Recipients and Sub-clients to enforce the data is entered in YYYY-MM-DD format. The field will also allow for only the data after 1900-01-01 and individuals of 18 years of age or older.

## 2022-04-12

### Changes

* Added validation of address fields. From now on, any address submitted as a part of any transaction should only include ASCII characters.

## 2022-02-25

### Changes

* Added `deposit.sender.accountName` so that you can query who deposited money to your Virtual Account Number (VAN).

## 2022-02-14

### Changes

* Additional validation for `lastName`, `middleName` and `firstName` introduced allowing only for latin alphabetical characters and special symbols: <img src="/files/6Q79p4DHBBFn9z0Jh2L1" alt="" data-size="line">

## 2022-02-09

### Changes

* `FundingAccount` type has been extended to include all deposit details you need to bring money to Australia. Your account address can now be retrieved using `accountAddress` property along with `name` and `address` fields which identify the accepting financial institution associated with your account.

## 2022-01-12

### Changes

* `lastName` and `firstName` fields of `Sender` and `Recipient` objects can now be one symbol long to allow for initials. Please note that such single symbols have to be alphabetic.

## 2021-11-02

### Changes

* Occasionally `Payment` objects do not have `sender` or `recipient` properties. Thus these properties are now marked at "not required" (exclamation mark was removed) when querying payments.
* We have added rate limiting. You can receive HTTP 429 error code and get temporary blocked if abusing the API too much.

## 2021-08-13

### Changed (BREAKING)

* Removed **XRP** currency form the list of supported currencies.

## 2021-07-22

### Changed (BREAKING)

* While creating sub-clients the address of the person/company was not required. It was a bug which was fixed. To create a sub-client you would also need their: **street** address, **suburb**/city, **state**/region, **postcode**, and country.

## 2021-07-14

### Changes

* Allow `accountNo` to be 4 digits long. Some old Japanese bank accounts could be just 4 digits.

## 2021-07-08

### Added

* The ability to query deposits, withdrawals, payments by the associated sub-client (`subClientId`).
* The payments can also have sub-clients now. Added the `Payment.subClient` field.

## 2021-06-29

### Added

* The `totalFee` property to both `Deposit` and `Withdrawal` types as well as webhook payloads.

## 2021-06-22

### Added

* The `bankInfo` reference query. You can now validate your BSB for existence, check if we support your BIC, and retrieve BIC (aka SWIFT code) by IBAN.

## 2021-06-17

### Added

* The `fundingAccounts` and `SubClient.fundingAccounts` queries. It returns international bank account numbers you can deposit in order to bring money to Australia. See [Auto receive funds](/fx/payments/auto-receive-funds) for more details.

## 2021-05-25

### Changed

* The `senderId` was always required when creating withdrawals via `createWithdrawal`. But now, if you provided the `subClientId` and didn't provide the `senderId` the sub-client becomes the sender, and will be reported to the government as the sender. However, you still must provide the `senderId` if your sub-client moves funds for other people/companies.

## 2021-05-17

### Changed (BREAKING)

* Replaced `docIssuer`, `docType` and `docNumber` fields from `CreateSubClientInput` with `idDoc` nested field instead.

## 2021-04-26

### Changed

* `RecipientAccountIdType` was fully duplicating the `AccountIdType`. Replace the former with the latter. This might break your auto-generated code in strongly typed languages. But won't change any API queries or responses. So, this change is not considered to be a breaking.

## 2021-04-16

### Added

* Added ability to disable and activate sub-clients
  * mutation `disableSubClient(id: ID!): MutateSubClientReply`
  * mutation `activateSubClient(id: ID!): MutateSubClientReply`

## 2021-04-12

### Added

* Added deposit queries
  * query `deposits(input: DepositQueryInput): [Deposit]`
  * query `deposit(id: ID!): Deposit`
* **Introduced sub-client feature** – transactional virtual account numbers for AUD processing in Australia.
  * query `subClients(input: SubClientQueryInput): [SubClient]`
  * query `subClient(id: ID!): SubClient`
  * mutation `createSubClient(input: CreateSubClientInput!): MutateSubClientReply`
* Deposit and withdrawal webhooks now include `subClient` object with sub-client information when present

## 2021-01-07

### Removed (BREAKING)

These types and fields were never used by anyone for couple of years.

* Removed enum `DepositMechanism`.
* `PaymentInput` and `ConfirmPaymentInput` fields:
  * removed `depositMechanism`
  * removed `depositReference`
  * removed `depositAmount`

## 2020-12-16

### Added

* New item in `BsbDepositDetails`
  * `accountName` - Australian account name.
* New item in `Withdrawal`
  * `statusMessage` - a human readable message of the current status reason, like processing error messages.
* New item in `Payment` and `PaymentInput`
  * `sourceOfFunds` - mandatory field for some destinations.
* New enum `SourceOfFunds`.

## 2020-10-14

### Added

* New items in both query type and mutation input `Senders`.
  * `legalName`
  * `tradingAsName`
  * `businessNumber` - differs by country, e.g. ABN in Australia.
  * `acn` - Australian Company Number. Should not be used for other countries.

## 2020-06-18

### Changed (BREAKING)

* Fixed typo in `RecipientQueryInput` field name. `snaps` -> `cnaps`

## 2020-05-04

### Added

* New compliance-related fields to the `CreateWithdrawalInput` input:
  * `acceptingMoneyInstitutionSenderId` - you must pre-create this `Sender` and submit every time if you are not the FI who collected the money for this withdrawal.
  * `acceptingInstructionInstitutionSenderId` - you must pre-create this `Sender` and submit every time if you were instructed by other FI to make this withdrawal.

## 2020-03-05

### Changed (BREAKING)

* Fixed typo in the `WithdrawalStatus` enum item. `INITIALISING` -> `INITIALISED`

## 2020-02-12

### Added

* `callbackUri` to `Payment`, `Withdrawal`, `CreateWithdrawalInput`. Now you can query the callback/webhook URI you have supplied earlier. Also, this allows you to receive webhooks when you create a withdrawal (aka *local payout*).

## 2020-02-11

### Added

* New items in `RecipientQueryInput`. This means that recipients can be searched by:
  * `firstName`
  * `lastName`
  * `middleName`
  * `dob` - date of birth
  * `companyName`
  * `phCashoutNetwork`
  * `payid`
  * `bic`
  * `iban`
  * `aba`
  * `bsb`
  * `clabe`
  * `cnaps`
  * `sortCode`
  * `ifsc`
  * `accountNo`
  * `rippleAddress`
  * `externalId` - ID in your system

## 2020-01-28

### Added

* Introduced Withdrawals - send money from your account (FlashFX digital wallet) to local banks.
  * query `withdrawal(id: ID): Withdrawal`
  * query `withdrawals(input: WithdrawalQueryInput): [Withdrawal]`
  * mutation `createWithdrawal(input: CreateWithdrawalInput!): CreateWithdrawalReply`
* `PHP` currency support.
* `middleName` property in recipients and senders.
* `PAYID` recipient type for Australian local payments or withdrawals.
  * `Recipient.payid` new property.
* `PH_CASH` recipient type for Philippines cash network payments.
  * `Recipient.phCashoutNetwork` new property.
* You can now query your recipients by `accountIdType` property. For example: ` recipients(input: {`` `` `**`accountIdType: PH_CASH`**` `` ``}) `

### Removed (BREAKING)

* Removed the unused enum `PaymentType`. It has no sense and was deprecated a year ago.
  * Simultaneously removed properties `Payment.paymentType`, `PaymentQueryInput.paymentTypes`, `PaymentInput.paymentType`.
* Removed the long deprecated `PaymentInput.recipient` object. The only way to provide a recipient for a payment is via `PaymentInput.recipientId`. You would need to [pre-create the recipient](/moving-funds/recipients#create-a-recipient) beforehand.
* Removed the never used `AccountIdType` enum values: `BPAY`, `FIN_BTN`, `INTERAC`.


# Master Balance

Query your master account balances

Paste this query to the GraphQL Playground

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  operationName: "balances",
  variables: {
    currencies: ["AUD"],
  },
  query: `
query balances($currencies: [CurrencyIso3]) {
  balances(currencies: $currencies) {
    currency cleared pending
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query balances($currencies: [CurrencyIso3]){
  balances(currencies: $currencies) {
    currency
    cleared
    pending
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```
{
  "currencies": ["AUD"]
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "balances": [
      {
        "currency": "AUD",
        "cleared": 3860,
        "pending": 0
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

The `cleared` is the **Primary** balance you see on the Flash Connect website.

The `pending` balance is typically not shown on the Flash Connect interface because it's rather short lived. If your **Pending** balance is not 0 then you can see it right next to the **Primary** balance.

If you omit the `currencies` input argument then the query would return all the currency balances you have. Contact us to enable more than just the default `AUD` currency.

### Top up your UAT account balance

If you need to increase your **UAT** account balance please sign in to the **Flash Connect** website, open **Deposits** page, and click **Send Test Deposit**.


# Statement

Understand every movement of your primary balance

This query returns the same data as the Download CSV button on the Account Statement page of the [Flash Connect](https://connect.uat.flash-payments.com.au/).

The dates must be any ISO 8601 formatted dates.

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript">const bodyJSON = {
  variables: {
    input: {
        fromDate: "2023-08-28T00:00:00+03:00",
        currency: "USD",
    },
  },
  query: `
query ($input: StatementQueryInput!) {
  statement(input: $input) {
    succes code message fromDate toDate 
      rows {
        debit credit
    }
  }  
<strong>}`,
</strong>};
</code></pre>

{% endtab %}

{% tab title="GraphQL" %}

```graphql
query($input: StatementQueryInput!) {
  statement(input: $input) {
    success
    code
    message
    fromDate
    toDate
    rows {
      debit
      credit
      # and many other fields
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

<pre class="language-javascript"><code class="lang-javascript">{
<strong>  "input": {
</strong>    "fromDate": "2023-08-28T00:00:00+03:00",
    "currency": "USD"
  }
}
</code></pre>

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "statement": [
      {
        "success": true,
        "code": "GENERATED",
        "message": "Statement generated",
        "fromDate": "2023-08-27T21:00:00Z",
        "toDate": "2023-08-28T21:00:00Z",
        "rows": {
          [
            {
              "debit": 123.45,
              "credit": 0
            }
          ]
        }
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

The response dates are aways UTC. Timezones are always taken into account.


# Virtual account numbers

Generate named Virtual Account Numbers (aka sub-clients) for your clients' for collection

The sub-client (aka *merchant*) feature allows you to create client accounts for deposit collection purposes. These virtual accounts can be issued to individuals, companies, or other organisations.

{% hint style="info" %}
Note: This feature is **disabled** by default. Contact us if you want it.
{% endhint %}

Each sub-client will receive a dedicated **BSB** and **Vitrual Account Number** (VAN) that you or your clients can use to accept and withdraw domestic AUD transfers within Australia.

{% hint style="warning" %}
IMPORTANT: Your Australian VAN will be restricted to local Australian transfers. For international payments (aka FX payments), we offer different solutions.
{% endhint %}

The **account name** is your sub-client's name. For companies - it's their `tradingAsName` or `legalName`. For individuals - it's their `fullName` (`firstName` + `middleName` + `lastName`).

If your Flash account has a multi-currency feature enabled, each of your sub-clients will also have access to virtual accounts in the selected currencies for which you hold balances.

All [deposits](https://developer.flash-payments.com/deposits) sent to your sub-client Virtual Account Numbers (VANs) are booked on your (master-client's) corresponding account balances. **Sub-clients can't have their own balances**.

You can[ disburse funds](https://developer.flash-payments.com/withdrawals/withdraw-funds) and [make FX payments](https://developer.flash-payments.com/payments/send-funds) on behalf of your sub-clients by providing the sub-client ID when you create withdrawals or payments. This sub-client record will then be used as the sender, linked to the transaction, and reported to the government.

Notifications via [webhooks](/basics/webhooks/regular-webhooks) will provide important sub-client information as well.


# Create sub-clients

There are two types of sub-clients: `company` and `individual`.&#x20;

For every `company` registered as a sub-client, there must be one contact person for individual data submitted. Ideally, the contact person should be a **company director** or have a similar role. Therefore, if you are creating a sub-client of the `company` type, we require you to provide **extra** **details**:

* `legalName` - company legal name
* `businessNumber` - company business number (e.g. ABN in Australia)

If the above fields are not set, the sub-client will be created as `individual` type.

{% hint style="warning" %}
This action creates a real account number. If you ever submit fake, unreal, testing, or incorrect data - you will be immediately **blocked** from Flash Payments services.

Please add all possible precautions, processes, staff training, warning messages, and validation checks to your system(s) before creating a sub-client.

Please follow our latest requirements for the proper sub-client data submission:

1. Provide proper `firstName` , `middleName`, and `lastName` Please note that including the accurate `middleName`  is essential for the account name matching capability of the Australian New Payments Platform (NPP) real-time digital payment network.
2. Provide proper `mobile` number
3. Provide proper `dob` : **the person must be under 65 years of age**&#x20;
4. Provide proper residential `address` including unit and street number. The sub-client address should correspond to your approved use case from the contract agreement. By default, you can only create local Australian sub-clients with an adequate `address.street` field provided. **Any non-Australian entities will undergo extended due diligence based on their location and industry relevance for Flash Payments.**  &#x20;
5. Provide proper `idDoc` (`type`, `docNumber`, `issuer` (optional), `issueDate` (optional), `expiryDate` (optional), and `country` ) based on the sub-client contact person's address. For Australian residents, either a driver’s license or a passport is accepted. For non-Australian residents, only a passport is accepted as a document type.
6. Sometimes, we ask our partners to provide “instructing institution” information, but only if you are creating this VAN on behalf of another financial institution. More about institutions [here](/moving-funds/institutions). You may provide the ID of the already created institution via the field `instructingInstitutionId` or as a full object via the `instructingInstitution` field.
   {% endhint %}

The above personal data submission requirements should be as equally followed for the company contact person, with the exception of `address` property, which can be a company address in this case. &#x20;

To create a sub-client, you need to execute the `createSubClient` mutation as below. You can find the description of each field in the GraphQL API schema.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: { 
    input: {
      legalName: "Chineese Tradings", 
      businessNumber: "330782000329701", 
      firstName: "John", 
      lastName: "Smith", 
      email: "john.smith@example.com",
      mobile: "+61422832849",
      dob: "1979-05-12",
      address: {
        building: "25",
        street: "Xihu Road, Yuexiu District",
        suburb: "Guangzhou City",
        state: "Guangdong Province",
        postcode: "510030",
        country: "CN",
      },
      idDoc: {
        type: "passport",
        docNumber: "FF1948394",
        issuer: "Australian Passport Office (APO)",
        issueDate: "2000-01-01",
        expiryDate: "2045-01-01",
        country: "AU",
      },
      externalId: "991188227733",
    },
  },
  query: `
mutation ($input: CreateSubClientInput!) {
  createSubClient(input: $input) {
    success code message
    subClient {
      id legalName businessNumber fullName clientType status
      primaryContact {
        firstName lastName email mobile dob
      }
      address {
        country
      }      
      bsb accountNo externalId
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: CreateSubClientInput!) {
  createSubClient(input: $input) {
    success
    code
    message
    subClient {
      id
      legalName
      businessNumber
      fullName
      clientType
      status
      primaryContact {
        firstName
        lastName
        email
        mobile
        dob
      }
      address {
        country
      }
      bsb
      accountNo
      externalId
      # more properties available, see API schema
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "input": {
    "legalName": "Chineese Tradings",
    "businessNumber": "330782000329701",
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@example.com",
    "mobile": "+61422832849",
    "dob": "1979-05-12",
    "address": {
      "building": "25",
      "street": "Xihu Road, Yuexiu District",
      "suburb": "Guangzhou City",
      "state": "Guangdong Province",
      "postcode": "510030",
      "country": "CN"
    },
    "idDoc": {
      "type": "passport",
      "docNumber": "FF1948394",
      "issuer": "Australian Passport Office (APO)",
      "issueDate": "2000-01-01",
      "expiryDate": "2045-01-01",
      "country": "AU"     
    },
    "externalId": "991188227733"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createSubClient": {
      "success": true,
      "code": "SUBCLIENT_CREATED",
      "message": "Sub-client was successfully created",
      "subClient": {
        "id": "606d28675a2d931bc925fec2",
        "legalName": "Chineese Tradings",
        "businessNumber": "330782000329701",
        "fullName": "John Smith",
        "clientType": "INDIVIDUAL",
        "status": "ACTIVE",
        "primaryContact": {
          "firstName": "John",
          "lastName": "Smith",
          "email": "john.smith@example.com",
          "mobile": "+61 422 832 849",
          "dob": "1979-05-12"
        },
        "address": {
          "country": "CN"
        },
        "bsb": "802919",
        "accountNo": "1066419",
        "externalId": "991188227733"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Sub-client statuses

Sub-client VANs lifecycle

A sub-client lifecycle follows these stages.

A sub-client is created and has the **temporary** `INITIATED` status.\
At this stage, the request has been received and the system is currently processing it.

If processing is completed successfully, the sub-client automatically transitions to the `ACTIVE`.\
In this status, the sub-client is fully activated and approved.

If the sub-client requires manual compliance review, the sub-client moves from `INITIATED` to the **temporary** <mark style="color:orange;">`UNAPPROVED`</mark> status.\
From this status it would eventually transition to either `ACTIVE` or `FAILED_KYC`.\
Typically, we can't disclose the exact reason of the KYC failure, while it mostly happens because we do not have risk appetite for your client.

You can deactivate the client (via API of Flash Connect), - it'd move from `ACTIVE` to `DEACTIVATED`.\
A sub-client in the `DEACTIVATED` status can be activated by you at any time, returning to `ACTIVE`.

At any point, a sub-client may be moved to `DISABLED`.\
In this status, the sub-client is disabled and cannot be enabled by you, and contacting support is required for further information.


# Disable, Activate and Update sub-clients

You can disable and activate sub-clients. Deposits sent to a disabled sub-client will no longer be booked against your balance.

#### Disabling a sub-client

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "606128f24bf29139b2cf74ef",
  },
  query: `
mutation ($input: ID!) {
  disableSubClient(id: $input) {
    success code message 
    subClient {
      id status
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: ID!) {
  disableSubClient(id: $input) {
    success
    code
    message
    subClient {
      id
      status
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
   "input": "606128f24bf29139b2cf74ef"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "disableSubClient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Sub-client was successfully disabled",
      "subClient": {
        "id": "606128f24bf29139b2cf74ef",
        "status": "DISABLED"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Activating a sub-client

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "606128f24bf29139b2cf74ef",
  },
  query: `
mutation ($input: ID!) {
  activateSubClient(id: $input) {
    success code message 
    subClient {
      id status
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GrraphQL Query" %}

```graphql
mutation($input: ID!) {
  activateSubClient(id: $input) {
    success
    code
    message
    subClient {
      id
      status
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
   "input": "606128f24bf29139b2cf74ef"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "activateSubClient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Sub-client was successfully activated",
      "subClient": {
        "id": "606128f24bf29139b2cf74ef",
        "status": "ACTIVE"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Updating sub-clients

At this point, you can only update the `externalId` , `address` and `postalAddress` properties because each sub-client has a set of linked domestic and international Virtual Account Numbers to send and receive funds.

{% hint style="info" %}
Please note, that the updated address will be re-verified, so make sure to include all its components, even if some fields, like the `country`, remain unchanged.<br>
{% endhint %}

#### Updating sub-client externalId

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = { 
  variables: {
    id: "660fef8e1f3b5452bd6945ec",
    input: {
      externalId: "my_system_id_29f-ae0978b00d09e",
    },
  }, 
  query: `
mutation ($id: ID!, $input: UpdateSubClientInput!) {
  updateSubClient(id: $id, input: $input) {
    success code message
    subClient {
      id status externalId
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID!, $input: UpdateSubClientInput!) {
  updateSubClient(id: $id, input: $input) {
    success
    code
    message
    subClient {
      id
      status
      externalId
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "id": "660fef8e1f3b5452bd6945ec", 
  "input": {
    "externalId": "my_system_id_29f-ae0978b00d09e"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "updateSubClient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Sub-client was successfully updated",
      "subClient": {
        "id": "660fef8e1f3b5452bd6945ec",
        "status": "ACTIVE",
        "externalId": "my_system_id_29f-ae0978b00d09e"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Updating sub-client address

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = { 
  variables: {
    id: "660fef8e1f3b5452bd6945ec",
    input: {
      adddress: {
        street: "456 New St",
        suburb: "Newtow",
        state: "VIC",
        postcode: "3220", 
        country: "AU",
      },
    },
  }, 
  query: `
mutation ($id: ID!, $input: UpdateSubClientInput!) {
  updateSubClient(id: $id, input: $input) {
    success code message
    subClient {
      id status externalId address {building street suburb state postcode country}
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID!, $input: UpdateSubClientInput!) {
  updateSubClient(id: $id, input: $input) {
    success
    code
    message
    subClient {
      id
      status
      externalId
      address {
        building 
        street
        suburb
        state
        postcode
        country
      }
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "id": "660fef8e1f3b5452bd6945ec", 
  "input": {
    "address": {
        "street": "456 New St",
        "suburb": "Newtow",
        "state": "VIC",
        "postcode": "3220",
        "country": "AU"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "updateSubClient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Sub-client was successfully updated",
      "subClient": {
        "id": "660fef8e1f3b5452bd6945ec",
        "status": "ACTIVE",
        "externalId": "my_system_id_29f-ae0978b00d09e",
        "address": {
          "building": null,
          "street": "456 New St",
          "suburb": "Newtow",
          "state": "VIC",
          "postcode": "3220",
          "country": "AU"
        }
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Query sub-clients

### Available queries

#### Query for a single sub-client

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "606d28675a2d931bc925fec2",
      input: {
        currencies: ["EUR","USD","HKD","CNY"],
      },
  },
  query: `
query ($id: ID!, $input: FundingAccountQueryInput!) {
  subClient(id: $id) {
    id fullName legalName tradingAsNam clientType status 
    primaryContact {
      firstName middleName lastName email dob mobile
    }
    address {
      building street suburb state country postcode
    }
    postalAddress {
      building street suburb state country postcode
    } 
    businessNumber bsb accountNo externalId
    fundingAccounts(input: $input) {
      iban accountNo bic currency externalReference
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($id: ID!, $input: FundingAccountQueryInput!) {
  subClient(id: $id) {
    id
    fullName
    legalName
    tradingAsName
    clientType
    status
    primaryContact {
      firstName
      middleName
      lastName
      email
      dob
      mobile
    }
    address {
      building
      street
      suburb
      state
      country
      postcode
    }
    postalAddress {
      building
      street
      suburb
      state
      country
      postcode
    }
    businessNumber
    bsb
    accountNo
  	externalId
    fundingAccounts(input: $input) {
      iban
      accountNo
      bic
      currency
      externalReference
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "id": "606d28675a2d931bc925fec2",
  "input": {
    "currencies": ["EUR", "USD", "HKD", "CNY"] 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "subClient": {
      "id": "606d28675a2d931bc925fec2",
      "fullName": "ACME Corp",
      "legalName": "ACME Corp",
      "tradingAsName": null,
      "clientType": "COMPANY",
      "status": "ACTIVE",
      "primaryContact": {
        "firstName": "John",
        "middleName": null,
        "lastName": "Smith",
        "email": "john.smith@example.com",
        "dob": "1980-12-12",
        "mobile": "+61 422 832 849"
      },
      "address": {
        "building": "25",
        "street": "Moore St",
        "suburb": "Waterloo",
        "state": "NSW",
        "country": "AU",
        "postcode": "2017"
      },
      "postalAddress": {
        "building": "25",
        "street": "Moore St",
        "suburb": "Waterloo",
        "state": "NSW",
        "country": "AU",
        "postcode": "2017"
      },
      "businessNumber": "91383840265",
      "bsb": "802919",
      "accountNo": "1066419",
      "externalId": "991188227733"
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Query for multiple sub-clients

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  },
  query: `
query ($input: SubClientQueryInput!) {
  subClients(input: $input) {   
    id fullName legalName clientType status businessNumber
    bsb accountNo externalId
  }
}`,
};  
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: SubClientQueryInput!){
  subClients(input: $input) {
    id
    fullName
    legalName
    clientType
    status
    businessNumber
    bsb
    accountNo
    externalId
    # any other set of properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
 "input": {
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "subClients": [
      {
        "id": "5fb314cb9224595df522db61",
        "fullName": "Richard Smith",
        "legalName": null,
        "clientType": "INDIVIDUAL",
        "status": "ACTIVE",
        "businessNumber": null,
        "bsb": "802919",
        "accountNo": "1963041",
        "externalId": null
      },
      {
        "id": "60612f00a4d7dd5c96e37676",
        "fullName": "ABC Capital",
        "legalName": "ABC Co",
        "clientType": "COMPANY",
        "status": "ACTIVE",
        "businessNumber": "839399923932",
        "bsb": "802919",
        "accountNo": "1914920",
        "externalId": null
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Query for multiple sub-clients with filters

{% tabs %}
{% tab title="JavaSscript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      clientType: "INDIVIDUAL",
      status: "ACTIVE",
      firstName: "John",
      lastName: "Smith",
      address: { 
        country: "AU", 
      },
    },
  },
  query: `
query ($input: SubClientQueryInput!) {
  subClients(input: $input) {   
    id fullName clientType status 
    primaryContact {
      firstName lastName
    }
    address {
      country
    }
  }
}`,
};  
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: SubClientQueryInput!){
  subClients(input: $input) {
    id
    fullName
    clientType
    status   
    primaryContact {
      firstName
      lastName
    }
    address {
      country
    }
    # any other set of properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

<pre class="language-graphql"><code class="lang-graphql">{   
# more filters available, see SubClientQueryInput in API schema
<strong>  "input": {
</strong>    "clientType": "INDIVIDUAL",
    "status": "ACTIVE",
    "firstName": "John",
    "lastName": "Smith",
    "address": { 
      "country": "AU" 
    }
  }
}
</code></pre>

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "subClients": [
      {
        "id": "5fb314cb9224595df522db61",
        "fullName": "John Smith",
        "clientType": "INDIVIDUAL",
        "status": "ACTIVE",
        "primaryContact": {
          "firstName": "John",
          "lastName": "Smith"
        },
        "address": {
          "country": "AU"
        }
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}


# Payouts

Disburse your money to a third party bank account

You can [create payouts](/moving-funds/payouts/withdraw-funds) via the `createWithdrawal` mutation.

You can [retrieve](/moving-funds/payouts/query-withdrawals) your payouts via the `withdrawals` query.

Sometimes you'd need to understand the supported delivery methods using the [availableDeliveryMethods](/moving-funds/recipients/delivery-methods) query.

If you get instructed by another financial institution then you must submit their details too.

If the payouts didn't pass compliance we would reject it with a proper rejection code and descriptive message.


# Withdraw funds

Send money from your Flash Payments balances to Australian bank accounts or internationally per your approved use case.

To make a withdrawal, you need to execute the `createWithdrawal` mutation as below.

{% hint style="info" %}
You must have enough [balance](/accounts/master-balance) in your account for the chosen `currency` to make a withdrawal.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>const bodyJSON = {
</strong>  variables: {
    input: {
      amount: 1000,
      currency: "AUD",
      sender: {
        companyName: "Acme LLC",
        address: {
          street: "1 Jon St PORTLAND VA 54321",
          country: "US",
        },
      },
      recipient: {
        bsb: "370370",
        accountNo: "123123123",
        companyName: "Acme Pty Ltd",
        currency: "AUD",
        accountIdType: "BSB",
        address: {
          street: "1 Main St SYDNEY NSW 2000",
          country: "AU",
        },
      },
      externalReference: "invoice #1234",
      externalId: "12344321",
      idempotencyKey: "12344321",
    },
  },
  query: `
 mutation ($input: CreateWithdrawalInput!) { 
  createWithdrawal(input: $input) { 
    success code message withdrawal { 
      id status amount currency 
    } 
  } 
}`,
};  
</code></pre>

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success
    code
    message
    withdrawal {
      id
      status
      amount
      currency
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "amount": 1000,
    "currency": "AUD",
    "sender": {
      "companyName": "Acme LLC",
      "address": {
        "street": "1 Jon St PORTLAND VA 54321",
        "country": "US"
      }
    },
    "recipient": {
      "bsb": "370370",
      "accountNo": "123123123",
      "companyName": "Acme Pty Ltd",
      "currency": "AUD",
      "accountIdType": "BSB",
      "address": {
        "street": "1 Main St SYDNEY NSW 2000",
        "country": "AU"
      }
    },
    "externalReference": "invoice #1234",
    "externalId": "12344321",
    "idempotencyKey": "12344321"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createWithdrawal": {
      "success": true,
      "code": "SUCCESS",
      "message": "Withdrawal was created",
      "withdrawal": {
        "id": "6904332f42b934e1954a734e",
        "status": "INITIALISED",
        "amount": 1000,
        "currency": "AUD"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Payment reference - `externalReference`

Arbitrary text, which will be seen in the ultimate recipient's bank statement. E.g. `"invoice #123"`. Will be eventually truncated to `18` ASCII chars if delivered via Australia's old (DE, Direct Entry) payment system. However, if you choose to use the real-time NPP network, then the maximum length is `280` chars.

### Recipient - `recipient` object or  `recipientId`

You can either [pre-create recipients](/moving-funds/recipients#create-a-recipient) and provide us with the `recipientId` or submit a valid `recipient` object directly to `createWithdrawal`  as shown in the above example. We recommend the latter where possible, as you won’t need to send an extra HTTP request. Please note that a new recipient record won’t be created in this case.

{% hint style="info" %}
Please also note that the recipient's Australian `accountIdType` must be either `BSB` or `PAYID`
{% endhint %}

### Sender - `sender` object, `senderId`, `subClientId` , or neither

Just like submitting recipient information, you can either [pre-create a sender](/moving-funds/senders#create-a-sender) and provide us with the `senderId` or directly submit a valid `sender` object to `createWithdrawal` as shown in the above example. Please note that a new sender record won’t be created in the latter case.\
\
Alternatively, if your account is configured to disburse funds **on behalf of** your [sub-clients](https://developer.flash-payments.com/sub-clients), you may provide us with the `subClientId` and the withdrawal created will be linked to that sub-client. In this case the sub-client will be used as the sender and reported to the government.

To use `subClientId` as the sender for your withdrawal, please execute the `createWithdrawal` mutation as below.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      amount: 1000, 
      currency: "AUD",
      externalReference: "invoice #1234",
      recipient: {
        bsb: "370370",
        accountNo: "123123123",
        companyName: "Acme Pty Ltd",
        currency: "AUD",
        accountIdType: "BSB",
        address: {
          street: "1 Main St SYDNEY NSW 2000",
          country: "AU",
        },
      },
      subClientId: "3fbj71b1dc328d56g94g9375",
      externalId: "123443212",
      idempotencyKey: "123443212",
    },
  }, 
  query: ` 
mutation ($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success code message    
    withdrawal {
      id status amount currency    
    }  
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 mutation($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success
    code
    message
    withdrawal {
      id
      status
      amount
      currency
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 { 
    "input": {
      "amount": 1000,
      "currency": "AUD",
      "externalReference": "invoice #1234",
      "recipient": {
        "bsb": "370370",
        "accountNo": "123123123",
        "companyName": "Acme Pty Ltd",
        "currency": "AUD",
        "accountIdType": "BSB",
          "address": {
            "street": "1 Main St SYDNEY NSW 2000",
            "country": "AU"
          }
       },
      "subClientId": "3fbj71b1dc328d56g94g9375",
      "externalId": "123443212",
      "idempotencyKey": "123443212"
    }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createWithdrawal": {
      "success": true,
      "code": "SUCCESS",
      "message": "Withdrawal was created",
      "withdrawal": {
        "id": "60711af8c078ba061f623531",
        "status": "INITIALISED",
        "amount": 1000,
        "currency": "AUD"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
We are legally obliged to collect the actual sender and beneficiary details. Please do not send us intermediate organisation details such as exchanges, banks, gateways, etc.

If it is an intermediate, please see [Instiutions](#institutions) instead.

Please always send us the ultimate sender and recipient. If sending funds to yourself, please provide your own details. See the schema in [Playground](https://api.uat.flash-payments.com.au/) for other recipient details options.

If sending funds from yourself, there's an option to use your company's Flash account details as sender by default. Please consider the example below.
{% endhint %}

If your company is the ultimate sender for a withdrawal, you can skip both the `senderId` (or `sender` object) and `subClientId`. In this situation, we will use your company’s Flash account as the sender for the transaction. Please note that a new sender record will not be created in this case.

Please execute the following `createWithdrawal` mutation to use your company's Flash account details as sender.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      amount: 500, 
      currency: "AUD",
      externalReference: "invoice #123",
      recipient: {
        bsb: "370370",
        accountNo: "123123123",
        companyName: "Acme Pty Ltd",
        currency: "AUD",
        accountIdType: "BSB",
        address: {
          street: "1 Main St SYDNEY NSW 2000",
          country: "AU",
        },
      },
      externalId: "1234567890",
      idempotencyKey: "0987654321",
    },
  }, 
  query: ` 
mutation ($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success code message    
    withdrawal {
      id status amount currency
      sender {
        firstName lastName companyName    
      }  
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 mutation($input: CreateWithdrawalInput!) {
  createWithdrawal(input: $input) {
    success
    code
    message
    withdrawal {
      id
      status
      amount
      currency
      sender {
        firstName 
        lastName 
        companyName    
      }
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 { 
    "input": {
      "amount": 500,
      "currency": "AUD",
      "externalReference": "invoice #123",
      "recipient": {
        "bsb": "370370",
        "accountNo": "123123123",
        "companyName": "Acme Pty Ltd",
        "currency": "AUD",
        "accountIdType": "BSB",
          "address": {
            "street": "1 Main St SYDNEY NSW 2000",
            "country": "AU"
          }
       },
      "externalId": "1234567890",
      "idempotencyKey": "0987654321"
    }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createWithdrawal": {
      "success": true,
      "code": "SUCCESS",
      "message": "Withdrawal was created",
      "withdrawal": {
        "id": "67cb69f2ee6c254315bb1c3d",
        "status": "INITIALISED",
        "amount": 500,
        "currency": "AUD",
        "sender": {
          "firstName": "John",
          "lastName": "Smith",
          "companyName": "Smith Consulting Pty Ltd"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Instructing Institutions

An organisation that instructed you to make a withdrawal. This data is mandatory if you submit this withdrawal on behalf of another financial institution.

{% hint style="info" %}
For more information please see [Institutions](/moving-funds/institutions).
{% endhint %}

#### Using existing institutions `instructingInstitutionId`

This optional field refers to an existing `Institution` that was created earlier in the Flash Connect interface or via this API.

#### Create institutions on the fly using the `instructingInstitution` field

Optional field that allows you to provide [Institution](/moving-funds/institutions) details without pre-creating one. Once passed, Flash Payments will create the Institution for you. Before creating an institution, we will try to find an existing one:

* By `instructingInstitution.externalId` if present.
* By `instructingInstitution.businessNumber` AND `instructingInstitution.address.country`

### Callback (aka [Webhook](/basics/webhooks/adhoc-webhooks)) URI

We recommend against continuous polling for withdrawal status changes. Instead, please use `callbackUri`.

The optional `callbackUri` will be invoked several times during the processing of a withdrawal. These callbacks will usually occur soon (within several seconds) after the initial create withdrawal call - but may be delayed in some cases. The example JSON payloads can be found on the [Webhooks page](/basics/webhooks#example-payloads).

{% hint style="danger" %}
**Security note**

The callback (aka [webhook](/basics/webhooks/adhoc-webhooks)) endpoint URI can be invoked by anyone on the internet. Thus opening up a potential attack vector. See [Webhooks](/basics/webhooks/adhoc-webhooks) page to secure your data properly.
{% endhint %}


# Withdrawal statuses

Withdrawal processing statuses

1. You create a withdrawal. Your **balance goes down** by the withdrawal amount plus fee.\
   `INITIALISED`
   1. We might internally review the transaction.\
      `INITIALISED`-> <mark style="color:orange;">`REVIEWING`</mark>
   2. If review goes well it will become pending.\ <mark style="color:orange;">`REVIEWING`</mark>→ `PENDING`
   3. Otherwise it gets cancelled.\ <mark style="color:orange;">`REVIEWING`</mark>→ `CANCELLED`
2. The transaction is sent to the recipient bank for processing.\
   `INITIALISED` → `PENDING`
3. `PENDING` →
   * `CONFIRMED` - *the recipient bank has the money now*. Does not mean the beneficiary account number was credited though. Mostly ***FINAL status***. Except when bank decides to return the funds, the withdrawal gets refunded (see step 4).
   * `FAILED` - NOT FINAL status. Depending on the processing error we have three scenarios now.
     * `REFUNDED` - see step 4 below.
     * `CANCELLED` - manual action. Your **balance goes up** by the amount, Flash Payments keeps the fee. ***FINAL status.***
     * `PENDING` - rare case - retrying. Sometimes it might work. Go to item 3.
4. The recipient bank decided to return this transaction back to Flash Payments.`CONFIRMED` → `FAILED` → `REFUNDED` - usual way - automatic refunding. Your **balance goes up** by the withdrawal amount, Flash Payments keeps the fee. ***FINAL status***.

{% hint style="warning" %}
The <mark style="color:orange;">REVIEWING</mark> is an **optional** action by Flash Payments Compliance team. Occasionally we pick some transactions for extended AML/CT review. Most transactions do not ever get into the <mark style="color:orange;">REVIEWING</mark> status.
{% endhint %}

### Most common status transitions

#### The happiest path

The payout passed our automated compliance checks and was processed successfully:

`INITIALISED`→`PENDING`→`CONFIRMED`

#### Happy path

The payout was successfully processed after a manual compliance review:

`INITIALISED`→<mark style="color:orange;">`REVIEWING`</mark><mark style="color:orange;">→</mark>`PENDING`→`CONFIRMED`

#### Unhappy paths

Recipient bank accepts the payout but then returns it:

`INITIALISED`→`PENDING`→`CONFIRMED`→`FAILED`→`REFUNDED`

Recipient bank rejects the payout:

`INITIALISED`→`PENDING`→`FAILED`→`REFUNDED`

Flash Payments Compliance team rejects the payout:

`INITIALISED`→<mark style="color:orange;">`REVIEWING`</mark>→`CANCELLED`


# Withdrawal outcomes simulation

Test common payout outcomes in UAT, as you build and exercise your integration solution against the full range of real-life withdrawal flows, statuses and webhooks before going live.

To trigger a happy or unhappy path scenario, put the corresponding keyword in the `externalReference` field when you submit a withdrawal. The keyword instructs our system to automatically simulate that outcome instead of routing the withdrawal through the standard compliance and payout pipelines, which may require manual intervention by a compliance analyst.\
\
Typically, you want to adapt your system to handle the following common withdrawal scenarios:&#x20;

#### 1. Too long in the <mark style="color:orange;">REVIEWING</mark> status

If your withdrawal is in this status this means that we are doing an internal review of it. It happens occasionally when you trigger our monitoring rules. Also, this means that we have sent your Compliance Team (or else) an email message requesting more information. You must respond. In other words, if there is a delay - it's on you. Because Flash Payments delivers all your transactions in real-time 24/7.

{% hint style="info" %}
Please always provide accurate [sender](https://developer.flash-payments.com/senders#create-a-sender) and [recipient](https://developer.flash-payments.com/recipients#create-a-recipient) information, including the full address, to prevent delays associated with internal compliance reviews on our side.

Sender and recipient addresses are automatically validated when a transaction is created. If the address cannot be verified, the transaction will be flagged for review by our Compliance team, resulting in processing delays.\
To help ensure smooth and timely processing, please provide complete and accurate address details.
{% endhint %}

You can simulate the behaviour. Your `externalReference` must include this text: `HALT_AML`. For example: `"testing HALT_AML attempt 2"`. The withdrawal will get stuck in <mark style="color:orange;">`REVIEWING`</mark> forever.

#### 2. Fails AML and gets cancelled

We checked the data you sent us for withdrawal. We didn't like it. So we cancel it immediately.

You can simulate the behaviour. Your `externalReference` must include this text: `FAIL_AML`. For example: `"testing FAIL_AML attempt 4"`. The withdrawal will be cancelled next moment after you submit it.

#### 3. Passes AML and gets processed&#x20;

If our smart AML/TM checks stop your withdrawal for manual review, you can have it automatically pushed forward by including `PUSH_AML` in the `externalReference`. For example: `"testing PUSH_AML attempt 5"`.\
\
This enables the transaction to continue as if it were approved by the compliance analyst. It can be particularly useful during your integration testing activities and also help with UAT regression testing later.

Please note that the <mark style="color:orange;">`REVIEWING`</mark> status for this payout will be recorded on our end, and a `withdrawal_reviewing` webhook will be sent.

#### 4. Request for Information (RFI) is initiated by the Flash Compliance Team

Whenever our Compliance team needs more details about specific withdrawal, you’ll receive an email with a link to the RFI form. The withdrawal will sit in <mark style="color:orange;">`REVIEWING`</mark> until you respond to the RFI via the link in the email and a compliance analyst marks it satisfactory.

You can simulate the behaviour by including `SEND_RFI` text into the `externalReference` For example: `"testing SEND_RFI attempt 3"`.  The withdrawal remains in <mark style="color:orange;">`REVIEWING`</mark> until you respond to the RFI. At that point, we will review your submission and provide feedback, and then manually push the transaction forward. The primary goal of this test is to familiarize your team with our RFI process and address any questions beforehand, ensuring a smooth transition to production.

{% hint style="info" %}
Requires at least one active member with the `compliance` access role on your account. Otherwise no RFI is created, the withdrawal fails AML and gets cancelled in accordance with the `FAIL_AML` [pattern](#id-2.-fails-aml-and-gets-cancelled).
{% endhint %}

#### 5. Recipient bank rejects the money

A common scenario in the Australian domestic payment system involves a transaction that appears successful initially, but is later reversed by the recipient’s bank—sometimes days after processing. This can happen for various reasons, such as an invalid or closed account number, an account in the wrong currency, or other account-related issues.

You can simulate the behaviour. Your `externalReference` must include this text: `FAIL_ACC`. For example: `"testing FAIL_ACC attempt 8"`. The withdrawal will be completed, and next moment failed and refunded.


# Query withdrawals

#### Retrieving all your withdrawals

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript">const bodyJSON = {
<strong>  variables: {
</strong>    input: {
    },
  },
  query: `
query ($input: WithdrawalQueryInput!) {
  withdrawals(input: $input) {   
    id
    recipient {
     firstName lastName
    }
  }
}`,
};  
</code></pre>

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: WithdrawalQueryInput!) {
  withdrawals(input: $input) {
    id
    recipient {
      firstName
      lastName
    } 
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "input": {
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "withdrawals": [
      {
        "id": "5b04c62ec0bf606bf216ae21",
        "recipient": {
          "firstName": "John"
          "lastName": "Smith"
        }
      },
      {
        "id": "5b04c6bfc0bf606bf216af06",
        "recipient": {
          "firstName": "John"
          "lastName": "Smith"
        }
      },
      {
        "id": "5b04c8e3c0bf606bf216b026",
        "recipient": {
          "firstName": "John"
          "lastName": "Smith"
        }
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving some of your withdrawals

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      statuses: "CONFIRMED",
      maxCreatedAt: "2020-01-29",
    },
  },
  query: `
query ($input: WithdrawalQueryInput!) {
  withdrawals(input: $input) {   
    id createdAt 
  }
}`,
};  
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: WithdrawalQueryInput!) {
  withdrawals(input: $input) {
    id
    createdAt 
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{    
  # there are more query parameters available, see the API schema
  "input": {
    "statuses": "CONFIRMED",
    "maxCreatedAt": "2020-01-29"
  }  
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "withdrawals": [
      {
        "id": "5b04c62ec0bf606bf216ae21",
        "createdAt": "2020-01-17T07:21:20.247Z"
      },
      {
        "id": "5b04c6bfc0bf606bf216af06",
        "createdAt": "2018-08-13T05:45:28.698Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving a single withdrawal

{% tabs %}
{% tab title="JavaScript" %}

```graphql
const bodyJSON = {
  variables: {
    input: "5b04c62ec0bf606bf216ae21",
  },
  query: `
query ($input: ID) {  
  withdrawal(id: $input) {
    status createdAt amount
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  withdrawal(id: $input) {
    status
    createdAt
    amount
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{
  # there are more query parameters available, see the API schema
  "input": "5b04c62ec0bf606bf216ae21"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "withdrawal": {
      "status": "CONFIRMED",
      "createdAt": "2020-01-17T07:21:20.247Z",
      "amount": 1000
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Rejection codes

How to handle a payout rejection

If your withdrawal is canceled (aka rejected) by our AML and Compliance team, you'll receive the  [withdrawal\_cancelled](https://developer.flash-payments.com/webhooks#withdrawal_cancelled) webhook containing both a rejection code (`rejectCode`) and a manually written rejection reason (`statusMessage`). You can find the same two properties within the [`withdrawal`](/moving-funds/payouts/query-withdrawals) GraphQL type.

Here is a current list of all possible `rejectCode`s, but please note this list **can be extended with time**.

```
CANCELLATION_REQUESTED_BY_PARTICIPANT
CANCELLATION_BY_RECIPIENT_FI
COMPLIANCE_DECLINED
COMPLIANCE_DECLINED_EXTERNAL
SENDER_INADEQUATE_DATA
SENDER_INVALID_ADDRESS
SENDER_INCOMPLETE_ADDRESS
RECIPIENT_INADEQUATE_DATA
RECIPIENT_INVALID_ADDRESS
RECIPIENT_INCOMPLETE_ADDRESS
DATA_ENQUIRY_TIME_ELAPSED
DATA_ENQUIRY_RESPONSE_INADEQUATE
SOURCE_OF_FUNDS_INADEQUATE
DUPLICATE_TRANSACTION
TECHNICAL_ISSUE
RECIPIENT_ACCOUNT_CLOSED
RECIPIENT_INVALID_ACCOUNT_NUMBER
RECIPIENT_INVALID_BANK_CODE
RECIPIENT_INVALID_ACCOUNT
RECIPIENT_COUNTRY_NOT_SUPPORTED
RECIPIENT_CURRENCY_NOT_SUPPORTED
EXPIRED
```

{% hint style="danger" %}
**Please note**: `CANCELLED` is a **final** status for **any** withdrawal. \
Please do not retry a withdrawal if it was rejected by our Compliance team or by a beneficiary financial institution.

Only those withdrawals rejected with code `TECHNICAL_ISSUE` may be re-submitted as new transactions.
{% endhint %}

Please also note that while the rejection codes are set, the corresponding free text `statusMessage` will have a case-by-case human written text explaining the root cause of the cancellation. We'll try to be as descriprive as possible taking into account the legal bounds (we are not allowed by the law to disclose certain information).


# Deposits

Explains how to accept deposits programmatically

After fully registering with us, you get a BSB and a dedicated Virtual Account Number (VAN).

{% hint style="warning" %}
IMPORTANT: Your Australian VAN will be restricted to local Australian transfers. For international payments (aka FX payments), we offer different solutions.
{% endhint %}

Every deposit to your VAN would increase your Flash Payments balance.

Every deposit can trigger a [Webhooks](/basics/webhooks/regular-webhooks) notification, keeping you informed in real time

The deposit data includes the payment reference (we call it `externalReference` in this API).

By default, only you are permitted to make deposits. However, we can enable third-party deposits for your account upon request. Once enabled, your account number functions as a local collection account, allowing others to deposit funds on your behalf.

We can also enable the [sub-client](/accounts/virtual-account-numbers) feature. It allows you to programmatically create client accounts with dedicated BSB and account number for transactional purposes. You can give these bank account details to your clients to accept deposits. Once funds arrive, we will increase your account balance, and you will see a deposit with sub-client information linked to it.

To browse your deposits, you can use our [FlashConnect](https://connect.uat.flash-payments.com.au/login) interface.

{% hint style="info" %}
Tip. You can simulate and test a deposit with the FlashConnect tool in the UAT environment. Just go to the *Deposits* page and click "SEND TEST DEPOSIT".\
\
Additionally, you can test a deposit sent by your [sub-client](/accounts/virtual-account-numbers) in the UAT. Just go to the *Sub-clients* page, find the sub-client, and click "SEND TEST DEPOSIT".
{% endhint %}


# Deposit statuses

Deposit processing statuses

Upon detecting a deposit in a Flash Payments Virtual Account Number (VAN), we immediately record it as a deposit in our system.

The status of a successful deposit goes through the following lifecycle

`INITIALISED`-><mark style="color:orange;">`REVIEWING`</mark><mark style="color:orange;">→</mark>`CONFIRMED`

If you choose to reject a deposit, its status goes through the following lifecycle instead:

`INITIALISED`-><mark style="color:orange;">`REVIEWING`</mark><mark style="color:orange;">→</mark>`CONFIRMED`→`REFUNDING`→`REFUNDED`

{% hint style="warning" %}
The <mark style="color:orange;">REVIEWING</mark> is an **optional** action by Flash Payments Compliance team. Occasionally we pick some transactions for extended AML/CT review. Most transactions do not ever get into the <mark style="color:orange;">REVIEWING</mark> status.
{% endhint %}

If Flash Payments Compliance choose to reject a deposit, its status lifecycle goes through following stages:

`INITIALISED`→`REVIEWING`→`REFUNDING`→`REFUNDED`


# Query deposits

#### Query all deposits

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  },
  query: `
query ($input: DepositQueryInput!) {
  deposits(input: $input) {
    id amount currency status statusMessage externalId externalReference
    subClient {
      id fullName status clientType
    }    
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: DepositQueryInput!) {
  deposits(input: $input) {
    id
    amount
    currency
    status
    statusMessage
    externalId
    externalReference
    subClient {
      id
      fullName
      status
      clientType
    }
    createdAt
    # more fields available, see API schema
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "input": {
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "deposits": [
      {
        "id": "6053d4e0e3bc655e0598a742",
        "amount": 2000,
        "currency": "AUD",
        "status": "CONFIRMED",
        "statusMessage": "Transaction Confirmed",
        "externalId": "PR.1vcl",
        "externalReference": "FX1111",
        "subClient": null,
        "createdAt": "2021-03-18T22:32:01.010Z"
      },
      {
        "id": "6053d3319588389e1443587e",
        "amount": 40,
        "currency": "AUD",
        "status": "CONFIRMED",
        "statusMessage": "Transaction Confirmed",
        "externalId": "PR.1vci",
        "externalReference": "FX2121",
        "subClient": {
          "id": "5fb314cb9224595df522db61",
          "fullName": "John Doe",
          "status": "ACTIVE",
          "clientType": "INDIVIDUAL"
        },
        "createdAt": "2021-03-18T22:24:49.096Z"
      },
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Query deposit by ID

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "6053d4e0e3bc655e0598a742",
  },
  query: `
query ($input: ID) {  
  deposit(id: $input) {
    id 
    amount currency status statusMessage externalId externalReference createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  deposit(id: $input) {
    id
    amount
    currency
    status
    statusMessage
    externalId
    externalReference
    createdAt
    # more fields available, see API schema
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{
  # there are more query parameters available, see the API schema
  "input": "6053d4e0e3bc655e0598a742"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "deposit": {
      "id": "6053d4e0e3bc655e0598a742",
      "amount": 2000,
      "currency": "AUD",
      "status": "CONFIRMED",
      "statusMessage": "Transaction Confirmed",
      "externalId": "PR.1vcl",
      "externalReference": "KX23249",
      "createdAt": "2021-03-18T22:32:01.010Z"
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Refund deposits

Return the funds back to the original sender

#### Refund deposit by ID

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "6053d4e0e3bc655e0598a742",
    input: {
      amount: 10,
      reason: "sent by mistake",
    },
  }, 
  query: `
mutation ($id: ID!, $input: RefundDepositInput!) {
  refundDeposit(id: $id, input: $input) {
    success code message
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID!, $input: RefundDepositInput!) {
  refundDeposit(id: $id, input: $input) {
    success
    code
    message
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "id": "6053d4e0e3bc655e0598a742",
  "input": { 
    "amount": 10, 
    "reason": "sent by mistake"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "refundDeposit": {
      "success": true,
      "code": "REFUND_SENT",
      "message": "Refund initiated successfully"
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Senders

CRUD queries for your payment senders

We are legally obliged to collect the actual sender details. Please, do not send us an intermediate organisation details such as exchanges, banks, gateways, etc.

If you want to receive funds from yourself then please provide your own details. See the DOCS in [Playground](https://api.uat.flash-payments.com.au/) for other sender details options.

* `sender` and `senders` queries - **read** your address book.
* `createSender` - **creates** a new record in the Flash Payments database.
* `updateSender` - **updates** an existing sender.
* `deleteSender` - **deletes** an existing sender.

#### Query single sender

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "59f2733f2519e236edab0efe",
  },
  query: `
query ($input: ID) {
  sender(id: $input) {
    email firstName lastName companyName
    address {
      country
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  sender(id: $input) {
    email
    firstName
    lastName
    companyName
    address {
      country
    }
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": "59f2733f2519e236edab0efe"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "sender": {
      "email": "john@example.com",
      "firstName": "John",
      "lastName": "Smith",
      "companyName": null,
      "address": {
        "country": "GB"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Query multiple senders

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      email: "john@example.com",
    },
  },
  query: `
query ($input: RecipientQueryInput!) {
  senders(input: $input) {
    email firstName lastName companyName
    address {
      country
    } 
  } 
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: SenderQueryInput!) {
  senders(input: $input) {
    email
    firstName
    lastName
    companyName
    address {
      country
    }
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "email": "john@example.com" 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "senders": [
      {
        "email": "john@example.com",
        "firstName": "John",
        "lastName": "Smith",
        "companyName": null,
        "address": {
          "country": "GB"
        }
      },
      {
        "email": "john@example.com",
        "firstName": null,
        "lastName": null,
        "companyName": "Acme Inc",
        "address": {
          "country": "US"
        }
      },
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Create a sender

{% hint style="info" %}
In addresses the `suburb` field is an Australian suburb. For other countries you should put the city (e.g. Manila or London) or any other small administrative area name.

If you find it technically challenging to submit all components of the sender’s address, we would appreciate it if you could at least collect the sender’s country along with a complete address string that includes the postcode and put them into the `country` and `street` fields, respectively. In this case, you can skip the `postcode`, `suburb`, and `state` fields, and the sender record will still be created.

Please note that the `street` field is mandatory for Australian addresses.
{% endhint %}

{% hint style="info" %}
The date of birth (`dob`) is not mandatory. However, if it is not provided, your transactions may undergo additional compliance reviews, which can lead to longer processing times—potentially several hours or days instead of seconds. Please also be aware that this may result in additional fees to cover the extra effort involved.
{% endhint %}

#### Create an Individual sender

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      firstName: "Malcolm",
      lastName: "Jez",
      dob: "2000-01-01",
      email: "malcolm@example.com",
      mobile: "+61 4123456789",
      address: {
        street: "1 Test St",
        suburb: "London",
        state: "TST",
        country: "GB",
        postcode: "2000",
      },
      idDoc: {
        type: "passport",
        docNumber: "GB1234321",
        issuer: "His Majesty’s Passport Office (HMPO)",
        issueDate: "1990-01-01",
        expiryDate: "2045-01-01",
        country: "GB",
      },
    },
  },
  query: `
mutation ($input: SenderInput!) {
  createSender(input: $input) {
    success code message
    sender {
      id nickName
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: SenderInput!) {
  createSender(input: $input) {
    success code message
    sender {
      id 
      nickName
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "firstName": "Malcolm",
    "lastName": "Jez",
    "dob": "2000-01-01",
    "email": "malcolm@example.com",
    "mobile": "+61 4123456789", 
    "address": {
      "street": "1 Test St", 
      "suburb": "London", 
      "state": "TST", 
      "country": "GB", 
      "postcode": "2000"
    },
    "idDoc": {
      "type": "passport", 
      "docNumber": "GB1234321", 
      "issuer": "His Majesty’s Passport Office (HMPO)", 
      "issueDate": "1990-01-01", 
      "expiryDate": "2045-01-01", 
      "country": "GB"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createSender": {
      "success": true,
      "code": "CREATED",
      "message": "New sender created",
      "sender": {
        "id": "686393e689c1fb1b255cac5c",
        "nickName": "MalcolmJez"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Create a Company  sender

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      companyName: "Acme Pte Ltd",
      businessNumber: "12345678912",
      email: "acme@example.com",
      mobile: "+61 4123456789",
      address: {
        street: "1 Test St",
        suburb: "London",
        state: "TST",
        country: "GB",
        postcode: "2000",
      },
      idDoc: {
        type: "certificateOfRegistration",
        docNumber: "GB-REG-987654321",
        issuer: "Companies House",
        issueDate: "1990-01-01",
        expiryDate: "2100-01-01",
        country: "GB",
      },
    },
  },
  query: `
mutation ($input: SenderInput!) {
  createSender(input: $input) {
    success code message 
    sender { 
      id nickName    
    }  
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: SenderInput!) {
  createSender(input: $input) {
    success code message
    sender {
      id 
      nickName
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "companyName": "Acme Pte Ltd", 
    "businessNumber": "12345678912", 
    "email": "acme@example.com", 
    "mobile": "+61 4123456789", 
    "address": {
      "street": "1 Test St", 
      "suburb": "London", 
      "state": "TST", 
      "country": "GB", 
      "postcode": "2000"
    },
    "idDoc": {
      "type": "certificateOfRegistration", 
      "docNumber": "GB-REG-987654321", 
      "issuer": "Companies House", 
      "issueDate": "1990-01-01", 
      "expiryDate": "2100-01-01", 
      "country": "GB"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```
{
  "data": {
    "createSender": {
      "success": true,
      "code": "CREATED",
      "message": "New sender created",
      "sender": {
        "id": "68638e6989c1fb1b255ca9c3",
        "nickName": "Acme Pte L"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Update sender

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      firstName: "Malcolm",
      lastName: "Jez The Second",
      dob: "2000-01-01",
      email: "malcolm@example.com",
      mobile: "+61 4123456789",
      address: {
        street: "1 Test St",
        suburb: "London",
        state: "TST",
        country: "GB",
        postcode: "2000",
      },
    },
  },
  query: `
mutation ($input: SenderInput!) {
  updateSender(input: $input) {
    success code message
    sender {
      id lastName
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID, $input: SenderInput!) {
  updateSender(id: $id, input: $input) {
    success code message
    sender {
      id 
      lastName
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "id": "686393e689c1fb1b255cac5c",
  "input": {
    "firstName": "Malcolm",
    "lastName": "Jez The Second",
    "dob": "2000-01-01",
    "email": "malcolm@example.com",
    "mobile": "+61 4123456789", 
    "address": {
      "street": "1 Test St", 
      "suburb": "London", 
      "state": "TST", 
      "country": "GB", 
      "postcode": "2000"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "updateSender": {
      "success": true,
      "code": "UPDATED",
      "message": "Sender 686393e689c1fb1b255cac5c updated.",
      "sender": {
        "id": "686393e689c1fb1b255cac5c",
        "lastName": "Jez The Second"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Delete sender

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "686393e689c1fb1b255cac5c",
  },
  query: `
mutation ($input: ID) {
  deleteSender(id: $input) {
    success code message
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: ID) {
  deleteSender(id: $input) {
    success 
    code 
    message
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```
{
  "input": "686393e689c1fb1b255cac5c"
}

```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "deleteSender": {
      "success": true,
      "code": "SUCCESS",
      "message": "Sender deleted"
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Recipients

CRUD queries for your payment recipients

We are legally obliged to collect the actual recipient details. Please, do not send us an intermediate organisation details such as exchanges, banks, gateways, etc.

Please, send us the final funds recipient. If sending to self then please provide your own details. See the DOCS in [Playground](https://api.uat.flash-payments.com.au/) for other recipient details options.

* `recipient` and `recipients` queries - **read** your address book.
* `createRecipient` - **creates** a new record in the Flash Payments database.
* `updateRecipient` - **updates** an existing recipient.
* `deleteRecipient` - **deletes** an existing recipient.

#### Query a single recipient

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "6b04c62ec0bf606bf216ae21",
  },
  query: `
query ($input: ID) {
  recipient(id: $input) {
    accountIdType currency country email
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  recipient(id: $input) {
    accountIdType
    currency
    country
    email
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```
{
  "input": "6b04c62ec0bf606bf216ae21"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "recipient": {
      "accountIdType": "ACC NO",
      "currency": "USD",
      "country": "AU",
      "email": "john@example.com"
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Query multiple recipients

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript">const bodyJSON = {
  variables: {
    input: {
      currency: "USD",
    },
  },
  query: `
query ($input: RecipientQueryInput!) {
  recipients(input: $input) {
    accountIdType currency country email
  } 
<strong>}`,
</strong>};
</code></pre>

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: RecipientQueryInput!) {
  recipients(input: $input) {
    accountIdType
    currency
    country
    email
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{
  "input": { 
    "currency": "USD"
  }
}  
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "recipients": [
      {
        "accountIdType": "ACC NO",
        "currency": "USD",
        "country": "AU",
        "email": "john@example.com"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Create a recipient

{% hint style="info" %}
In addresses the `suburb` field is an Australian suburb. For other countries you should put the city (e.g. Manila or London) or any other small administrative area name.

If you find it technically challenging to submit all components of the recipients’s address, we would appreciate it if you could at least collect the recipients’s country along with a complete address string that includes the postcode and put them into the `country` and `street` fields, respectively. In this case, you can skip the `postcode`, `suburb`, and `state` fields, and the recipient record will still be created.&#x20;

Please note that the `street` field is mandatory for Australian addresses.
{% endhint %}

#### Create an Individual recipient

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      firstName: "John",
      lastName: "Malkovich",
      dob: "1987-06-05",
      accountIdType: "BSB",
      currency: "AUD",
      bsb: "370370",
      accountNo: "12341234",
      email: "john@example.com",
      address: {
        street: "22 Woolooware Rd",
        suburb: "Woolooware",
        state: "NSW",
        country: "AU",
        postcode: "2230",
      },
    },
  },
  query: `
mutation ($input: RecipientInput!) {
  createRecipient(input: $input) {
    success code message 
    recipient {
      id nickName accountIdType currency email
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: RecipientInput!) {
  createRecipient(input: $input) {
    success code message
    recipient {
      id nickName accountIdType currency email
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
    "firstName": "John",
    "lastName": "Malkovich",
    "dob": "1987-06-05",
    "accountIdType": "BSB",
    "currency": "AUD",
    "bsb": "370370",
    "accountNo": "12341234",
    "email": "john@example.com",
    "address": {
      "street": "22 Woolooware Rd",
      "suburb": "Woolooware",
      "state": "NSW",
      "country": "AU",
      "postcode": "2230"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createRecipient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Recipient created",
      "recipient": {
        "id": "6859c06eaa36ba8534d974f1",
        "nickName": "JohnMalkov",
        "accountIdType": "BSB",
        "currency": "AUD",
        "email": "john@example.com"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Create a Company recipient

{% tabs %}
{% tab title="JavaScript" %}

```graphql
const bodyJSON = {
  variables: {
    input: {
      companyName: "Acme Pty Ltd",
      accountIdType: "BSB",
      currency: "AUD",
      bsb: "370370",
      accountNo: "12341234",
      email: "john@example.com",
      address: {
        street: "22 Woolooware Rd",
        suburb: "Woolooware",
        state: "NSW",
        country: "AU",
        postcode: "2230",
      },
    },
  },
  query: `
mutation ($input: RecipientInput!) {
  createRecipient(input: $input) {
    success code message 
    recipient {
      id nickName accountIdType currency email
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: RecipientInput!) {
  createRecipient(input: $input) {
    success code message
    recipient {
      id nickName accountIdType currency email
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
    "companyName": "Acme Pty Ltd",
    "accountIdType": "BSB",
    "currency": "AUD",
    "bsb": "370370",
    "accountNo": "12341234",
    "email": "john@example.com",
    "address": {
      "street": "22 Woolooware Rd",
      "suburb": "Woolooware",
      "state": "NSW",
      "country": "AU",
      "postcode": "2230"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createRecipient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Recipient created",
      "recipient": {
        "id": "6859ca4baa36ba8534d97da1",
        "nickName": "Acme Pty L",
        "accountIdType": "BSB",
        "currency": "AUD",
        "email": "john@example.com"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Update recipient

{% hint style="info" %}
Please note the recipient's`accountIdType`can't be changed
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "5ba89a6b35a2b327b81ffc3b",
    input: {
      nickName: "JohnM",
      firstName: "John",
      lastName: "Malkovich",
      accountIdType: "BSB",
      currency: "AUD",
      bsb: "370370",
      accountNo: "12341234",
      email: "john@example.com",
      address: {
        street: "22 Woolooware Rd",
        suburb: "Woolooware",
        state: "NSW",
        country: "AU",
        postcode: "2230",
      },
    },
  },
  query: `
mutation ($id: ID, $input: RecipientInput!) {
  updateRecipient(id: $id, input: $input) {
    success code message  
    recipient {
      id nickName    
    }
  }
}`,
};  
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID, $input: RecipientInput!) {
  updateRecipient(id: $id, input: $input) {
    success
    code
    message
    recipient {
      id
      nickName
      # there are many other properties
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "id": "5ba89a6b35a2b327b81ffc3b",
  "input":{
    "nickName": "JohnM",
    "firstName": "John",
    "lastName": "Malkovich",
    "accountIdType": "BSB",
    "currency": "AUD",
    "bsb": "370370",
    "accountNo": "12341234",
    "email": "john@example.com",
    "address": {
      "street": "22 Woolooware Rd",
      "suburb" : "Woolooware",
      "state": "NSW",
      "country": "AU",
      "postcode": "2230"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createRecipient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Recipient updated",
      "recipient": {
        "id": "5ba89a6b35a2b327b81ffc3b",
        "nickName": "JohnM"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Delete recipient

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "6b04c62ec0bf606bf216ae21",
  },
  query: `
mutation ($input: ID) {
  deleteRecipient(id: $input) {
    success code message
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: ID) {
  deleteRecipient(id: $input) {
    success 
    code 
    message
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{
  "input": "6b04c62ec0bf606bf216ae21"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "deleteRecipient": {
      "success": true,
      "code": "SUCCESS",
      "message": "Recipient deleted"
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Delivery methods

Different countries support different account types, transfer mechanisms, payment delivery methods.

Please verify that you have all the required data to initiate a successful payment transfer.

#### List all the available payment delivery methods

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  }, 
  query: `
query ($input: AvailableDeliveryMethodsInput!) {
  availableDeliveryMethods(input: $input) {
    country currency method requiredFields
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AvailableDeliveryMethodsInput!) {
  availableDeliveryMethods(input: $input) {
    country
    currency
    method
    requiredFields
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{ 
  "input": {
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "availableDeliveryMethods": [
      {
        "country": "AE",
        "currency": "AED",
        "method": "ACC_NO",
        "requiredFields": [
          "bic",
          "accountNo"
        ]
      },
      {
        "country": "AT",
        "currency": "EUR",
        "method": "IBAN",
        "requiredFields": [
          "bic",
          "iban"
        ]
      },
...
```

{% endtab %}
{% endtabs %}

The response above means that if you want to send euros to Austria (AT) then you'd need a BIC (aka SWIFT) code **and** an IBAN.

#### List some of the delivery methods

{% tabs %}
{% tab title="JavaScript" %}

```graphql
const bodyJSON = {
  variables: {
    input: {
      country: "FR",
      currency: "EUR",
    },
  }, 
  query: `
query ($input: AvailableDeliveryMethodsInput!) {
  availableDeliveryMethods(input: $input) {
    country currency method requiredFields
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AvailableDeliveryMethodsInput!) {
  availableDeliveryMethods(input: $input) {
    country
    currency
    method
    requiredFields
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```
{
  "input": {
    "country": "FR", 
    "currency": "EUR" 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "availableDeliveryMethods": [
      {
        "country": "FR",
        "currency": "EUR",
        "method": "ACC_NO",
        "requiredFields": [
          "bic",
          "accountNo"
        ]
      },
      {
        "country": "FR",
        "currency": "EUR",
        "method": "IBAN",
        "requiredFields": [
          "bic",
          "iban"
        ]
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

The response above means that to send euros to France (FR) you have to have ether of:

* BIC and an account number, or
* BIC and an IBAN.


# Institutions

CRUD queries for Institutions

### Instructing Institution

`Institution` entity is a piece of information about the party who instructed you to make the withdrawal. This data is important for compliance within Australia. This is not the sender. If there is no other institution who has instructed this withdrawal, leave this blank and your own details will be used for compliance and auditing purposes.&#x20;

<figure><img src="/files/N48UVfURKBf37aQGHyCV" alt=""><figcaption><p>Institution explanation</p></figcaption></figure>

#### Creating institutions

* via Flash Connect (you can copy an ID of an existing Institution).&#x20;
* via API by invoking `createInstitution` mutation.&#x20;
* by providing `instructingInstitution` object into `createWithdrawal` mutation.&#x20;

{% hint style="warning" %}
Please avoid creating multiple Institutions for the same organisation because they are used for compliance reporting and subject to review.&#x20;
{% endhint %}

{% hint style="info" %}
Before creating or updating an institution we will try to find an existing one by:&#x20;

* By `instructingInstitution.externalId`
* By `instructingInstitution.businessNumber` AND `instructingInstitution.address.country`
* By `instructingInstitution.legalName` AND `instructingInstitution.address.country`
  {% endhint %}

### Creating institution example

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      legalName: "Intermediate Institution Ltd",
      businessNumber: "A39477669937",
      address: {
        postcode: "2000",
        street: "203 Business Street",
        country: "AU",
        state: "NSW",
        suburb: "Sydney",
    },
  },
},
query: `
mutation ($input: InstitutionInput!) {
  createInstitution(input: $input) {
    success code message    
    institution {     
      id    
    }  
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: InstitutionInput!) {
  createInstitution(input: $input) {
    success
    code
    message
    institution {
      id
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 "input": {
    "legalName": "Intermediate Institution Ltd",
    "businessNumber": "A39477669937",
    "address": {
      "postcode": "2000",
      "street": "203 Business Street",
      "country": "AU",
      "state": "NSW",
      "suburb": "Sydney"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createInstitution": {
      "success": true,
      "code": "INSTITUTION_CREATED",
      "message": "Institution created",
      "institution": {
        "id": "65570da4f176682c5e412552"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

**Updating institutions**

You can update an existing institution by invoking the `updateInstitution` mutation with its `id`. The input always requires `legalName` and `address`; every other field is optional. Only the non-empty fields you send are applied — omitted or empty optional fields keep their current values (you can't blank out a field by sending an empty value), and the `address` you provide is merged over the stored one.\
If nothing actually changes, the update is a no-op and returns `NO_CHANGES`; the stored data and its compliance status are left untouched.

{% hint style="info" %}
Before persisting a change, we check whether a different institution already exists with the same:

* `externalId` if present, or
* `businessNumber` AND `address.country`
* `legalName` AND `address.country`

If a match is found, the update is rejected with the `INSTITUTION_ALREADY_EXISTS` code.
{% endhint %}

#### Updating institution example

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "65570da4f176682c5e412552",
    input: {
      legalName: "Intermediate Institution Ltd",
      businessNumber: "A39477669937",
      address: {
        postcode: "2000",
        street: "203 Business Street",
        country: "AU",
        state: "NSW",
        suburb: "Sydney",
    },
  },
},
query: `
mutation ($id: ID, $input: InstitutionInput!) {
  updateInstitution(id: $id, input: $input) {
    success code message    
    institution {     
      id    
    }  
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($id: ID, $input: InstitutionInput!) {
  updateInstitution(id: $id, input: $input) {
    success
    code
    message
    institution {
      id
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "id": "65570da4f176682c5e412552",
  "input": {
    "legalName": "Intermediate Institution Ltd",
    "businessNumber": "A39477669937",
    "address": {
      "postcode": "2000",
      "street": "203 Business Street",
      "country": "AU",
      "state": "NSW",
      "suburb": "Sydney"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "updateInstitution": {
      "success": true,
      "code": "UPDATED",
      "message": "Institution 65570da4f176682c5e412552 updated.",
      "institution": {
        "id": "65570da4f176682c5e412552"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Quote

Quote the current bid and ask for a currency pair and size.

## Reference/indicative quotes

Consider requesting an **indicative/reference** quote to understand the current currency trading rates before deciding to take action. Please be aware that market makers are not required to honor indicative quotes.

Paste this query to the API Playground to request an indicative quote.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "USD",
      size: "10000",
      currency: "AUD",
    },
  },
  query: `
query ($input: QuoteInput!) { 
  quote(input: $input) {   
    bid ask symbol timestamp inverted 
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

<pre class="language-graphql"><code class="lang-graphql"><strong>query($input: QuoteInput!) {
</strong>  quote(input: $input) {
    bid
    ask
    symbol
    timestamp
    inverted
  }
}
</code></pre>

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "fromCurrency": "AUD", 
    "toCurrency": "USD", 
    "size": "10000", 
    "currency": "AUD"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "quote": {
      "bid": 0.61104,
      "ask": 0.62077,
      "symbol": "USDAUD",
      "timestamp": "2018-08-13T07:54:54.993Z",
      "inverted": true
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Multiple reference/indicative quotes with a single HTTP request

If you send us too many API request - the system will automatically block you for a short period of time. To avoid that, we recommend sending multiple queries within a single HTTP request.

Typically, you want to collect several dozen FX prices with a sincle API call. The GraphQL allows sending multiple queries within one HTTP request. Below is an example of such query:

{% tabs %}
{% tab title="GraphQL Query" %}

```graphql
query {
  AUDUSD: quote(input: { fromCurrency: AUD, toCurrency: USD, size: 1000 }) { bid ask symbol }
  AUDEUR: quote(input: { fromCurrency: AUD, toCurrency: EUR, size: 1000 }) { bid ask symbol }
  AUDGBP: quote(input: { fromCurrency: AUD, toCurrency: GBP, size: 1000 }) { bid ask symbol }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "AUDUSD": {
      "bid": 0.76508,
      "ask": 0.76922,
      "symbol": "AUDUSD"
    },
    "AUDEUR": {
      "bid": 0.64588,
      "ask": 0.64942,
      "symbol": "AUDEUR"
    },
    "AUDGBP": {
      "bid": 0.57091,
      "ask": 0.57404,
      "symbol": "AUDGBP"
    }
  }
}
```

{% endtab %}
{% endtabs %}

Here is a JavaScript code to build and send the above query string:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const fromCurrencies = ["AUD"];
const toCurrencies = ["USD", "EUR", "GBP"];
const size = 1000;

let query = "";
for (const from of fromCurrencies) 
  for (const to of toCurrencies) 
    query += `${from}${to}: quote(input: { fromCurrency: ${from}, toCurrency: ${to}, size: ${size} }) { bid ask symbol }\n`;

query = "query {\n" + query + "\n}";

const response = await fetch("https://api.uat.flash-payments.com.au", { 
  method: "POST",
  headers: {
    authorization: "Bearer " + YOUR_TOKEN,
    "content-type": "application/json",
  },
  body: JSON.stringify({ query }),
});
const { data } = await response.json();
```

{% endtab %}
{% endtabs %}

Please be mindful. Do not fetch the rates you do not need. If there will be hundreds of `quote` queries within one HTTP request - it might timeout (take longer than 60 seconds).

## Tradable quote

In contrast to an indicative quote, a **tradable** quote is guaranteed by the market maker.

Paste this query to the GraphQL Playground to request a tradable quote. It is important to consider the `expireAt` date and time, and preserve the `id` of a tradable quote for future `createPayment` and `createConversion` calls.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "USD",
      size: "10000",
      currency: "AUD",
      tradable: true,
    },
  },
  query: `
query ($input: QuoteInput!) { 
  quote(input: $input) {   
    bid ask symbol timestamp inverted expireAt id
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: QuoteInput!) {
  quote(input: $input) {
    bid
    ask
    symbol
    timestamp
    inverted
    expireAt
    id
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
    "fromCurrency": "AUD", 
    "toCurrency": "USD", 
    "size": "10000", 
    "currency": "AUD",
    "tradeable": true 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "quote": {
      "bid": 0.61339,
      "ask": 0.63101,
      "symbol": "AUDUSD",
      "timestamp": "2025-03-04T01:53:08.829Z",
      "inverted": false,
      "expireAt": "2025-03-04T01:55:08.830Z",
      "id": "67c65d04e5086d18751617ba"
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Conversions

Convert between your multi-currency balances

If you use our multi-currency feature, you can exchange currency and [convert funds](https://developer.flash-payments.com/conversions/convert-funds) between your master accounts in real-time.&#x20;

Conversion fees are detailed in your contract and vary based on your use case and risk assessment.


# Convert funds

Convert between your multi-currency balances

To convert between, say, `AUD` and `EUR` you should:

1. Request a tradeable quote with applicability: CONVERSION.
2. Retrieve the quote ID from the response.
3. Reference the quote ID when creating the conversion.

Get a tradable quote ID:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "EUR",
      size: "10000",
      currency: "AUD",
      tradeable: true,
      applicability: "CONVERSION",
    },
  },
  query: `
query ($input: QuoteInput!) {
  quote(input: $input) {
    id bid ask symbol timestamp inverted expireAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: QuoteInput!) {
  quote(input: $input) {
    id
    bid
    ask
    symbol
    timestamp
    inverted
    expireAt
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "fromCurrency": "AUD", 
    "toCurrency": "EUR", 
    "size": "10000", 
    "currency": "AUD",
    "tradeable": true,
    "applicability": "CONVERSION"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "quote": {
      "id": "685369cf85f7cb51fb4ae2eb",
      "bid": 0.55663,
      "ask": 0.57153,
      "symbol": "AUDEUR",
      "timestamp": "2025-06-19T01:37:19.418Z",
      "inverted": false,
      "expireAt": "2025-06-19T01:39:19.419Z"
    }
  }
}
```

{% endtab %}
{% endtabs %}

Convert funds:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
        note: "for major client",
        externalId: "561402",
        quoteId: "6854dcffaa36ba8534d5f8e2",
        callbackUri: "https://example.com/my-webhook/endpoint/",
    },
  },
  query: `
mutation ($input: ConversionInput!) {
  createConversion(input: $input) {    
    success code message 
    conversion { 
      id fromCurrency toCurrency currencyPair fromAmount toAmount rate note 
      status statusMessage callbackUri externalId createdAt updatedAt 
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: ConversionInput!) {
  createConversion(input: $input) {
    success code message
    conversion {
      id fromCurrency toCurrency currencyPair fromAmount toAmount rate note
      status statusMessage callbackUri externalId createdAt updatedAt
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "note": "for major client",
    "externalId": "561402",
    "quoteId": "6854dcffaa36ba8534d5f8e2",
    "callbackUri": "https://example.com/my-webhook/endpoint/"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "createConversion": {
      "success": true,
      "code": "CREATED",
      "message": "Conversion successfully created",
      "conversion": {
        "id": "6711f0a7b549a701ebeb02ac",
        "fromCurrency": "EUR",
        "toCurrency": "AUD",
        "currencyPair": "AUDEUR",
        "fromAmount": 101,
        "toAmount": 159.81,
        "rate": 0.63199,
        "note": "for major client",
        "status": "PENDING",
        "statusMessage": "Awaiting execution",
        "callbackUri": "https://example.com/my-webhook/endpoint/",
        "externalId": "561402",
        "createdAt": "2024-10-18T05:22:47.433Z",
        "updatedAt": "2024-10-18T05:22:47.433Z"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Query conversions

You can query all your past conversions

#### Retrieving all your conversions

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  },
  query: `
query ($input: ConversionQueryInput!) {
  conversions(input: $input) {   
    id fromCurrency toCurrency rate 
  }
}`,
};    
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 query($input: ConversionQueryInput!) {
  conversions(input: $input) {
    id
    fromCurrency
    toCurrency
    rate
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "conversions": [
      {
        "id": "6b04c62ec0bf606bf216ae21",
        "fromCurrency": "AUD",
        "toCurrency": "EUR",
        "rate": 0.71
      },
      {
        "id": "6b04c6bfc0bf606bf216af06",
        "fromCurrency": "AUD",
        "toCurrency": "USD",
        "rate": 0.70
      },
      {
        "id": "6b04c8e3c0bf606bf216b026",
        "fromCurrency": "EUR",
        "toCurrency": "AUD",
        "rate": 0.71
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving some of your conversions

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      statuses: "CONVERTED",
      toCurrencies: ["EUR","USD"], 
    },
  },
  query: `
query ($input: ConversionQueryInput!) {
  conversions(input: $input) {   
    id fromCurrency toCurrency rate 
  }
}`,
};    
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ConversionQueryInput!) {
  conversions(input: $input) {
    id
    fromCurrency
    toCurrency
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "statuses": "CONVERTED",
    "toCurrencies": ["EUR","USD"]
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "conversions": [
      {
        "id": "6833ad9b4e94acce5d4a031b",
        "fromCurrency": "AUD",
        "toCurrency": "USD"
      },
      {
        "id": "678a18bb2879c374b378ee71",
        "fromCurrency": "AUD",
        "toCurrency": "EUR"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving a single conversion by ID

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "6b04c62ec0bf606bf216ae21",
  },
  query: `
query ($input: ID) {  
  conversion(id: $input) {
    status createdAt fromAmount toAmount 
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  conversion(id: $input) {
    status
    createdAt
    fromAmount
    toAmount
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": "6b04c62ec0bf606bf216ae21"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "conversion": {
      "status": "CONVERTED",
      "createdAt": "2024-08-13T05:45:28.698Z",
      "fromAmount": 1000,
      "toAmount": 710.01
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Conversion statuses

The GraphQL schema defines statuses like this:

```graphql
enum ConversionStatus {
    INITIALISED
    PENDING
    CONVERTED
    FAILED
    CANCELLED
}
```

The status of a conversion can be any of the following:

* INITIALISED — A conversion record was created, but no further action has been taken.\
  This status typically does not occur via the API.
* PENDING — The conversion is in progress. This is the usual status immediately after creation.
* CONVERTED — The conversion completed successfully. Your balances have been updated accordingly.
* FAILED — An error occurred during the conversion. This is usually a temporary state.
* CANCELLED — The conversion was not completed and has been cancelled.\
  This action is typically performed by the Flash Payments operations team.


# FX Payments

Convert and send your balance as single instruction

What we call "FX Payment" is a fully orchestrated account to account delivery of any currency(-ies) we support. Typical examples:

* You need to send from the EU to Australia. You would have a European virtual IBAN on your name. As soon as you deposit some EUR to it - you'll see a corresponding amount of AUD on your master balance in a matter of minutes, which you'll be able to use immediately.
* You need to fund someone's overseas IBAN in Euros. You send us the AUD and give us the recipient's details either via API or via you FlashConnect back-office GUI. We orchestrate the rest.

You can [create payments](/fx/payments/send-funds). using the `createPayment` mutation.

You can [retrieve](/fx/payments/query-payments) your payments with the `payments` query.

But before you need to understand the supported delivery methods using the [availableDeliveryMethods](/moving-funds/recipients/delivery-methods) query.


# Send funds

How to send orchestrated account-to-account payments which include FX

To make a payment from AUD to a different currency, you need to execute the `createPayment` mutation as below.

{% hint style="info" %}
Note that you must have enough AUD balance to make an outbound AUD payment.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "GBP",
      size: 1000,
      currency: "AUD",
      reason: "BUSINESS",
      sourceOfFunds: "BUSINESS_FUNDS",
      externalReference: "my ref 221b",
      sender: {
        companyName: "Acme AU Ltd",
        address: {
          street: "1 Hay St SYDNEY NSW 2000",
          country: "AU",
        },
      },
      recipient: {
        iban: "GB26MIDL40051512345674",
        companyName: "Acme GB Ltd",
        currency: "GBP",
        accountIdType: "IBAN",
        address: {
          street: "1 Main St LONDON SW1A 1AA",
          country: "GB",
        },
      },
      externalId: "12344321",
      idempotencyKey: "12344321",
    },
  },
  query: ` 
mutation ($input: PaymentInput!) {
  createPayment(input: $input) {
    success code message
    payment {
      id status size
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 mutation($input: PaymentInput!) {
  createPayment(input: $input) {
    success
    code
    message
    payment {
      id
      status
      size
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "fromCurrency": "AUD",
    "toCurrency": "GBP",
    "size": 1000,
    "currency": "AUD",
    "reason": "BUSINESS",
    "sourceOfFunds": "BUSINESS_FUNDS",
    "externalReference": "my ref 221b",
    "externalId": "12344321",
    "idempotencyKey": "12344321",
    "recipient": {
      "iban": "GB26MIDL40051512345674",
      "companyName": "Acme GB Ltd",
      "currency": "GBP",
      "accountIdType": "IBAN",
      "address": {
        "street": "1 Main St LONDON SW1A 1AA",
        "country": "GB"
      }
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createPayment": {
      "success": true,
      "code": "SUCCESS",
      "message": "Scheduled for immediate execution",
      "payment": {
        "id": "60711af8c078ba061f623531",
        "status": "OPEN",
        "size": 1000
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Recipient - `recipient` object or `recipientId`

You can either [pre-create recipients](https://developer.flash-payments.com/moving-funds/recipients#create-a-recipient) and provide us with the `recipientId` or submit a valid `recipient` object directly to `createPayment` as shown in the above example. We recommend the latter where possible, as you won’t need to send an extra HTTP request. Please note that a new recipient record won’t be created in this case.

{% hint style="warning" %}
We are legally obliged to collect the actual sender and beneficiary details. Please do not send us intermediate organisation details such as exchanges, banks, gateways, etc.

If it is an intermediate, please see [Instiutions](#institutions) instead.

Please always send us the ultimate sender and recipient. If sending funds to yourself, please provide your own details. See the schema in [Playground](https://api.uat.flash-payments.com.au/) for other recipient details options.

If sending funds from yourself, there's an option to use your company's Flash account details as sender by default. Please consider the examples below.
{% endhint %}

### Sender - `sender` object, `senderId`, `subClientId` , or neither <a href="#sender-senderid-or-subclientid-or-neither" id="sender-senderid-or-subclientid-or-neither"></a>

Just like submitting recipient information, you can either [pre-create a sender](/moving-funds/senders#create-a-sender) and provide us with the `senderId` or directly submit a valid `sender` object to `createPayment` as shown in the above example. Please note that a new sender record won’t be created in the latter case.\
\
Alternatively, if your account is configured to send funds **on behalf of** your [sub-clients](https://developer.flash-payments.com/sub-clients), you may provide us with the `subClientId` and the FX payment created will be linked to that sub-client. In this case the sub-client will be used as the sender and reported to the government.

To use `subClientId` as the sender for your withdrawal, please execute the `createPayment` mutation as below.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "GBP",
      size: 1000,
      currency: "AUD",
      reason: "BUSINESS",
      sourceOfFunds: "BUSINESS_FUNDS",
      externalReference: "my ref 221b",
      subClientId: "6092360bf40f2dgc52f85cf1",
      recipient: {
        iban: "GB26MIDL40051512345674",
        companyName: "Acme GB Ltd",
        currency: "GBP",
        accountIdType: "IBAN",
        address: {
          street: "1 Main St LONDON SW1A 1AA",
          country: "GB",
        },
      },
      externalId: "123443212",
      idempotencyKey: "123443212",
    },
  },
  query: ` 
mutation ($input: PaymentInput!) {
  createPayment(input: $input) {
    success code message
    payment {
      id status size
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 mutation($input: PaymentInput!) {
  createPayment(input: $input) {
    success
    code
    message
    payment {
      id
      status
      size
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "fromCurrency": "AUD",
    "toCurrency": "GBP",
    "size": 1000,
    "currency": "AUD",
    "reason": "BUSINESS",
    "sourceOfFunds": "BUSINESS_FUNDS",
    "externalReference": "my ref 221b",
    "subClientId": "6092360bf40f2dgc52f85cf1",
    "externalId": "12344321",
    "idempotencyKey": "12344321",
    "recipient": {
      "iban": "GB26MIDL40051512345674",
      "companyName": "Acme GB Ltd",
      "currency": "GBP",
      "accountIdType": "IBAN",
      "address": {
        "street": "1 Main St LONDON SW1A 1AA",
        "country": "GB"
      }
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createPayment": {
      "success": true,
      "code": "SUCCESS",
      "message": "Scheduled for immediate execution",
      "payment": {
        "id": "60711bg8d078cb061g623531",
        "status": "OPEN",
        "size": 1000
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

If your company is the ultimate sender for an FX payment, you can skip both the `senderId` and `subClientId`. In this situation, we will use your company’s Flash account as the sender for the payment. Please note that a new sender record will not be created in this case.

Please execute the following `createPayment` mutation to use your company's Flash account details as sender.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      fromCurrency: "AUD",
      toCurrency: "GBP",
      size: 1000,
      currency: "AUD",
      reason: "BUSINESS",
      sourceOfFunds: "BUSINESS_FUNDS",
      externalReference: "my ref 2234",
      recipient: {
        iban: "GB26MIDL40051512345674",
        companyName: "Acme GB Ltd",
        currency: "GBP",
        accountIdType: "IBAN",
        address: {
          street: "1 Main St LONDON SW1A 1AA",
          country: "GB",
        },
      },
      externalId: "0123443210",
      idempotencyKey: "0000012344321000",
    },
  },
  query: ` 
mutation ($input: PaymentInput!) {
  createPayment(input: $input) {
    success code message
    payment {
      id status size
      sender {
        firstName lastName companyName
      }
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 mutation($input: PaymentInput!) {
  createPayment(input: $input) {
    success
    code
    message
    payment {
      id
      status
      size   
      sender {
        firstName 
        lastName 
        companyName
      }
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": { 
    "fromCurrency": "AUD",
    "toCurrency": "GBP",
    "size": 1000,
    "currency": "AUD",
    "reason": "BUSINESS",
    "sourceOfFunds": "BUSINESS_FUNDS",
    "externalReference": "my ref 2234",
    "externalId": "0123443210",
    "idempotencyKey": "0000012344321000",
    "recipient": {
      "iban": "GB26MIDL40051512345674",
      "companyName": "Acme GB Ltd",
      "currency": "GBP",
      "accountIdType": "IBAN",
      "address": {
        "street": "1 Main St LONDON SW1A 1AA",
        "country": "GB"
      }
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "createPayment": {
      "success": true,
      "code": "SUCCESS",
      "message": "Scheduled for immediate execution",
      "payment": {
        "id": "67d8e98caaa23286e1a1fd00",
        "status": "OPEN",
        "size": 1000,
        "sender": {
          "firstName": "John",
          "lastName": "Smith",
          "companyName": "Smith Consulting Pty Ltd"
        }
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Callback (aka [Webhook](/basics/webhooks/adhoc-webhooks)) URI

We recommend against continuous polling for payment status changes. Instead, please use `callbackUri`.

The optional `callbackUri` will be invoked several times during the processing of a payment. These callbacks will usually occur soon (within several seconds) after the initial create payment call - but may be delayed in some cases. The example JSON payloads can be found on the [Webhooks page](/basics/webhooks#example-payloads).

Please note that `toAmount` (or `fromAmount`) and other fluctuating payment properties can change during payment execution.

{% hint style="danger" %}
**Security note**

The callback (aka [webhook](/basics/webhooks/adhoc-webhooks)) endpoint URI can be invoked by anyone in the internet. Thus opening up a potential attack vector. See [Webhooks](/basics/webhooks/adhoc-webhooks) page to secure your data properly.
{% endhint %}


# Payment statuses

The GraphQL schema defines statuses like this:

```graphql
enum PaymentStatus {
  INITIALISING
  OPEN
  CLOSED
  FAILED
  CANCELLED
}
```

The status of a payment can be any of the following:

Payment Statuses:

* INITIALISING – a draft payment. It may or may not have all required information to be executed. Typically, this never happens through the API. Can be created via the [Flash Payments app](http://app.uat.flash-payments.com.au/) under certain circumstances.
* OPEN – The payment is in progress.
* CLOSED – The payment was successfully delivered.
* FAILED – An error occurred during processing.
* CANCELLED – The payment did not complete and was cancelled, usually by the Flash Payments operations team.

{% hint style="info" %}
Important to understand that the `Payment.history` is a transfer logs and is not related to payment status at all. Sometimes the history may contain half a dozen entries, however your payment will go through only two steps: `OPEN` and `CLOSED`.
{% endhint %}


# Query payments

#### Retrieving all your payments

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  },
  query: `
query ($input: PaymentQueryInput!) {
  payments(input: $input) {   
    id fromCurrency toCurrency 
  }
}`,
};  
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
 query($input: PaymentQueryInput!) {
  payments(input: $input) {
    id
    fromCurrency
    toCurrency
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "payments": [
      {
        "id": "5b04c62ec0bf606bf216ae21",
        "fromCurrency": "AUD",
        "toCurrency": "EUR"
      },
      {
        "id": "5b04c6bfc0bf606bf216af06",
        "fromCurrency": "AUD",
        "toCurrency": "USD"
      },
      {
        "id": "5b04c8e3c0bf606bf216b026",
        "fromCurrency": "EUR",
        "toCurrency": "AUD"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving some of your payments

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      statuses: "CLOSED",
      toCurrencies: ["EUR","USD"], 
    },
  },
  query: `
query ($input: PaymentQueryInput!) {
  payments(input: $input) {   
    id fromCurrency toCurrency 
  }
}`,
};    
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
  query($input: PaymentQueryInput!) {
  payments(input: $input) {
    id
    fromCurrency
    toCurrency
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
 {
  # there are more query parameters available, see the API schema
  "input": { 
    "statuses": "CLOSED",
    "toCurrencies": ["EUR","USD"]
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "payments": [
      {
        "id": "5b04c62ec0bf606bf216ae21",
        "fromCurrency": "AUD",
        "toCurrency": "EUR"
      },
      {
        "id": "5b04c6bfc0bf606bf216af06",
        "fromCurrency": "AUD",
        "toCurrency": "USD"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Retrieving a single payment

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: "5b04c62ec0bf606bf216ae21",
  },
  query: `
query ($input: ID) {  
  payment(id: $input) {
    status createdAt size
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: ID) {
  payment(id: $input) {
    status
    createdAt
    size
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```graphql
{
  # there are more query parameters available, see the API schema
  "input": "5b04c62ec0bf606bf216ae21"
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "payment": {
      "status": "CLOSED",
      "createdAt": "2018-08-13T05:45:28.698Z",
      "size": 1000
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Auto receive funds

Automatically receive and convert funds from other countries and currencies

Some customers can automatically receive funds from overseas. Meaning, if we detect an overseas deposit to the Flash Payments controlled bank account(s) then we can automatically create an inbound payment, convert funds, and top up your Flash Payments balance with AUD.

{% hint style="warning" %}
Please note that funds must be transferred from a bank account registered under your company name. If a virtual Flash sub-account is used as the beneficiary, the transfer should be made from an account in your sub-client’s name.\
\
Whenever a sub-client record is involved in the transaction, their full real-world address is always required. For your local Australian sub-clients, please ensure all address components are provided when adding a sub-client to our system.\
\
In some cases, but not always, the payment must include the specific payment reference we provide. See below for more details.
{% endhint %}

Here is how it looks step by step.

1. We would need to enable the foreign currency auto-receiving feature for you.
2. You, or your [Sub-client](/accounts/virtual-account-numbers), would have a special bank account in, say, SEPA zone. Find the details below.
   * The account number and **payment reference** depends on the currency and country you wish to deposit to. E.g. the EUR currency account is usually a British IBAN (starts with "GB").
3. You, or your [Sub-client](/accounts/virtual-account-numbers), would deposit money to it. Make sure to submit the exact **payment reference** we told you! Otherwise, your funds will be returned.
4. The Flash Payments would detect the account funding event and automatically create a EUR->AUD payment for you.
5. You would receive at least two webhook notifications - `payment_created` and `payment_complete`.
6. Your Flash Payments AUD balance would increase accordingly.

### Funding Accounts&#x20;

\
To find which foreign currency bank account you need to deposit into, please visit [FlashConnect](https://connect.uat.flash-payments.com.au/) and locate the list of supported inbound currencies and their corresponding bank account numbers. It is referred to as the **“Funding Accounts”** throughout the user interface.

{% hint style="info" %}
You can simulate and test an international inbound payment with the FlashConnect tool in the UAT environment. Just go to the *FX Payments* page and click "SEND TEST INBOUND PAYMENT".\
\
Additionally, you can test an international inbound payment sent by your [sub-client](/accounts/virtual-account-numbers) in the UAT. Just go to the *Sub-clients* page, find the sub-client, and click "SEND TEST INBOUND PAYMENT".
{% endhint %}

To find out the Funding Accounts via API please use the `fundingAccounts` query.

You should deposit your foreign currency to one of the following master accounts:

{% tabs %}
{% tab title="JavaScript" %}

```graphql
const bodyJSON = {
  variables: {
    input: {
      currencies: ["EUR","USD","HKD","CNY"],
      },
  },
  query: `
query ($input: FundingAccountQueryInput!) {
  fundingAccounts(input: $input) {
    iban accountNo accountName accountAddress bic currency externalReference
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
  query($input: FundingAccountQueryInput!) {
  fundingAccounts(input: $input) {
    iban
    accountNo
    accountName
    accountAddress
    bic
    currency
    externalReference
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": { 
    "currencies": ["EUR", "USD", "HKD", "CNY"] 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "fundingAccounts": [
      {
        "iban": "GB91 BARC 2006 0565 4685 66",
        "accountNo": "65468566",
        "bic": "BARCGB22",
        "currency": "USD",
        "externalReference": "191127-99999"
      },
      {
        "iban": "GB05 BARC 2006 0574 7412 77",
        "accountNo": "74741277",
        "bic": "BARCGB22",
        "currency": "EUR",
        "externalReference": "191127-99999"
      },
      {
        "iban": null,
        "accountNo": "87135588",
        "bic": "BARCGB22",
        "currency": "CNY",
        "externalReference": "191127-99999"
      },
      {
        "iban": "GB87 BARC 2006 0546 9946 00",
        "accountNo": "46994600",
        "bic": "BARCGB22",
        "currency": "HKD",
        "externalReference": "191127-99999"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

Your [sub-clients](/accounts/virtual-account-numbers) should deposit their foreign currency to one of the follwing virtual sub-accounts:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    sc: {
      externalId: "991188227733",
    },
    fa: {
      currencies: ["EUR","USD","CNY"],
    },
  },
  query: `
query ($sc: SubClientQueryInput!, $fa: FundingAccountQueryInput!) {
  subClients(input: $sc) {
    id externalId 
    fundingAccounts(input: $fa) {
      iban accountNo accountName accountAddress bic currency externalReference
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($sc: SubClientQueryInput!, $fa: FundingAccountQueryInput!) {
  subClients(input: $sc) {
    id
    externalId
    fundingAccounts(input: $fa) {
      iban
      accountNo
      accountName
      accountAddress
      bic
      currency
      externalReference
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "sc": { 
    "externalId": "991188227733" 
  },
  "fa": {
    "currencies": ["EUR", "USD", "CNY"] 
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "subClients": [
      {
        "id": "60a1e9e76eaedbf66964a323",
        "externalId": "991188227733",
        "fundingAccounts": [
          {
            "iban": "GB91 BARC 2006 0565 4685 66",
            "accountNo": "65468566",
            "bic": "BARCGB22",
            "currency": "USD",
            "externalReference": "210616-99999"
          },
          {
            "iban": "GB05 BARC 2006 0574 7412 77",
            "accountNo": "74741277",
            "bic": "BARCGB22",
            "currency": "EUR",
            "externalReference": "210616-99999"
          },
          {
            "iban": null,
            "accountNo": "87135588",
            "bic": "BARCGB22",
            "currency": "CNY",
            "externalReference": "210616-99999"
          },
        ]
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}


# Request for Information

Respond to compliance information requests programmatically

A Request for Information (RFI) is a compliance request raised by Flash Payments against deposits, withdrawals, or payments that require additional information before they can be released. RFIs are created on our side when a compliance review flags certain transactions — you cannot create RFIs via the API.

Each RFI carries a list of questions and a response deadline. There are two ways to respond:

* **Via the API** (this section) — receive a webhook, [query the RFI](/compliance/request-for-information/query-rfis), [answer each questio](/compliance/request-for-information/answer-rfi-questions)n with text or documents, or [decline](/compliance/request-for-information/decline-an-rfi) if you cannot comply.
* **Via the secure form** — the end user fills in the secure form sent by email ([the existing flow](https://developer.flash-payments.com/compliance/pages/wEAxvJ5gyBFgRFOvH9iv#id-4.-request-for-information-rfi-is-initiated-by-the-flash-compliance-team)). No integration required.

Both paths emit the same [lifecycle webhooks](/basics/webhooks#rfi_created), so you can mix them — for example, automate document collection but let the email form remain as a fallback.

{% hint style="info" %}
The RFI API is available to every client. There is no separate enablement step. Authentication uses your existing [API token](/basics/authentication) — no new credentials.
{% endhint %}

### What's in this section

* [RFI statuses ](/compliance/request-for-information/rfi-statuses)— the `PENDING` → `ASSESSING` → `CLOSED`  lifecycle and a `CANCELLED` case.
* [Query RFIs](/compliance/request-for-information/query-rfis) — the `rfi` and `rfis` queries.
* [Answer RFI questions](/compliance/request-for-information/answer-rfi-questions) — the `answerRfiQuestion` mutation, including file uploads.
* [Decline an RFI](/compliance/request-for-information/decline-an-rfi) — the `declineRfi` mutation.
* [RFI response codes](/compliance/request-for-information/rfi-response-codes) — all reply codes and GraphQL errors.

### Recommended integration flow

1. Subscribe to the `rfi_created`, `rfi_assessing`, `rfi_closed` and `rfi_canceled` [webhook events](/basics/webhooks#rfi_created) in your Flash Connect webhook settings.
2. On `rfi_created`, call the [`rfi`](/compliance/request-for-information/query-rfis#retrieving-a-single-rfi) query to load the questions and the linked deposits, withdrawals, or payments.
3. For each question with `answered: false`, call [`answerRfiQuestion`](/compliance/request-for-information/answer-rfi-questions) with text or files, according to the question's `fileUploadOption`.
4. When the last question is answered, the RFI moves to `ASSESSING` — you will receive `rfi_assessing`. No further action is required.
5. When the review is completed, the RFI moves to `CLOSED` and you will receive `rfi_closed`. The linked transactions are then released, or rejected with an explanatory `rejectCode`.
6. If you cannot supply the requested information, call [`declineRfi`](/compliance/request-for-information/decline-an-rfi) while the RFI is still `PENDING`. This will cancel the linked transactions being still under review.
7. Separately from your responses, we may withdraw an RFI if it is no longer needed. If that happens the RFI moves to `CANCELLED` and you receive the `rfi_cancelled` webhook — no response is required, and any linked deposits, withdrawals, or payments are left unaffected.

{% hint style="info" %}
`CANCELLED` is initiated by us, not by you — it means we withdrew the request. It is different from declining (which you initiate, and which closes the RFI as `CLOSED` and cancels the linked transactions).&#x20;
{% endhint %}

{% hint style="warning" %}
Respond before the RFI's `deadline`. If the deadline passes without a complete response, the RFI is closed and the linked transactions may be rejected.
{% endhint %}


# RFI statuses

RFI lifecycle statuses

Most common RFI status transitions follow one of these paths.

**Happy path**

`PENDING` → `ASSESSING` → `CLOSED` <br>

1. It starts when our compliance review flags one of your transactions. An RFI is created with a list of questions and a response deadline.\
   \
   Status  `PENDING` means the RFI is open for your response. \
   Answer each question via [`answerRfiQuestion`](/compliance/request-for-information/answer-rfi-questions) before `deadline`. The status stays `PENDING` until all answers are received or the deadline passes.<br>
2. The last open question is answered.\
   \
   Status `ASSESSING` means that all your answers have been received and are under our review. No action is required from you.<br>
3. The review is completed.\
   \
   Status  `CLOSED` means that the RFI is finalised. No further answers are accepted. ***Final status.***

\
**Declined or expired path**

`PENDING` → `CLOSED`

An RFI can also move to `CLOSED` directly from `PENDING` when you [decline it](/compliance/request-for-information/decline-an-rfi), or when the deadline passes without a complete response from your end.

\
**Cancelled path**

`PENDING` → `CANCELLED`  or  `ASSESSING` → `CANCELLED`&#x20;

Separately from your responses, our compliance team can withdraw an RFI when the information is no longer needed — for example the underlying transaction question was resolved another way. The RFI moves to `CANCELLED`, no further answers are accepted, and any linked deposits, withdrawals, or payments are left untouched and continue on their own lifecycle. You don't need to do anything — we notify you by email and via the `rfi_cancelled` webhook. ***Final status.***

{% hint style="info" %}
`CANCELLED` status is different from `CLOSED`. The status `CLOSED` is the outcome of a review (the linked transactions are then released or rejected). `CANCELLED` means we withdrew the request itself — the linked transactions are not affected by the cancellation.
{% endhint %}

Each transition emits a [webhook event](/basics/webhooks#rfi_created):

| Event           | Status      |
| --------------- | ----------- |
| `rfi_created`   | `PENDING`   |
| `rfi_assessing` | `ASSESSING` |
| `rfi_closed`    | `CLOSED`    |
| `rfi_cancelled` | `CANCELLED` |

**Status message**

The `statusMessage` field carries a meaningful explanation of the current status, for example "We are waiting for your replies" while `PENDING`, or "We assessed the information you provided" once `CLOSED`. The exact wording varies with the circumstances — treat it as display text, not as a value to parse.

{% hint style="info" %}
Once an RFI is `CLOSED`, the outcome is applied to the linked transactions: they are released, or rejected with an explanatory `rejectCode` (see [Rejection codes](/moving-funds/payouts/rejection-codes)). The RFI itself does not expose the review verdict.
{% endhint %}


# Query RFIs

Retrieve your RFIs and their questions

### **Retrieving a single RFI**

Use the `rfi` query with the `id` from the `rfi_created` webhook to load the questions and the linked transactions. The query returns `null` if the RFI does not exist or does not belong to you.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "61f3a2c8d1e9b7a4c5d6e7f8",
  },
  query: `
query ($id: ID!) {
  rfi(id: $id) {
    id
    status
    statusMessage
    deadline
    questions {
      questionCode
      questionText
      fileUploadOption
      answered
    }
    withdrawals { id status }
    deposits { id status }
    payments { id status }
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($id: ID!) {
  rfi(id: $id) {
    id
    status
    statusMessage
    deadline
    questions {
      questionCode
      questionText
      fileUploadOption
      answered
    }
    withdrawals { id status }
    deposits { id status }
    payments { id status }
    createdAt
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "id": "61f3a2c8d1e9b7a4c5d6e7f8"
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "rfi": {
      "id": "61f3a2c8d1e9b7a4c5d6e7f8",
      "status": "PENDING",
      "statusMessage": "We are waiting for your replies",
      "deadline": "2026-06-04T09:00:00.000Z",
      "questions": [
        {
          "questionCode": "SENDER_ID_PROOF",
          "questionText": "Sender's ID proof",
          "fileUploadOption": "PREFERRED",
          "answered": false
        },
        {
          "questionCode": "OTHER_TX_PURPOSE",
          "questionText": "Purpose of transfer",
          "fileUploadOption": "NONE",
          "answered": false
        }
      ],
      "withdrawals": [
        { "id": "61f3a2c8d1e9b7a4c5d6e7aa", "status": "REVIEWING" }
      ],
      "deposits": [],
      "payments": [],
      "createdAt": "2026-05-28T09:00:00.000Z"
    }
  }
}
```

{% endtab %}
{% endtabs %}

### **The key RFI fields**

| Field                                   | Description                                                                                                    |
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `status`                                | One of `PENDING`, `ASSESSING`, `CLOSED` — see [RFI statuses](/compliance/request-for-information/rfi-statuses) |
| `statusMessage`                         | Human-readable explanation of the current status                                                               |
| `deadline`                              | Submission deadline. Respond before it passes                                                                  |
| `questions`                             | The questions to answer. `answered` tells you which ones are still open                                        |
| `deposits` / `withdrawals` / `payments` | The transactions this RFI is gating, in the same shape as the `deposit`, `withdrawal`, and `payment` queries   |

Each question's `fileUploadOption` tells you what kind of answer it expects — see [Answer RFI questions.](/compliance/request-for-information/answer-rfi-questions)

### **Retrieving all RFIs**

Use the `rfis` query, for example to find everything still awaiting your response.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      statuses: ["PENDING"],
    },
  },
  query: `
query ($input: RfisInput) {
  rfis(input: $input) {
    id
    status
    deadline
    questions {
      questionCode
      answered
    }
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: RfisInput) {
  rfis(input: $input) {
    id
    status
    deadline
    questions {
      questionCode
      answered
    }
    createdAt
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "statuses": ["PENDING"]
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "rfis": [
      {
        "id": "61f3a2c8d1e9b7a4c5d6e7f8",
        "status": "PENDING",
        "deadline": "2026-06-04T09:00:00.000Z",
        "questions": [
          { "questionCode": "SENDER_ID_PROOF", "answered": false },
          { "questionCode": "OTHER_TX_PURPOSE", "answered": false }
        ],
        "createdAt": "2026-05-28T09:00:00.000Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

### **Filter fields on** `RfisInput`

| Field          | Description                                                                            |
| -------------- | -------------------------------------------------------------------------------------- |
| `statuses`     | Filter by one or more [RFI statuses](/compliance/request-for-information/rfi-statuses) |
| `minCreatedAt` | Return only RFIs created at or after this timestamp (ISO 8601, inclusive)              |
| `maxCreatedAt` | Return only RFIs created at or before this timestamp (ISO 8601, inclusive)             |

All filters are optional and combined with an "AND" logic when more than one is supplied. With no `input`, all your RFIs will be returned.


# Answer RFI questions

Submit answers with plaintext or documents

Use the `answerRfiQuestion` mutation to submit an answer for a single question on a `PENDING` RFI. Files are sent inline as base64 in the same call — there is no separate upload step or multipart request.

### **What kind of answer to send**&#x20;

The shape of the answer depends on the question's `fileUploadOption`:

| fileUploadOption | What to send                                                                                                                            |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `PREFERRED`      | A document is expected — send `files`. If the document is not available, send `text` with the reason instead. Sending both is rejected. |
| `NONE`           | Send `text` only. Files are not accepted.                                                                                               |

### **File rules**

* Accepted extensions: `.pdf`, `.jpg`, `.jpeg`, `.png`, `.xls`, `.xlsx`. The extension determines the MIME type, so it must match the actual file.
* Up to **10 files** per question.
* Up to **10 MB** per file (raw bytes, before base64 encoding).
* `base64` must be the plain base64 body, with no `data:...;base64,` prefix.

### &#x20;**Answer with a file**

For a `PREFERRED` question.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      rfiId: "61f3a2c8d1e9b7a4c5d6e7f8",
      questionCode: "SENDER_ID_PROOF",
      files: [{ name: "passport.pdf", base64: "JVBERi0xLjQK..." }],
    },
  },
  query: `
mutation ($input: AnswerRfiQuestionInput!) {
  answerRfiQuestion(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      questions { questionCode answered }
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: AnswerRfiQuestionInput!) {
  answerRfiQuestion(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      questions { questionCode answered }
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "rfiId": "61f3a2c8d1e9b7a4c5d6e7f8",
    "questionCode": "SENDER_ID_PROOF",
    "files": [
      { "name": "passport.pdf", "base64": "JVBERi0xLjQK..." }
    ]
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "answerRfiQuestion": {
      "success": true,
      "code": "RECORDED",
      "message": "RFI reply recorded",
      "rfi": {
        "id": "61f3a2c8d1e9b7a4c5d6e7f8",
        "status": "PENDING",
        "questions": [
          { "questionCode": "SENDER_ID_PROOF", "answered": true },
          { "questionCode": "OTHER_TX_PURPOSE", "answered": false }
        ]
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### **Answer with plain text only**

For a `NONE` question, or for a `PREFERRED` question where the document is not available and you provide the reason instead.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      rfiId: "61f3a2c8d1e9b7a4c5d6e7f8",
      questionCode: "OTHER_TX_PURPOSE",
      text: "Payment for invoice #INV-2031, software development services.",
    },
  },
  query: `
mutation ($input: AnswerRfiQuestionInput!) {
  answerRfiQuestion(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      questions { questionCode answered }
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: AnswerRfiQuestionInput!) {
  answerRfiQuestion(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      questions { questionCode answered }
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "rfiId": "61f3a2c8d1e9b7a4c5d6e7f8",
    "questionCode": "OTHER_TX_PURPOSE",
    "text": "Payment for invoice #INV-2031, software development services."
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "answerRfiQuestion": {
      "success": true,
      "code": "RECORDED",
      "message": "RFI reply recorded",
      "rfi": {
        "id": "61f3a2c8d1e9b7a4c5d6e7f8",
        "status": "ASSESSING",
        "questions": [
          { "questionCode": "SENDER_ID_PROOF", "answered": true },
          { "questionCode": "OTHER_TX_PURPOSE", "answered": true }
        ]
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

### **Completing the RFI**

Each question can be answered once — pick the questions with `answered: false`. When the last open question is answered, the RFI moves to `ASSESSING` in the same call (as in the response above) and an [`rfi_assessing`](/basics/webhooks#rfi_assessing) webhook is dispatched. No further action is required from you.

{% hint style="info" %}
Invalid submissions such as an unknown `questionCode`, an already-answered question, files on a `NONE` question, or a file-rule violation will be rejected as GraphQL errors. [See RFI response codes](/compliance/request-for-information/rfi-response-codes).&#x20;
{% endhint %}


# Decline an RFI

When you cannot provide the requested information

Use the `declineRfi` mutation when you are unable to provide the requested information — the API equivalent of "Unable to comply" on the secure form.

Declining:

* marks the RFI as `CLOSED` — an [`rfi_closed`](/basics/webhooks#rfi_closed) webhook is dispatched;
* cancels any linked deposits, withdrawals, or payments **still under review** at the time of decline, with [reject code](/moving-funds/payouts/rejection-codes) `CANCELLATION_REQUESTED_BY_PARTICIPANT` ;
* leaves anything already confirmed, cancelled, or refunded as-is.

{% hint style="warning" %}
Only `PENDING` RFIs can be declined, and the action is **irreversible** — once declined, no further answers are accepted and the cancelled transactions can not be reinstated.
{% endhint %}

### Decline an RFI by ID

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      rfiId: "61f3a2c8d1e9b7a4c5d6e7f8",
    },
  },
  query: `
mutation ($input: DeclineRfiInput!) {
  declineRfi(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      statusMessage
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: DeclineRfiInput!) {
  declineRfi(input: $input) {
    success
    code
    message
    rfi {
      id
      status
      statusMessage
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "rfiId": "61f3a2c8d1e9b7a4c5d6e7f8"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "declineRfi": {
      "success": true,
      "code": "MARKED",
      "message": "RFI marked as unanswered",
      "rfi": {
        "id": "61f3a2c8d1e9b7a4c5d6e7f8",
        "status": "CLOSED",
        "statusMessage": "You specified that you are unable to comply. Relevant transfers can be cancelled."
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

If the RFI is no longer `PENDING`, the mutation returns `success: false` with code `INVALID_STATUS` and the unchanged RFI — see [RFI response codes](/compliance/request-for-information/rfi-response-codes).


# RFI response codes

All reply codes and GraphQL errors

There are two places an RFI call can report a problem: the `code` field on the mutation reply payload, and the top-level GraphQL `errors` array.

### **Reply codes**

Returned in the `code` field of `AnswerRfiQuestionReply` / `DeclineRfiReply`:

| Mutation            | success | code               | When                                                                                                 |
| ------------------- | ------- | ------------------ | ---------------------------------------------------------------------------------------------------- |
| `answerRfiQuestion` | `true`  | `RECORDED`         | The reply was recorded                                                                               |
| `declineRfi`        | `true`  | `MARKED`           | The RFI was declined and closed                                                                      |
| both                | `false` | `NOT_FOUND`        | The RFI does not exist or does not belong to you                                                     |
| both                | `false` | `INVALID_STATUS`   | The RFI is not `PENDING` — answers and declines are only accepted while it is open for your response |
| `answerRfiQuestion` | `false` | `Already provided` | The question was answered by a concurrent submission (for example, via the email form)               |

### **GraphQL errors**

Invalid input is rejected before any reply payload is produced. These are returned in the top-level `errors` array with no `data`, with `extensions.code` set to:

| extensions.code     | Operation                 | When                                                                                                                                                                                                                                                                                    |
| ------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BAD_USER_INPUT`    | any RFI query or mutation | Malformed `rfiId` / `id` — IDs are 24-character hex strings                                                                                                                                                                                                                             |
| `BAD_USER_INPUT`    | `answerRfiQuestion`       | The RFI was not found, unknown `questionCode`, the question has already been answered, or a file-rule violation — files on a `NONE` question, both `text` and `files` on a `PREFERRED` question, neither provided, too many files, unsupported file type, or a file over the size limit |
| `TOO_MANY_REQUESTS` | any                       | Rate limit exceeded — see below                                                                                                                                                                                                                                                         |

The error `message` spells out the specific problem, for example `Question SENDER_ID_PROOF has already been answered.` or `File "passport.pdf" exceeds the 10 MB per-file limit.`

### **Rate limits**

RFI queries and mutations are subject to the same per-client and per-IP limits as the rest of the API. When a limit is exceeded, the response is HTTP `429` with a `Retry-After` header (seconds) and `code: TOO_MANY_REQUESTS`. See [Rate limiting](/other/rate-limiting).


# Confirmation of Payee

Verify that a payee's account name matches their bank account details

Confirmation of Payee (CoP) is a security feature that verifies whether an account holder's name matches the account details you provide. It helps to:

* Reduce fraud by verifying the account holder's name before sending funds
* Prevent accidental payments to wrong accounts due to mistyped details
* Provide confidence that money is being sent to the intended recipient
* Alert you when the account name doesn't match or only partially matches

{% hint style="info" %}
The feature is also available through the [Flash Connect](https://connect.flash-payments.com/) portal. You can perform CoP checks directly from the UI, view your request history, and monitor usage statistics without writing any code. This can be useful for manual verification workflows or for getting familiar with the feature before integrating it into your application via the API.
{% endhint %}

### Making a CoP Request

To verify account details, execute the `confirmationOfPayee` mutation. You must provide the `accountIdType`, the relevant account details, and the `accountName` you wish to verify.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      accountIdType: "BSB",
      bsb: "012003",
      accountNo: "123456789",
      accountName: "John Smith",
    },
  },
query: `
  mutation ($input: CopInput!) {
    confirmationOfPayee(input: $input) {
      success code message billable
    }
  }`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation ($input: CopInput!) {
  confirmationOfPayee(input: $input) {
    success
    code
    message
    billable
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": {
    "accountIdType": "BSB",
    "bsb": "012003",
    "accountNo": "123456789",
    "accountName": "John Smith"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "confirmationOfPayee": {
      "success": true,
      "code": "MATCH",
      "message": "Account name matches",
      "billable": true
    }
  }
}
```

{% endtab %}
{% endtabs %}

The `code` field in the response indicates the [result of the verification](https://developer.flash-payments.com/~/revisions/QODtCCHQ0ULYQp2U9s5d/other/confirmation-of-payee/response-codes).&#x20;

The `billable` field indicates whether the CoP request may be subject to a fee.&#x20;

{% hint style="info" %}
CoP requests are billed based on your agreement with Flash Payments. Contact Flash Payments support for details on pricing.
{% endhint %}


# Testing CoP integration

In the UAT environment, you can simulate different CoP responses by using specific substring keywords in the `accountName` field and any valid `bsb` and `accountNo` values.

{% hint style="info" %}
The pattern matching on the  `accountName` field is **substring-based** and **case-insensitive,** e.g. using `"Test Copimatch"`, `"John copimatch Smith"`, or `"COPIMATCH"` will all trigger the same scenario.
{% endhint %}

Here is a current list of the testing keywords and the most common [response codes](https://developer.flash-payments.com/~/revisions/9LlT1HXk7YEwcubW18VI/compliance/confirmation-of-payee/cop-response-codes). Please note this list **can be changed over time.**

| Account Name Keyword | Response Code        | Simulated Account Type     |
| -------------------- | -------------------- | -------------------------- |
| `copimatch`          | `MATCH`              | Individual                 |
| `copijmatch`         | `MATCH`              | Individual (joint account) |
| `copcmatch`          | `MATCH`              | Company                    |
| `copiclosematch`     | `CLOSE_MATCH`        | Individual                 |
| `copijclosematch`    | `CLOSE_MATCH`        | Individual (joint account) |
| `copcclosematch`     | `CLOSE_MATCH`        | Company                    |
| `copinotmatch`       | `NOT_MATCH`          | Individual                 |
| `copcnotmatch`       | `NOT_MATCH`          | Company                    |
| `copclosed`          | `ACCOUNT_CLOSED`     | -                          |
| `copnotfound`        | `ACCOUNT_NOT_FOUND`  | -                          |
| `coperror`           | `COP_PLATFORM_ERROR` | -                          |

{% hint style="info" %}
You can start with testing CoP requests in the [API Playground](https://api.uat.flash-payments.com.au/). Log in with your UAT credentials and use the [`confirmationOfPayee` mutation](/compliance/confirmation-of-payee#making-a-cop-request).
{% endhint %}

### Integration Examples

#### CoP as a standalone investigation tool

CoP can be used independently from your payment flows as an account investigation tool. For example, you may want to verify account holder details during onboarding, reconciliation, or dispute resolution, without initiating a payment. A typical investigation flow looks like this:

1. Collect the account details you wish to verify: BSB, account number, and the expected account holder name.
2. Call `confirmationOfPayee` with those details.
3. Inspect the `code` in the response.
4. If `MATCH` then the account holder name is confirmed. Record the result for your records.
5. If `CLOSE_MATCH` then the name partially matches. Review the `message` for details and decide whether further investigation is needed.
6. If `NOT_MATCH` then the name does not match the account. This may warrant further due diligence.
7. If `ACCOUNT_CLOSED` or `ACCOUNT_NOT_FOUND` then the account is no longer active or does not exist. Flag accordingly.
8. If `COP_PLATFORM_ERROR` then the check could not be completed. The account may have opted out of CoP. Retry later or use alternative verification methods.

{% hint style="info" %}
Each CoP request is logged and available in your [FlashConnect](https://connect.flash-payments.com.au/) request history, making it easy to maintain an audit trail of your verification checks.
{% endhint %}

#### CoP as a part of your payment integration flow

{% hint style="warning" %}
While CoP is fully functional on our platform, and the adoption among Australian financial institutions is growing, the **Australian CoP coverage is currently limited.**&#x20;

This means a significant portion of accounts may return `ACCOUNT_NOT_FOUND` or `COP_PLATFORM_ERROR`  not because the details are wrong, but because the receiving institution does not yet fully participate in CoP.

Additionally, financial institutions store account holder names in varying formats (e.g., abbreviated names, reordered words, special characters). The current matching algorithm used by the Australian Payments Plus (AP+) relies on basic string similarity, which can produce false-negative `NOT_MATCH` results for accounts that are, in fact, correct.

For this reason, **we currently recommend using CoP as a standalone verification tool** rather than as a blocking step in your payment flow.
{% endhint %}

A typical future integration flow could look like this:

1. Before submitting a payment or withdrawal, call `confirmationOfPayee` with the recipient's account details.
2. Inspect the `code` in the response.
3. If `MATCH` then proceed with the payment.
4. If `CLOSE_MATCH` then display a warning to your user and let them decide whether to proceed.
5. If `NOT_MATCH` then alert the user and recommend they verify the account details.
6. If `ACCOUNT_CLOSED` or `ACCOUNT_NOT_FOUND` then block the payment and ask the user to provide correct details.
7. If `COP_PLATFORM_ERROR` then optionally proceed, as the account may have opted out of CoP.

{% hint style="info" %}
**CoP is advisory**. The response does not block payments automatically. It is **your responsibility** to act on the result codes appropriately for your use case.
{% endhint %}

#### Error Handling&#x20;

If your account does not have CoP enabled, the API will return:

```jsonl
{
  "data": {
    "confirmationOfPayee": {
      "success": false,
      "code": "COP_API_DISABLED",
      "message": "Confirmation Of Payee API is disabled. Please contact support.",
      "billable": false
    }
  }
}
```

Standard [rate limiting](https://developer.flash-payments.com/~/revisions/VVAbKd5tNL6a2Thg7Hh6/other/rate-limiting) applies to CoP requests. Additionally, CoP has its own usage limits. If you exceed them, you will receive the `COP_LIMIT_EXCEEDED` code.

{% hint style="info" %}
When the [response code](https://developer.flash-payments.com/~/revisions/cMEPQHA2kkPOWBiWhppd/compliance/confirmation-of-payee/cop-response-codes) is `COP_PLATFORM_ERROR`, it may indicate that the account holder has opted out of CoP verification. The general recommendation is to proceed with the payment.
{% endhint %}


# CoP response codes

Here is the list of all possible CoP response codes.

<table><thead><tr><th width="251.1875">Code</th><th width="245.5">Description</th><th>Recommended Action</th></tr></thead><tbody><tr><td><code>MATCH</code></td><td>The account name exactly matches the provided information.</td><td>Safe to proceed with payment.</td></tr><tr><td><code>CLOSE_MATCH</code></td><td>The account name partially matches. This may indicate a minor spelling difference or an abbreviated name.</td><td>Warn the user; consider proceeding with caution.</td></tr><tr><td><code>NOT_MATCH</code></td><td>The account name does not match the provided information.</td><td>Alert the user. Verify the account details before proceeding.</td></tr><tr><td><code>ACCOUNT_CLOSED</code></td><td>The specified account is closed.</td><td>Do not proceed. The recipient should provide alternative account details.</td></tr><tr><td><code>ACCOUNT_NOT_FOUND</code></td><td>The specified account cannot be found.</td><td>Verify the BSB and account number are correct.</td></tr><tr><td><code>ACCOUNT_TYPE_NOT_SUPPORTED</code></td><td>The <code>accountIdType</code> provided is not yet supported for CoP checks.</td><td>Fall back to manual verification if needed.</td></tr><tr><td><code>COP_PLATFORM_ERROR</code></td><td>An error occurred in the CoP platform, or the account has opted out from CoP.</td><td>You may proceed with the payment at your own discretion.</td></tr><tr><td><code>COP_LIMIT_EXCEEDED</code></td><td>Your CoP request limit has been exceeded.</td><td>Contact Flash Payments support.</td></tr></tbody></table>


# Adverse Media Search

Screen individuals and organisations against adverse media sources

Adverse Media Search (AMS) lets you screen an individual or organisation against web-based adverse media sources — news articles, court records, and other publicly available content.

{% hint style="info" %}
The feature is also available through the [Flash Connect](https://connect.flash-payments.com/) portal. You can perform the AMS directly from the UI, view your request history, and monitor usage statistics without writing any code. This can be useful for getting familiar with the feature before integrating it into your application via the API.
{% endhint %}

You can [run a search](/compliance/adverse-media-search/run-ams-request) via the `adverseMediaSearch` mutation or past searches via the `amsRequest` and `amsRequests` queries.\
\
Scans run in the background and can take several minutes. Use webhooks or poll the `amsRequest` query to track progress. See [AMS statuses](/compliance/adverse-media-search/ams-statuses) for the full lifecycle.


# Run AMS Request

## Adverse Media Search

To run a search, execute the `adverseMediaSearch` mutation as below.

#### Search for an individual

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      firstName: "John",
      lastName: "Smith",
      country: "AU",
    },
  },
  query: `
mutation ($input: AmsRequestInput!) {
  adverseMediaSearch(input: $input) {
    success
    code
    message
    amsRequest {
      id
      status
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: AmsRequestInput!) {
  adverseMediaSearch(input: $input) {
    success
    code
    message
    amsRequest {
      id
      status
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {
    "firstName": "John",
    "lastName": "Smith",
    "country": "AU"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "adverseMediaSearch": {
      "success": true,
      "code": "SCAN_SCHEDULED",
      "message": "Name scan scheduled",
      "amsRequest": {
        "id": "6820a4f3e1c2b5d8f0123456",
        "status": "INITIALISED"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Search for an organisation

Use `accountName` instead of individual name fields when screening a business or other non-person entity.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      accountName: "Acme Pty Ltd",
      country: "AU",
    },
  },
  query: `
mutation ($input: AmsRequestInput!) {
  adverseMediaSearch(input: $input) {
    success
    code
    message
    amsRequest {
      id
      status
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
mutation($input: AmsRequestInput!) {
  adverseMediaSearch(input: $input) {
    success
    code
    message
    amsRequest {
      id
      status
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {
    "accountName": "Acme Pty Ltd",
    "country": "AU"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "adverseMediaSearch": {
      "success": true,
      "code": "SCAN_SCHEDULED",
      "message": "Name scan scheduled",
      "amsRequest": {
        "id": "6820b1d9c3f4a7e2d0987654",
        "status": "INITIALISED"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Name — `firstName` / `lastName` / `middleName` or `accountName`

For individuals, provide  `firstName` and `lastName`. The optional `middleName` improves matching accuracy.

For organisations, use `accountName` instead. You cannot combine `accountName` with individual name fields.

{% hint style="warning" %}
Either `accountName` **or** at least one of `firstName` / `lastName` is required. Providing both will result in a validation error.
{% endhint %}

#### Country — `country`

A two-letter ISO 3166-1 alpha-2 country code (e.g. `AU`, `US`, `GB`). This is required and used to contextualise results — articles where the detected location does not match the supplied country are flagged via `locationMismatch`.

#### Background scan — tracking progress

The scan runs in the background and may take several minutes. The mutation returns immediately with `status: INITIALISED`. Use the returned `id` to poll for results or subscribe to webhook events to be notified when the scan progresses.

Webhook events fired during a scan:

| Event             | Status        |
| ----------------- | ------------- |
| `ams_initialised` | `INITIALISED` |
| `ams_pending`     | `PENDING`     |
| `ams_completed`   | `COMPLETED`   |
| `ams_failed`      | `FAILED`      |

See [AMS statuses](/compliance/adverse-media-search/ams-statuses) for the full lifecycle.

#### Deduplication

If you submit a search for the same name and country more than once within the same calendar day, the existing request is returned rather than creating a new one. The `code` field indicates whether the scan was newly scheduled or is already in progress or complete:

| Code                     | Meaning                                                         |
| ------------------------ | --------------------------------------------------------------- |
| `SCAN_SCHEDULED`         | New scan created and queued                                     |
| `SCAN_ALREADY_SCHEDULED` | A scan for this name and country is already in progress today   |
| `SCAN_ALREADY_COMPLETED` | A completed scan for this name and country already exists today |

#### Monthly request limit

A free monthly limit applies to AMS requests. Once reached, `success: false` is returned with `code: LIMIT_EXCEEDED`. Contact support to increase your limit.


# AMS statuses

Adverse media search request statuses

1. You submit a search. The request is created and queued.\
   `INITIALISED`
2. The background scan starts — web sources are fetched and analysed.\
   `INITIALISED` → `PENDING`
3. `PENDING` →
   * `COMPLETED` — the scan finished successfully. Results are available in the `results` field. ***Final status.***
   * `FAILED` — the scan could not be completed due to an error. The request is not billable. ***Final status.***

#### Most common status transitions

**Happy path**

`INITIALISED` → `PENDING` → `COMPLETED`

**Unhappy path**

`INITIALISED` → `PENDING` → `FAILED`

{% hint style="info" %}
A `FAILED` request is not billed. You may submit the same search again — a new request will be created and processed.
{% endhint %}

#### Results

Once a request reaches `COMPLETED`, the `results` field is populated with an array of `AmsWebSearchResult` objects. Each result represents a single web article found during the scan and includes:

| Field                | Description                                                                   |
| -------------------- | ----------------------------------------------------------------------------- |
| `title`              | Title of the web page                                                         |
| `snippet`            | Web search snippet                                                            |
| `link`               | URL of the article                                                            |
| `adversityScore`     | Overall adversity score, 0–100. Higher = more adverse content found           |
| `personSimilarity`   | Similarity between the search subject and the person in the article, 0–100    |
| `role`               | Role of the subject in the article — e.g. `perpetrator`, `victim`, `other`    |
| `roleDetails`        | Further detail on the role or alleged involvement                             |
| `summary`            | One-sentence summary of the article                                           |
| `extractedCountry`   | ISO country code extracted from the article, if detected                      |
| `extractedState`     | State or region extracted from the article, if detected                       |
| `locationMismatch`   | `true` if the article's detected location does not match the supplied country |
| `paywall`            | `true` if the article is behind a paywall and could not be fully analysed     |
| `exactFullNameMatch` | `true` if the article contains an exact match of the full name                |
| `dob`                | Date of birth extracted from the article, if detected                         |
| `ageInArticle`       | Age of the person extracted from the article, if detected                     |
| `articlePublishDate` | Publication date of the article, if detected                                  |
| `lookup`             | Keywords found in the article and their occurrence counts                     |


# Query AMS requests

#### Retrieving a single AMS request

Use the `amsRequest` query with the `id` returned from the `adverseMediaSearch` mutation to check the status of a scan or retrieve its results.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "6820a4f3e1c2b5d8f0123456",
  },
  query: `
query ($id: ID!) {
  amsRequest(id: $id) {
    id
    name
    country
    status
    createdAt
    results {
      title
      link
      adversityScore
      personSimilarity
      summary
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($id: ID!) {
  amsRequest(id: $id) {
    id
    name
    country
    status
    createdAt
    results {
      title
      link
      adversityScore
      personSimilarity
      summary
      # there are many other result fields
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "id": "6820a4f3e1c2b5d8f0123456"
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "amsRequest": {
      "id": "6820a4f3e1c2b5d8f0123456",
      "name": "John Smith",
      "country": "AU",
      "status": "COMPLETED",
      "createdAt": "2025-03-15T08:23:14.521Z",
      "results": [
        {
          "title": "Local businessman John Smith fined for tax evasion",
          "link": "https://example-news.com.au/articles/smith-tax",
          "adversityScore": 72,
          "personSimilarity": 85,
          "summary": "John Smith of Sydney was fined $45,000 for understating income over three financial years."
        }
      ]
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The `results` field is populated only once the scan reaches `COMPLETED` status. While the scan is `INITIALISED` or `PENDING`, `results` will be `null`.
{% endhint %}

#### Retrieving all your AMS requests

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {},
  },
  query: `
query ($input: AmsQueryInput) {
  amsRequests(input: $input) {
    id
    name
    country
    status
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AmsQueryInput) {
  amsRequests(input: $input) {
    id
    name
    country
    status
    createdAt
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {}
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "amsRequests": [
      {
        "id": "6820a4f3e1c2b5d8f0123456",
        "name": "John Smith",
        "country": "AU",
        "status": "COMPLETED",
        "createdAt": "2025-03-15T08:23:14.521Z"
      },
      {
        "id": "6820b1d9c3f4a7e2d0987654",
        "name": "Acme Pty Ltd",
        "country": "AU",
        "status": "PENDING",
        "createdAt": "2025-03-15T09:01:44.008Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

#### Filtering AMS requests

Use the `input` parameter to narrow results by status, date range, or name.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      statuses: ["COMPLETED"],
      minCreatedAt: "2025-03-01T00:00:00.000Z",
      maxCreatedAt: "2025-04-01T00:00:00.000Z",
      country: "AU",
    },
  },
  query: `
query ($input: AmsQueryInput) {
  amsRequests(input: $input) {
    id
    name
    country
    status
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AmsQueryInput) {
  amsRequests(input: $input) {
    id
    name
    country
    status
    createdAt
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  # there are more filter parameters available, see the API schema
  "input": {
    "statuses": ["COMPLETED"],
    "minCreatedAt": "2025-03-01T00:00:00.000Z",
    "maxCreatedAt": "2025-04-01T00:00:00.000Z",
    "country": "AU"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "amsRequests": [
      {
        "id": "6820a4f3e1c2b5d8f0123456",
        "name": "John Smith",
        "country": "AU",
        "status": "COMPLETED",
        "createdAt": "2025-03-15T08:23:14.521Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

Available filter fields on `AmsQueryInput`:

| Field          | Description                                                   |
| -------------- | ------------------------------------------------------------- |
| `statuses`     | Filter by one or more AMS statuses                            |
| `minCreatedAt` | Return only requests created after this timestamp (ISO 8601)  |
| `maxCreatedAt` | Return only requests created before this timestamp (ISO 8601) |
| `firstName`    | Filter by first name — case insensitive, partial match        |
| `middleName`   | Filter by middle name — case insensitive, partial match       |
| `lastName`     | Filter by last name — case insensitive, partial match         |
| `accountName`  | Filter by business name — case insensitive, partial match     |
| `country`      | Filter by two-letter ISO country code                         |


# Bank information

Ensuring bank details are correct

To validate BSB, BIC (aka SWIFT code) or IBAN use the bankInfo query.

{% hint style="info" %}
The `bankInfo` query accepts only one of `bsb`, `bic`, or `iban` arguments. Otherwise, it will return an error.
{% endhint %}

The below sample queries will return `null` if the BSB, BIC, IBAN is not found.

Validate BSB

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      bsb: "012622",
    },
  }, 
  query: `
query ($input: BankInfoQueryInput!) {
  bankInfo(input: $input) {
    name 
    address {
      building street suburb state country postcode
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: BankInfoQueryInput!){
  bankInfo(input: $input) {
    name
    address {
      building
      street
      suburb
      state
      country
      postcode
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": {
    "bsb": "012622"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "bankInfo": {
      "name": "ANZ",
      "address": {
        "building": null,
        "street": "Shop 1  Westfield Shopping Ctr",
        "suburb": "Figtree",
        "state": "NSW",
        "country": "AU",
        "postcode": "2525"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

Validate BIC

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      bic: "BARCGB22",
    },
  }, 
  query: `
query ($input: BankInfoQueryInput!) {
  bankInfo(input: $input) {
    name 
    address {
      building street suburb state country postcode
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: BankInfoQueryInput!){
  bankInfo(input: $input) {
    name
    address {
      building
      street
      suburb
      state
      country
      postcode
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": {
    "bic": "BARCGB22"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "bankInfo": {
      "name": "BARCLAYS BANK PLC",
      "address": {
        "building": null,
        "street": "1 CHURCHILL PLACE, CANARY WHARF London",
        "suburb": "London",
        "state": null,
        "country": "GB",
        "postcode": "E14 5HP"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

Validate IBAN

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      iban: "DE59500105178646768962",
    },
  }, 
  query: `
query ($input: BankInfoQueryInput!) {
  bankInfo(input: $input) {
    name 
    address {
      building street suburb state country postcode
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: BankInfoQueryInput!){
  bankInfo(input: $input) {
    name
    address {
      building
      street
      suburb
      state
      country
      postcode
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
 {
  "input": {
    "iban": "DE59500105178646768962"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```javascript
{
  "data": {
    "bankInfo": {
      "name": "ING-DIBA AG (RETAIL BANKING)",
      "address": {
        "building": null,
        "street": "THEODOR-HEUSS-ALLEE 2 Frankfurt Am Main",
        "suburb": "Frankfurt Am Main",
        "state": null,
        "country": "DE",
        "postcode": "60486"
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}


# Address Cleanser

Validate and standardise physical addresses

Address Cleanser is a data-standardisation and geocoding utility designed to ensure physical addresses exist and are correctly formatted. It standardises a supplied address against multiple geocoding providers and returns a suggested recommendation together with a score.

It helps you:

* Validate and standardise addresses before processing payments
* Reduce failed deliveries due to incorrect or unrecognised addresses
* Support data integrity and screening accuracy by standardising physical addresses

{% hint style="info" %}
The feature is also available through the [Flash Connect](https://connect.flash-payments.com/) portal. You can cleanse addresses directly from the UI, view your request history, and monitor usage statistics without writing any code. This can be useful for getting familiar with the feature before integrating it into your application via the API.
{% endhint %}

You can cleanse an address via the [`cleanseAddress`](/compliance/address-cleanser/cleanse-an-address) mutation or retrieve past requests via the [`addressCleanserRequest`](/compliance/address-cleanser/query-address-cleanser-requests) and [`addressCleanserRequests`](/compliance/address-cleanser/query-address-cleanser-requests) queries.

Unlike Adverse Media Search, address cleansing is synchronous — the result is returned in the mutation response. There is no background processing and no webhooks.

**Recommendation and score**

The result is an estimate, not a definitive check. Each cleansed address comes with:

| Field            | Description                                                                                                                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recommendation` | <p><code>accept</code> — suggests the result can be accepted as-is. <br><code>review</code> — suggests it should be reviewed before it is used. <br><code>flag</code> — suggests it should be rejected.</p> |
| `score`          | From 0 to 100. A higher value indicates a closer match. Can be null.                                                                                                                                        |

**Pricing**

Address Cleanser is charged per request — 1,000 requests per month are included free of charge. To learn more about pricing, API access, or to enable Address Cleanser for your organisation, reach out to our team.

{% hint style="warning" %}
**Regulatory disclaimer**

**Identity Verification:** This tool does not verify that a specific individual, company, or ultimate beneficial owner is legally associated with, or resides at, the validated address.

**Compliance Obligations:** Use of this tool does not satisfy an AUSTRAC reporting entity's Know Your Customer (KYC) or Customer Due Diligence (CDD) obligations under the AML/CTF Act 2006.

**Data Retention:** To comply with statutory 7-year record-keeping requirements, users should ensure their systems retain the original, raw address string inputted by the participant alongside any cleansed data outputs.
{% endhint %}


# Cleanse an address

### Address Cleanser

To cleanse an address, execute the `cleanseAddress` mutation as below. The result is returned synchronously — no polling or webhooks are required.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      street: "33 effingham st, sth launceston 7249",
      country: "AU",
    },
  },
  query: `
fragment AddressParts on Address { building streetNo street suburb state postcode country }

mutation ($input: AddressInput!) {
  cleanseAddress(input: $input) {
    success
    code
    message
    addressRequest {
      id
      originalAddress { ...AddressParts }
      cleansedAddress { ...AddressParts }
      recommendation
      score
    }
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
fragment AddressParts on Address { building streetNo street suburb state postcode country }

mutation($input: AddressInput!) {
  cleanseAddress(input: $input) {
    success
    code
    message
    addressRequest {
      id
      originalAddress { ...AddressParts }
      cleansedAddress { ...AddressParts }
      recommendation
      score
    }
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {
    "street": "33 effingham st, sth launceston 7249",
    "country": "AU"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "cleanseAddress": {
      "success": true,
      "code": "CLEANSED",
      "message": "Address cleansed",
      "addressRequest": {
        "id": "6820a4f3e1c2b5d8f0123456",
        "originalAddress": {
          "building": null,
          "streetNo": null,
          "street": "33 effingham st, sth launceston 7249",
          "suburb": null,
          "state": null,
          "postcode": null,
          "country": "AU"
        },
        "cleansedAddress": {
          "building": null,
          "streetNo": null,
          "street": "33 Effingham Street",
          "suburb": "South Launceston",
          "state": "TAS",
          "postcode": "7249",
          "country": "AU"
        },
        "recommendation": "accept",
        "score": 97.1
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
`originalAddress` and `cleansedAddress` are both of type `Address`, so the examples above declare a reusable [GraphQL fragment](https://graphql.org/learn/queries/#fragments) — `fragment AddressParts on Address { ... }` — and spread it into both with `...AddressParts` instead of repeating the field list.
{% endhint %}

**Address — `input`**

The standard `AddressInput` type is used:

| Field      | Description                                                               |
| ---------- | ------------------------------------------------------------------------- |
| `street`   | Street string, e.g. `Apt 256 123 John Ave`. **Required**                  |
| `country`  | Two-letter ISO 3166-1 alpha-2 country code, e.g. `AU`, `US`. **Required** |
| `building` | Building part of the address, where applicable (e.g. HK, SG). *Optional*  |
| `streetNo` | Street number, e.g. `33`. *Optional*                                      |
| `suburb`   | Suburb, city or other locality, e.g. `Paddington`. *Optional*             |
| `state`    | State of the country, e.g. `NSW`. *Optional*                              |
| `postcode` | Post code (aka zip code), e.g. `2000`. *Optional*                         |

Addresses from most countries worldwide are supported.

**Optional fields**

Only `street` and `country` are required. The other components — `building`, `streetNo`, `suburb`, `state`, `postcode` — are optional: you can either supply them separately, or fold them into `street` as a single free-form string (e.g. `"Unit 5, 33 Effingham St, South Launceston TAS 7249"`).

Either way, `originalAddress` keeps your input exactly as you sent it.

**Result — `recommendation` and `score`**

The result is an estimate, not a definitive check. Inspect `recommendation` (`accept`, `review`, `flag`) and `score` (0 to 100, higher is a closer match) on the returned `addressRequest` to decide how to treat the cleansed address. See the overview for details.

**Response codes**

| Code                            | Meaning                                                                        |
| ------------------------------- | ------------------------------------------------------------------------------ |
| `CLEANSED`                      | The address was cleansed and the result is in `addressRequest`                 |
| `ALREADY_CLEANSED`              | The same address was already cleansed today — the existing request is returned |
| `VALIDATION_ERROR`              | The input failed validation — e.g. `street` is missing                         |
| `CLEANSING_FAILED`              | The address could not be processed — the request is not billable               |
| `LIMIT_EXCEEDED`                | The free monthly request limit was reached                                     |
| `ADDRESS_CLEANSER_API_DISABLED` | The API is not enabled for your account — contact support                      |

**Deduplication**

If you submit the same address more than once within the same calendar day, the existing request is returned rather than creating a new one, with `code: ALREADY_CLEANSED`. You are billed at most once per day for the same address.

**Monthly request limit**

1,000 requests per month are included free of charge. Once reached, `success: false` is returned with `code: LIMIT_EXCEEDED`. Contact support to upgrade your account.


# Query Address Cleanser requests

**Retrieving a single Address Cleanser request**

Use the `addressCleanserRequest` query with the `id` returned from the `cleanseAddress` mutation.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    id: "6820a4f3e1c2b5d8f0123456",
  },
  query: `
query ($id: ID!) {
  addressCleanserRequest(id: $id) {
    id
    originalAddress {
      building
      streetNo
      street
      suburb
      state
      postcode
      country
    }
    cleansedAddress {
      building
      streetNo
      street
      suburb
      state
      postcode
      country
    }
    recommendation
    score
    createdAt
    billable
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($id: ID!) {
  addressCleanserRequest(id: $id) {
    id
    originalAddress {
      building
      streetNo
      street
      suburb
      state
      postcode
      country
    }
    cleansedAddress {
      building
      streetNo
      street
      suburb
      state
      postcode
      country
    }
    recommendation
    score
    createdAt
    billable
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "id": "6820a4f3e1c2b5d8f0123456"
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "addressCleanserRequest": {
      "id": "6820a4f3e1c2b5d8f0123456",
      "originalAddress": {
        "building": null,
        "streetNo": null,
        "street": "33 effingham st, sth launceston 7249",
        "suburb": null,
        "state": null,
        "postcode": null,
        "country": "AU"
      },
      "cleansedAddress": {
        "building": null,
        "streetNo": null,
        "street": "33 Effingham Street",
        "suburb": "South Launceston",
        "state": "TAS",
        "postcode": "7249",
        "country": "AU"
      },
      "recommendation": "accept",
      "score": 97.1,
      "createdAt": "2026-06-12T08:23:14.521Z",
      "billable": true
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The query returns `null` if no request with the supplied `id` exists on your account.
{% endhint %}

**Retrieving all your Address Cleanser requests**

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {},
  },
  query: `
query ($input: AddressCleanserQueryInput) {
  addressCleanserRequests(input: $input) {
    id
    recommendation
    score
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AddressCleanserQueryInput) {
  addressCleanserRequests(input: $input) {
    id
    recommendation
    score
    createdAt
    # there are many other properties
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {}
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "addressCleanserRequests": [
      {
        "id": "6820a4f3e1c2b5d8f0123456",
        "recommendation": "accept",
        "score": 98.25,
        "createdAt": "2026-06-12T08:23:14.521Z"
      },
      {
        "id": "6820b1d9c3f4a7e2d0987654",
        "recommendation": "review",
        "score": 64.1,
        "createdAt": "2026-06-12T09:01:44.008Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

**Filtering Address Cleanser requests**

Use the `input` parameter to narrow results by recommendation or date range.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      recommendation: "accept",
      minCreatedAt: "2026-06-01T00:00:00.000Z",
      maxCreatedAt: "2026-07-01T00:00:00.000Z",
    },
  },
  query: `
query ($input: AddressCleanserQueryInput) {
  addressCleanserRequests(input: $input) {
    id
    recommendation
    score
    createdAt
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query($input: AddressCleanserQueryInput) {
  addressCleanserRequests(input: $input) {
    id
    recommendation
    score
    createdAt
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```json
{
  "input": {
    "recommendation": "accept",
    "minCreatedAt": "2026-06-01T00:00:00.000Z",
    "maxCreatedAt": "2026-07-01T00:00:00.000Z"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "addressCleanserRequests": [
      {
        "id": "6820a4f3e1c2b5d8f0123456",
        "recommendation": "accept",
        "score": 98.25,
        "createdAt": "2026-06-12T08:23:14.521Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

Available filter fields on `AddressCleanserQueryInput`:

| Field            | Description                                                   |
| ---------------- | ------------------------------------------------------------- |
| `recommendation` | Filter by recommendation — `accept`, `review`, or `flag`      |
| `minCreatedAt`   | Return only requests created after this timestamp (ISO 8601)  |
| `maxCreatedAt`   | Return only requests created before this timestamp (ISO 8601) |


# Account members

Retrieve the members of your client account

The read-only `members` query returns a list of registered users for your client account, including their contact details, roles, access controls, and account status. This provides a programmatic way to retrieve the list of your account users and their information, which can otherwise be obtained via the Flash Connect portal.

The output is always limited to your client account, meaning you can only see your own members.

### Query all members

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
    },
  },
  query: `
query ($input: MembersQueryInput) {
  members(input: $input) {
    id firstName middleName lastName dob email mobile
    address {
      building streetNo street suburb state postcode country
    }
    status roles access isPrimaryContact
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query ($input: MembersQueryInput) {
  members(input: $input) {
    id
    firstName
    middleName
    lastName
    dob
    email
    mobile
    address {
      building
      streetNo
      street
      suburb
      state
      postcode
      country
    }
    status
    roles
    access
    isPrimaryContact
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "members": [
      {
        "id": "5fb314cb9224595df522db61",
        "firstName": "John",
        "middleName": null,
        "lastName": "Smith",
        "dob": "1980-12-12",
        "email": "john.smith@example.com",
        "mobile": "+61 422 832 849",
        "address": {
          "building": null,
          "streetNo": "25",
          "street": "Moore St",
          "suburb": "Waterloo",
          "state": "NSW",
          "postcode": "2017",
          "country": "AU"
        },
        "status": "ACTIVE",
        "roles": ["director", "treasurer"],
        "access": ["admin", "transact", "approve"],
        "isPrimaryContact": true
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

### Filtering members

`MembersQueryInput` accepts three optional list filters: `status`, `roles` and `access`. Omit a field to leave it unfiltered. A member matches a list filter if it has **at least one** of the listed values.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const bodyJSON = {
  variables: {
    input: {
      status: ["ACTIVE"],
      roles: ["director"],
      access: ["transact"],
    },
  },
  query: `
query ($input: MembersQueryInput) {
  members(input: $input) {
    id firstName lastName status roles access
  }
}`,
};
```

{% endtab %}

{% tab title="GraphQL Query" %}

```graphql
query ($input: MembersQueryInput) {
  members(input: $input) {
    id
    firstName
    lastName
    status
    roles
    access
  }
}
```

{% endtab %}

{% tab title="Variables" %}

```javascript
{
  "input": {
    "status": ["ACTIVE"],
    "roles": ["director"],
    "access": ["transact"]
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "data": {
    "members": [
      {
        "id": "5fb314cb9224595df522db61",
        "firstName": "John",
        "lastName": "Smith",
        "status": "ACTIVE",
        "roles": ["director"],
        "access": ["transact", "login"]
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

### Member statuses

| Member Status       | Meaning                                                                                               |
| ------------------- | ----------------------------------------------------------------------------------------------------- |
| `ACTIVE`            | Fully verified and able to log in and transact.                                                       |
| `REGISTERING`       | Has started registration but not finished it yet.                                                     |
| `PASSWORD_REQUIRED` | Created without a password and must set one before logging in.                                        |
| `UNAPPROVED`        | Has finished registration and is waiting to be verified.                                              |
| `SUSPENDED`         | Cannot log in or transact. Covers accounts that are inactive, locked, failed verification or deleted. |

### Member roles

The roles are descriptive and identify a member’s position within the client organisation. They do not, by themselves, grant access (access is regulated by the access controls below). One member can hold several roles.

| Member Role   | Meaning                                                      |
| ------------- | ------------------------------------------------------------ |
| `director`    | A director of the company.                                   |
| `partner`     | A partner of the partnership.                                |
| `secretary`   | A company secretary.                                         |
| `beneficiary` | A beneficial owner of the client.                            |
| `treasurer`   | Manages the client's funds and finances.                     |
| `engineer`    | A technical contact, e.g. someone integrating with this API. |
| `support`     | A support contact for day-to-day queries.                    |
| `compliance`  | A compliance contact for the client.                         |

### Member access

The Access Control Levels (ACLs) define what a member is permitted to do on the account. A member can hold several ACLs.

| Member ACL       | Grants                                                         |
| ---------------- | -------------------------------------------------------------- |
| `admin`          | Full administrative control, including managing other members. |
| `transact`       | Create and send payments and conversions.                      |
| `login`          | Log in to the account.                                         |
| `api`            | Authenticate and use this API on behalf of the client.         |
| `correspondence` | Receive account correspondence and notifications.              |
| `approve`        | Approve payments that require a second authorisation.          |
| `compliance`     | Access compliance-related information and tasks.               |


# Reference data

1. [`bankInfo`](/compliance/bank-information) - query bank information to **validate** if we support your BSB, IBAN, BIC (aka Swift code).
2. `depositDetails` - query the accounts you can send deposits to in order to increase your Flash Payments master balance.
3. [`availableDeliveryMethods`](/moving-funds/recipients/delivery-methods) - query countries/currency combinations we support and what the required bank account details are.
4. [Rejection codes](/moving-funds/payouts/rejection-codes) - Flash proprietary list of all the reasons why your payout could have been cancelled.


# Rate limiting

How to avoid and resolve HTTP 429 Too Many Requests

## Limits

This API apply various rate limits depending on the type of HTTP request or GraphQL query being executed, as well as the number of such requests. The rate-limiting mechanism is quite dynamic and is based on the IP address(es), error rates, HTTP headers, and the GraphQL queries.

We do not disclose the exact limits due to their complexity and our security policy. However, it's nearly impossible to reach the limits if your requests are properly formed.

When one of the numerous limits exceeds the API typically responds with

1. the HTTP status `429`&#x20;
2. the HTTP header:<br>

   ```
   Retry-After: 59
   ```
3. and a JSON body:<br>

   ```json
   {
     success: false,
     code: "TOO_MANY_REQUESTS",
     message: "Retry after 1 min",
     retrySecs: 59
   }
   ```

## Common cases

Here are the common situations when you might get yourself temporarily blocked:

* When your requests produce numerous errors, e.g. malformed header, JSON body, or a GraphQL query.
* When you send too many requests without a valid `Authorization` header.
* When you send too many requests within a very short period.
  * Most often reason - when you collect reference prices/quotes using the `quote` query for multiple currency pairs. To avoid the issue you must [send multiple GraphQL queries within a single HTTP request](/fx/quote#multiple-reference-indicative-quotes-with-a-single-http-request).

## How to unblock if you see HTTP 429 responses

Please contact our support team via the established communication channels. We will manually reset the counters for you.


