# CoverPay sandbox testing

Test keys (`cp_test_…`) create sandbox link tokens (`lt_test_…`). Payments go through Stripe's test mode: no real money moves.

## Provider payments

Pick Klarna, Affirm, Afterpay or Zip in Link. You land on the provider's test page.

| Provider | Test page | To approve | To fail |
|---|---|---|---|
| Affirm, Afterpay, Zip | Stripe's test payment page | Authorize test payment | Fail test payment |
| Klarna | Klarna's playground | Follow the test login | Cancel |

Approving returns `onSuccess` with a public token; failing returns `onExit` with `PAYMENT_FAILED`. Each provider shows only for amounts in its range.

## CoverPay's own plan

CoverPay fills in when no provider approves: pay in 4, every 2 weeks, 0% APR, up to $500 per shopper (minus what they still owe), from $10. To see it, make every provider decline with a sandbox-only flag on the link token:

```json
POST /v1/link/token/create
{ "amount": 12000, "currency": "USD", "merchantName": "My Store", "orderId": "order_1",
  "customerId": "user_1", "metadata": { "coverpay_test": "providers_decline" } }
```

Pick CoverPay, then pay the first payment on Stripe's page with a test card:

| Card | What happens |
|---|---|
| `4242 4242 4242 4242` | Succeeds now and later. |
| `4000 0000 0000 0341` | Saves, then every later charge fails. |

Any future expiry, any CVC, ZIP 94103.

## Collecting the rest without waiting

Payments 2 to 4 are charged automatically when due. In sandbox:

```
POST /v1/credit/loans/{payment_id}/make-due      # next payment due now; the collector charges it
POST /v1/credit/loans/{payment_id}/collect-next  # or charge it immediately
GET  /v1/credit/loans/{payment_id}               # plan, schedule and your payout
```

A failed payment marks the plan `behind` and is retried after 24 hours, up to 3 times.

## Your payout

When payment 1 succeeds, CoverPay pays you the plan amount minus your CoverPay fee (0% in sandbox) through Stripe Connect. Set up payouts once with `POST /v1/payouts/onboarding` (Stripe-hosted, test values accepted) and check them with `GET /v1/payouts`.

## Things that should be refused

| Try | Expect |
|---|---|
| Change the amount in the browser before paying | The payment is for the link token amount anyway |
| Open Link with an API key instead of a link token | Throws before opening |
| Exchange a public token with another business's key | 404 |
| Reuse a finished link token | 410 `USED_LINK_TOKEN` |
| Send a webhook without a valid signature | 401 |

Use test cards and Stripe's test identity values only. Never real personal or bank details.
