# Quickstart

Connect one customer end to end in Test mode. Replace the placeholders with your Test keys, from **API keys** in the partner portal's Test mode.

In Test mode the customer is a test customer you make up. Test data lists what to use: an email at `sandbox.madecard.com` that starts with your company's name and ends with something random, whose codes Made's window shows on screen, a test phone number, and an SSN of their own. Use a new email each time you run through this guide.

## 1. Get a partner JWT

```bash
curl -X POST https://api-sandbox.madecard.com/v1/partners/auth \
  -H "Content-Type: application/json" \
  -d '{"client_id": "pk_test_yourcompany", "client_secret": "sk_test_..."}'
```

Test keys start with `pk_test_` and `sk_test_`. Keys issued before these prefixes (`pk_yourcompany`, `sk_...`) keep working.

```json
{
  "error": null,
  "message": "Authentication successful",
  "data": {
    "access_token": "eyJhbGciOi...",
    "token_type": "bearer",
    "expires_in": 3600,
    "partner_id": "7270dd85-8fdc-443e-8777-bdba887ef138",
    "slug": "yourcompany",
    "livemode": false
  }
}
```

Send `data.access_token` as `Authorization: Bearer <token>` on every other call. Request a new one before `expires_in` runs out. `livemode` is `false` in Test mode and `true` in Live mode.

## 2. Start a link session

```bash
curl -X POST https://api-sandbox.madecard.com/v1/partners/link/sessions \
  -H "Authorization: Bearer $PARTNER_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "apply",
    "prefill": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "yourcompany-ada-7k2m@sandbox.madecard.com",
      "address_line_1": "1 Main St",
      "city": "Virginia Beach",
      "state": "VA",
      "zipcode": "23451"
    },
    "lock_fields": ["first_name", "last_name", "email", "address"]
  }'
```

The response is HTTP 201 and contains `link_url`. It expires in 60 minutes.

## 3. Open it in the browser

```html
<script src="https://staging-app.madecard.com/sdk/v1/made-link.js"></script>
<button id="apply" disabled>Apply for Made Card</button>
<script>
  const button = document.getElementById("apply");
  let made;
  fetch("/made/link-session", { method: "POST" })
    .then((r) => r.json())
    .then(({ link_url }) => {
      made = MadeLink.create({
        linkUrl: link_url,
        onSuccess: (publicToken) =>
          fetch("/made/exchange", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ public_token: publicToken }),
          }),
        onExit: (error) => console.log("Made Link ended:", error ? error.code : "closed by the customer"),
      });
      button.disabled = false;
    });
  button.addEventListener("click", () => made.open());
</script>
```

`/made/link-session` and `/made/exchange` are routes on your own server. The browser never sees your partner JWT, `client_secret`, or the customer `access_token`. The session is created before the click so `open()` runs inside the click handler, where browsers allow new windows. The Web SDK page has the full example.

## 4. Exchange the public token

```bash
curl -X POST https://api-sandbox.madecard.com/v1/partners/link/token \
  -H "Authorization: Bearer $PARTNER_JWT" \
  -H "Content-Type: application/json" \
  -d '{"public_token": "public_..."}'
```

Store `data.access_token` (`link_...`) and `data.user_id` against your own customer record.

## 5. Open Made Card on a later visit

```bash
curl -X POST https://api-sandbox.madecard.com/v1/partners/sessions/launch \
  -H "Authorization: Bearer $PARTNER_JWT" \
  -H "Content-Type: application/json" \
  -d '{"access_token": "link_...", "target_path": "/dashboard/home"}'
```

The response is HTTP 201. Open `data.launch_url` within 5 minutes, for example with `MadeLink.openLaunchUrl(launch_url)`. The customer lands in Made Card already signed in.
