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

# Authentication

> Prove which Stellar account your user owns. Every transfer belongs to that account.

Every transfer has an **owner**: a Stellar `G...` address. Deposits deliver only to the owner, and withdrawals and sends spend only from it. The API learns the owner from the bearer token on each request.

There are two ways to get a token.

| Method | For | Owner |
| - | - | - |
| SEP-10 | Any app with a Stellar wallet (Freighter, Stellar Wallets Kit, your own keys) | The account that signed the challenge |
| Privy access token | Apps built on Pesa's Privy app, such as the Pesa mobile app | The user's embedded Privy Stellar wallet |

## SEP-10

SEP-10 is Stellar's standard web authentication. Your app asks for a challenge transaction, the user's wallet signs it, and the API returns a JWT.

<Steps>
  <Step title="Ask for a challenge">
    ```bash theme={null}
    curl "https://api-testnet.pesapay.xyz/auth?account=GABC...XYZ"
    ```

    The response has `transaction` (a base64 XDR challenge) and `network_passphrase`.
  </Step>

  <Step title="Sign it with the user's wallet">
    ```ts theme={null}
    import { StellarWalletsKit } from "@creit.tech/stellar-wallets-kit";

    const { signedTxXdr } = await kit.signTransaction(challenge.transaction, {
      networkPassphrase: challenge.network_passphrase,
    });
    ```
  </Step>

  <Step title="Exchange it for a token">
    ```bash theme={null}
    curl -X POST https://api-testnet.pesapay.xyz/auth \
      -H "content-type: application/json" \
      -d '{"transaction": "<signed XDR>"}'
    ```

    The response is `{ "token": "<JWT>" }`.
  </Step>
</Steps>

Send the token as `Authorization: Bearer <token>`. With the SDK, return it from `getToken`:

```ts theme={null}
const pesa = createTransfersClient({
  baseUrl: "https://api-testnet.pesapay.xyz",
  getToken: () => token,
});
```

## Privy access token

If your app signs users in with Pesa's Privy app, send the Privy access token as the bearer token. The API checks the token's ES256 signature and looks up the user's linked Stellar wallet. Only the embedded Privy Stellar wallet counts as the owner.

```ts theme={null}
import { getAccessToken } from "@privy-io/expo";

const pesa = createTransfersClient({ baseUrl, getToken: () => getAccessToken() });
```

## Public routes

`GET /v1/routes` and the SEP-10 endpoints need no token. Everything else returns `401` without one.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.