# Testing Your Integration

Source: https://docs.gocardless.com/docs/partner-integrations/testing-your-integration

# Testing Your Integration

Before you go live, test your partner integration in the GoCardless sandbox environment. Sandbox works like the live environment, but no real money moves and you can trigger events that your integration must be able to handle, but that are not easily reproducible in live production.

> **Warning: Don**
> Don't use real customer email addresses or bank details in the sandbox. Payments aren't processed,
>   but email notifications can still be sent.

This page acts as a guide for testing:

- [The OAuth flow](#test-the-oauth-flow) that connects a merchant to your app
- [Webhook handling](#test-webhook-handling) for the events in [Webhooks for Partners](/docs/partner-integrations/webhooks-for-partners)
- [Importing mandates](#test-mandate-imports) from outside your partner integration

In addition to the above, you should also be independently validating that all data is being displayed correctly in your partner app and that merchants are able to complete all the actions outlined in the [Integration Guide](/docs/partner-integrations/integration-guide).

## Test accounts

A partner integration involves two kinds of organisations, and you need both to test it end to end:

| Account              | What it represents                                                           | How you use it                                                                                                       |
| -------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Partner account**  | Your organisation. This organisation owns your partner app integration.      | You create your app in this account, set your redirect and webhook URLs, and view the Partner Dashboard.             |
| **Merchant account** | One of your users. This account is connected to your app via the OAuth flow. | Go through the OAuth flow, create mandates and payments, trigger events that are handled by your partner integration |

This guide assumes you have created your partner app in a sandbox account. If you do not have access to a sandbox account with a live app, please see [Partner Integrations - Before you start](/docs/partner-integrations#before-you-start).

### Create a merchant test account

Create a second sandbox account with a different email address to your partner account. For testing, this will act as your merchant.

## Test the OAuth flow

As part of your integration you should have built a way to generate links to the OAuth flow using your app's `client_id`, `client_secret` and `redirect_uri`.

### 1. Connect your merchant test account

Go through the OAuth flow via your app and sign in as your merchant test account. This should connect your merchant account to your app.

### 2. Check what your integration stores

Verify that you are retrieving and storing the app access token from this connection, along with the GoCardless organisation ID of the connected merchant in your system.

### 3. Test each connection scenario

| Scenario                   | How to test                                                                                   | Expected result                                                                                                                                                                                                                                                                                    |
| -------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| New merchant signs up      | Clear your cache and fill in the sign up form instead of signing in with an existing account. | Successful connection. Your integration should complete the code exchange and store the access token and organisation ID.                                                                                                                                                                          |
| Merchant declines          | Go through the sign in/sign up flow and cancel on the authorisation screen.                   | GoCardless redirects with `error=access_denied` and an `error_description`. Your integration should show the merchant a clear message.                                                                                                                                                             |
| Merchant already connected | Run the flow again for a merchant you've already connected.                                   | Your integration code exchanges for a new access token, and GoCardless disables the old one. Your integration should replace the old token.                                                                                                                                                        |
| Merchant revokes access    | Revoke your app in the merchant's dashboard.                                                  | Your integration receives and processes a [disconnection webhook](/docs/partner-integrations/webhooks-for-partners#disconnections). Your integration should mark the token stored against the merchant as revoked and should not attempt to make any more requests to the GoCardless API using it. |

If any of these scenarios produce unexpected results, refer back to [Connect your merchants](/docs/partner-integrations/connect-your-merchants).

## Test webhook handling

Your partner integration should be set up to appropriately handle the events listed in [Webhooks for Partners](/docs/partner-integrations/webhooks-for-partners).

The following steps walk you through how to trigger these events from the sandbox environment.

### 1. Choose how to trigger events

There are three ways to trigger events in the sandbox environment:

| Method                                                                                             | Use it for                                                                                                                                                          |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [GoCardless CLI](/docs/developer-resources/gc-cli).                                                | Forwarding webhooks to a local instance of your partner integration. Creating/transitioning mandates, payments and billing requests to desired states.              |
| [Scenario simulators](/docs/developer-resources/scenario-simulators), through the API or dashboard | Transitioning a mandate, payment, refund, payout or billing request to a new state.                                                                                 |
| [Send test webhook](/docs/developer-resources/testing-webhooks-dashboard)                          | Simulating events that have no simulator or trigger via the CLI. You choose the resource type, action and cause, and GoCardless sends the webhook to your endpoint. |

For testing against a local instance of your partner integration, the GoCardless CLI is recommended as it allows you to forward webhooks to your local handler, and will print logs of all generated events.

### 2. Trigger events

Use the methods from the previous step to trigger the events your integration handles. See [Key events](/docs/partner-integrations/webhooks-for-partners#key-webhook-events) for a list of events and their suggested handling.

#### Trigger events with the GoCardless CLI

1. Install the [GoCardless CLI](/docs/developer-resources/gc-cli)

2. [Log in](/docs/developer-resources/gc-cli#log-in) using your merchant test account

3. [Listen for webhooks](/docs/developer-resources/gc-cli/cli-reference#gocardless-listen). If running your integration locally, forward webhooks to your local instance.

You can then use the CLI to trigger events which your integration should handle appropriately.

The GoCardless CLI can create resources or transition existing resources. Run `gocardless trigger --help` for a full list of supported actions.

See [Testing webhooks (CLI)](/docs/developer-resources/gc-cli/testing-webhooks-cli) for more information.

#### Trigger events with the scenario simulator

You can use the dashboard or API triggered scenario simulator to transition resources in your merchant test account. The events from these transitions will be sent to your app's webhook URL for processing.

For more information see [Scenario Simulator](/docs/developer-resources/scenario-simulators)

#### Trigger events with Send test webhook

For events that are not covered by the GC CLI triggers or the scenario simulator (e.g. `payment.chargeback_cancelled`), you can send test webhooks directly to your integration via the dashboard [Send test webhook](/docs/developer-resources/testing-webhooks-dashboard) feature.

### 3. Test routing and reliability

Run these checks as well as the individual events to verify the security and reliability of your integration:

| Check                   | How to test                                                                       | Expected result                                                 |
| ----------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Routing to the merchant | Connect two merchant accounts and trigger the same event on each.                 | Each event is handled for the merchant in `links.organisation`. |
| Invalid signature       | Send a request to your endpoint with a wrong `Webhook-Signature` header.          | You reject the request and don't process any events in it.      |
| Duplicate events        | Resend an event from the dashboard.                                               | You skip the event ID you've already processed.                 |
| Several events together | Trigger a simulator that creates more than one event, such as `payment_paid_out`. | You process every event in the webhook.                         |

> **Tip: Inspect and retry webhooks**
> In the sandbox dashboard, open a webhook to see the request GoCardless sent and your response. You
>   can resend it with **Retry**. See [Testing webhooks
>   (Dashboard)](/docs/developer-resources/testing-webhooks-dashboard).

## Test mandate imports

Merchants who already use GoCardless have mandates that exist before they connect to your app. Your integration should be able to find these mandates after the OAuth connection, match them to customers in your product, and store the mandate links. See [Supporting mandates set up outside of your product](/docs/partner-integrations/supporting-mandates-set-up-outside-of-your-product) for how to build this.

To test it, you need mandates to exist in the merchant test account **before** you connect it to your app. The steps below follow that order.

### 1. Use a merchant account that isn't connected

The import flow runs when a merchant connects, so you need a merchant test account with no connection to your app. Do one of the following:

- Create a new merchant test account, as described in [Create a merchant test account](#create-a-merchant-test-account).
- Revoke your app in the dashboard of a merchant account you've already connected. Your integration should handle the [disconnection webhook](/docs/partner-integrations/webhooks-for-partners#disconnections).

### 2. Create mandates in the merchant account

Create mandates using the [GoCardless CLI](#create-mandates-with-the-gocardless-cli) or the [scenario simulator](#create-mandates-with-the-scenario-simulator). Create enough mandates to cover each case your import handles:

| Case to cover                                   | How to set it up                                                                                                              | Expected result in your integration                                                   |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Exact email match                               | Give the GoCardless customer the same `email` as a customer in your test data.                                                | The mandate is auto-matched.                                                          |
| Metadata match                                  | Add a `partner_id` to the GoCardless customer's `metadata` that matches a customer ID in your test data.                      | The mandate is auto-matched.                                                          |
| Probable match                                  | Use a customer with a similar name and the same postal code as a customer in your test data, but a different email.           | The mandate is shown as a probable match for the merchant to review.                  |
| Unresolved                                      | Use a customer who doesn't match anyone in your test data.                                                                    | The mandate is shown as unresolved, and the merchant can pair it manually or skip it. |
| Mandates that can't be used to collect payments | Move a mandate to `failed`, `cancelled` or `expired`, for example with the `mandate_failed` and `mandate_expired` simulators. | The mandate isn't included in the sync.                                               |

> **Warning: Use fake customer details**
> Match the emails and names to test customers in your own system, not real people. Email
>   notifications can still be sent from the sandbox.

#### Create mandates with the GoCardless CLI

1. [Log in](/docs/developer-resources/gc-cli#log-in) to the CLI using the merchant test account.

2. Create a customer with the details you want your integration to match on:

   ```bash
   gocardless create customers \
     -d given_name=Alex \
     -d family_name=Example \
     -d email=alex@example.com \
     -d postal_code=E1+1AA \
     -d country_code=GB \
     -d address_line1=Example+Street \
     -d city=London
   ```

3. Trigger a mandate for that customer. The CLI creates the bank account and mandate, and activates the mandate:

   ```bash
   gocardless trigger mandate_activated customer=CU123
   ```

   Replace `CU123` with the customer ID from the previous step.

4. Repeat for each case in the table. To create a mandate with an auto-generated customer, run `gocardless trigger mandate_activated` with no arguments.

To create a mandate in a different state, use another trigger such as `mandate_failed`, `mandate_expired` or `mandate_pending_submission`. Run `gocardless trigger --help` for the full list. See the [CLI reference](/docs/developer-resources/gc-cli/cli-reference#gocardless-trigger) for details.

#### Create mandates with the scenario simulator

1. Create a customer, bank account and mandate in the merchant test account, using the dashboard or the API. A new mandate starts in `pending_submission`.

2. Use the [scenario simulator](/docs/developer-resources/scenario-simulators) to move the mandate to the state you want to test. For example, run the `mandate_activated` simulator against the mandate ID, from the dashboard or the [API](/docs/api-reference/scenario-simulator#simulate-a-scenario).

### 3. Connect the merchant account to your app

Before you connect, confirm the mandates exist by running `gocardless list mandates` or checking the sandbox dashboard.

Go through the [OAuth flow](#test-the-oauth-flow) from your app and sign in as the merchant test account.

### 4. Sync the mandates in your app

In your app, start the sync, for example by selecting **Sync Existing Mandates**. Then check the following:

| Check                    | Expected result                                                                                                                                           |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Mandates are retrieved   | Your integration lists the merchant's mandates and customers using the merchant's access token, and joins them on `mandates[].links.customer`.            |
| Matching                 | Each mandate you created ends up in the match tier you expected: auto-matched, probable match, or unresolved.                                             |
| Review and confirmation  | The merchant can confirm, reassign, manually pair or skip mandates. Nothing is linked until they confirm.                                                 |
| Mandate links are stored | After confirmation, you store the GoCardless mandate ID against the matched customer, and the mandate is available for collecting payments.               |
| Collecting a payment     | You can create a payment against an imported mandate. Use the `payment_paid_out` simulator to check that your integration handles the resulting webhooks. |

If any of these produce unexpected results, refer back to [Supporting mandates set up outside of your product](/docs/partner-integrations/supporting-mandates-set-up-outside-of-your-product).

## What's next?

  
#### [Go-live checklist](/docs/partner-integrations/go-live-checklist)

Record your demonstration video and submit your integration for review.

  
#### [Scenario simulators](/docs/developer-resources/scenario-simulators)

See every simulator and name-triggered scenario available in the sandbox.

  
#### [GC CLI](/docs/developer-resources/gc-cli)

See the triggers available in the GoCardless CLI