> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yabetoopay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing Connect

> What you can verify in the test environment, and what needs a manual intervention.

Connect is tested with your `sk_test_` keys, on the same endpoints as production.

## The environment is inherited, never chosen

<Warning>
  **An `sk_test_` key only creates test vendors, and can only target them.** The environment of
  a connected account is inherited from the key that created it: there is no field to choose it.

  Targeting a `live` vendor with a test key (or the reverse) returns `401`, on **every** Connect
  route. This is not a key bug: it is the isolation barrier.
</Warning>

This is the first symptom to recognise: a `401` on a vendor you have just created almost
always means you changed keys between the two calls.

## 1. Activate Connect on your test account

Activation happens in your [dashboard](https://app.yabetoo.com/dashboard/connect), under
**Connect**, with your test account.

<Warning>
  **The mode is immutable, including in test.** You will not be able to switch your test account
  from `marketplace` to `platform` to compare the two cascades. To test both modes you need
  **two separate merchant accounts**.
</Warning>

Then check that your integration really reads the mode:

```bash theme={null}
curl https://pay.sandbox.yabetoopay.com/v1/connect/activations \
  -H "Authorization: Bearer sk_test_..."
```

## 2. Create test vendors

Nothing distinguishes the creation of a test vendor: same fields, same required
`Idempotency-Key`.

<Tip>
  Create **at least two**, and keep one you never verify: it is the only way to exercise the
  verification-related refusals (`403 E_VERIFICATION_REQUIRED`,
  `422 E_CONNECT_VENDOR_PAYOUT_METHOD_UNAVAILABLE`).
</Tip>

<Tip>
  Also create a vendor under a **second merchant account**. It is the only way to check that
  your code handles the `403` of a vendor that is not yours, a case you will meet in production
  as soon as an identifier slips from one tenant to another.
</Tip>

## 3. Verification is not instant in test

<Warning>
  **Do not count on automatic approval in test.** You will get the link, the vendor will be able
  to submit their documents and their payout destination, but the file goes through a **review**:
  its move to `approved` is neither immediate nor guaranteed.

  To obtain an **approved** test vendor (needed to exercise withdrawals), contact
  [support@yabetoopay.com](mailto:support@yabetoopay.com).
</Warning>

What you can verify without approval:

* link generation and expiry (`expires_at`);
* the fact that regenerating the link **resumes** the session instead of opening a second one;
* the `422` refusals on `country` and `kycLevel`;
* that funds do accumulate while no withdrawal is possible.

## 4. Test collection and the cascade

The split is computed at **capture**. Use the usual test numbers to drive the payment outcome.
See [Test your integration](/en/developer-tools/test/overview).

<Steps>
  <Step title="Create the intent with the Connect fields">
    ```json theme={null}
    { "amount": 10000, "currency": "xaf",
      "on_behalf_of": "acct_...", "application_fee_rate": 10 }
    ```
  </Step>

  <Step title="Confirm with a test number that succeeds">
    The split only happens on a successful capture.
  </Step>

  <Step title="Read the vendor's balances back">
    ```bash theme={null}
    GET /v1/connect/accounts/{acct}
    ```

    You should see the vendor net in `pending_balance`, and **`balance` at zero**.
  </Step>
</Steps>

<Tip>
  **Check conservation, not just the HTTP code.** On every capture,
  `vendor net + your net + Yabetoo fees` must equal the gross exactly. That is the assertion
  that catches a mode or unit error; a `201` proves nothing.
</Tip>

### Exercising the commission refusals

| To obtain                              | Send                                                                                             |
| -------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `400 connect.application_fee_too_low`  | an `application_fee_rate` **at or below** the floor of your grid (4.5% on the standard schedule) |
| `400 connect.application_fee_too_high` | a rate that produces a commission larger than the gross                                          |
| `422 connect.incomplete_request`       | `on_behalf_of` without `application_fee_rate`                                                    |
| `422 connect.fee_payer_unset`          | a Connect call **before** activating Connect                                                     |
| `403`                                  | a made-up, malformed, or another merchant's `acct_`                                              |

<Note>
  The `too_low` refusal does **not** depend on the amount: a rate under the floor fails at
  100 XAF just as it does at 1,000,000. There is no point looking for an amount that triggers it.
</Note>

## 5. The availability delay

<Warning>
  **This is the main difficulty of end-to-end testing.** A vendor's funds land in
  `pending_balance` and only become withdrawable after the availability delay, **7 days by
  default**. There is no test clock and no endpoint to force maturation.

  To test the full chain in one session, ask support for a shortened delay on your test
  environment.
</Warning>

In the meantime, you can verify:

* that `next_maturity_at` carries the expected date;
* that `available_at` is set and `matured_at` is null on the transaction;
* that a withdrawal against a still-pending balance really returns
  `422 E_CONNECT_VENDOR_EMPTY_BALANCE`, and not a generic error.

## 6. Test deferred mode without waiting

[Deferred mode](/en/connect/payments/allocations) can be exercised **without a real
collection**: all you need is a balance on your own merchant wallet.

It is the fastest way to verify:

* the 1% surcharge and the meaning of `amount` in the response;
* a partial then a full reversal, and the `reversed_total` running sum;
* the `422 connect.reversal_exceeds_remaining` when you exceed the remainder;
* the `402` on reversal when the vendor cannot return the funds.

## 7. Test idempotency for real

<Tip>
  Replay every money call **with the same `Idempotency-Key`** and check that no second operation
  was created (by reading the balances back, not by reading the HTTP code).

  Also check the opposite case: the **same key on two different vendors** must produce **two**
  operations. An implementation that deduplicates there would only pay one vendor out of two.
</Tip>

## What cannot be tested

|                                                          | Why                                |
| -------------------------------------------------------- | ---------------------------------- |
| `platform` mode on an account activated as `marketplace` | `connect_mode` is immutable        |
| Unlinking or transferring a vendor                       | These operations do not exist      |
| Multi-currency                                           | A different currency is refused    |
| Automatic KYC approval                                   | Review is not automatic in test    |
| Automatic return at the end of onboarding                | Connect v1 exposes no `return_url` |

## Going to production

<Steps>
  <Step title="Activate Connect with your live key">
    Activation is **per account and per environment**: activating in test does not activate in
    production.
  </Step>

  <Step title="Recreate your vendors">
    A test vendor does not exist in production. No migration is possible, and their
    verification has to be done again.
  </Step>

  <Step title="Rewire your webhooks">
    Check that you subscribe to the **bare** names (`connect.transfer.created`), and that your
    routing does not assume `accountId` is your own account.
  </Step>

  <Step title="Check how you handle the 402">
    It is the refusal you will probably never see in test, and the one that costs the most in
    production. Subscribe to `connect.refund.blocked_insufficient_funds`.
  </Step>
</Steps>
