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

# Integration Patterns

> Shared conventions for auth, proxying, idempotency, and amounts across Endaoment API integrations.

These patterns apply across the [standard journey](./overview) steps. Read this once before implementing individual flows.

## Environment configuration

Keep base URLs in config and swap by environment:

```bash theme={null}
ENDAOMENT_AUTH_URL=https://auth.dev.endaoment.org
ENDAOMENT_API_URL=https://api.dev.endaoment.org
```

Examples in this quickstart use **dev**. Do not hardcode production URLs while building.

## Backend proxy

Endaoment user access tokens must stay on your server. Your frontend calls your backend; your backend calls Endaoment with the user's Bearer token.

```js theme={null}
async function proxyToEndaoment(path, token, options = {}) {
  const response = await fetch(`${process.env.ENDAOMENT_API_URL}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`,
      ...options.headers,
    },
  });

  return response.json();
}
```

**Why:** OAuth tokens are secrets. Never expose them in browser code or mobile clients.

## OAuth with PKCE

Standard donor integrations authenticate users with OAuth 2.0 Authorization Code + PKCE:

1. Your backend creates `code_verifier`, `code_challenge`, and `state`.
2. Redirect the user to `{AUTH_URL}/auth` with `client_id`, `redirect_uri`, PKCE params, scopes, and `prompt=consent` when you need refresh tokens.
3. User logs in; Endaoment redirects back with `code` and `state`.
4. Your backend exchanges the code at [`POST {AUTH_URL}/token`](/developers/api/authentication/get-access-token) using `Authorization: Basic base64(clientId:clientSecret)` and the stored `code_verifier`.
5. Store `access_token` (and optionally `refresh_token`) for subsequent API calls.

**Scopes:** The auth server supports:

| Scope            | Claims / purpose                                                    |
| ---------------- | ------------------------------------------------------------------- |
| `openid`         | OpenID Connect baseline                                             |
| `accounts`       | FDX account data                                                    |
| `transactions`   | FDX transaction data                                                |
| `profile`        | `first_name`, `last_name`, `wallet`                                 |
| `email`          | User email address                                                  |
| `address`        | User physical address                                               |
| `offline_access` | Refresh tokens (requires `prompt=consent` on the authorize request) |

Common quickstart combination: `openid accounts transactions profile email address`. Add `offline_access` only when you need refresh tokens — and include `prompt=consent` on the `/auth` redirect or refresh tokens are silently omitted.

**Redirect URIs:** Local dev commonly uses `http://localhost:5454`. Register all redirect URLs with Endaoment before testing.

Full PKCE implementation: [GitHub quickstart sample](https://github.com/endaoment/endaoment-integration-docs/tree/main/quickstart/backend).

## Dev token shortcut

While OAuth is in progress, issue test tokens with the [Access Token Issuer Tool](https://app.dev.endaoment.org/dev/token). Development only—not for production.

## Bearer authentication

Authenticated Endaoment API calls use the user's access token:

```bash theme={null}
Authorization: Bearer <access_token>
```

Verify the caller with [`GET /v1/auth/whoami`](/developers/api/authentication/get-authenticated-caller).

## Partner auth options

Most partner endpoints require `x-api-key`. Acting-user context varies by endpoint — check the specific API reference page before integrating.

`POST /v1/funds/partner` accepts **either** a registered OAuth user Bearer token **or** partner server-to-server credentials (`x-api-key`, optionally with impersonation headers or body `partnerUserIdentifier`).

### Partner fund creation (`POST /v1/funds/partner`)

Pick the path that matches your integration preference:

| Path                                  | Headers / body                                | Best for                                             |
| ------------------------------------- | --------------------------------------------- | ---------------------------------------------------- |
| **A. Registered OAuth user bearer**   | `Authorization: Bearer <access_token>`        | Standard OAuth quickstart after user login           |
| **B. API key + body user id**         | `x-api-key` + `partnerUserIdentifier` in body | Pure server-to-server; user already provisioned      |
| **C. API key + impersonation header** | `x-api-key` + `x-endaoment-user-id`           | Server-to-server when you store Endaoment user UUIDs |
| **D. Partner OIDC bearer**            | `Authorization: Bearer <partner_oidc_token>`  | Partner apps that already hold an OIDC access token  |

When both a header/OIDC user and body `partnerUserIdentifier` are supplied, they must resolve to the same user.

### Partner settled donations (`POST /v1/donation-pledges/partner/*-settled`)

| Path                                  | Headers / body                                | Best for                                                                             |
| ------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------ |
| **A. API key + impersonation header** | `x-api-key` + `x-endaoment-user-id`           | Partners that track Endaoment user UUIDs                                             |
| **B. API key + body user id**         | `x-api-key` + `partnerUserIdentifier` in body | API-key-only when partner inflow routes are enabled and partner has `canManageUsers` |

### Other partner endpoints

| Endpoint                                       | Typical auth     |
| ---------------------------------------------- | ---------------- |
| `POST /v1/auth/partner/users`                  | `x-api-key` only |
| `GET /v1/funds/partner/{id}`                   | `x-api-key` only |
| `POST /v1/transfers/partner/grant-submissions` | `x-api-key` only |
| `POST /v1/missing-org-reports/tech-platform`   | `x-api-key` only |

See [Partner Journey](./partner-journey) and [Partner Endpoints](/developers/api/partner-endpoints/provision-user).

## Idempotency

Donation pledges and grant submissions require an `idempotencyKey` in the request body. Generate a new UUID per user action. Reusing the same key with different payload data returns a conflict.

```js theme={null}
import { randomUUID } from 'crypto';

const idempotencyKey = randomUUID();
```

## Amounts in microdollars

Monetary fields use **microdollars** (1 USD = `1_000_000`):

| Dollars  | Microdollars |
| -------- | ------------ |
| \$1.00   | `1000000`    |
| \$100.00 | `100000000`  |

```js theme={null}
const microdollars = Math.round(dollars * 1_000_000);
```

## Public vs authenticated endpoints

Some endpoints do not require a Bearer token:

| Endpoint                                              | Auth |
| ----------------------------------------------------- | ---- |
| `GET /v2/orgs/search`                                 | None |
| `GET /v1/donation-pledges/wire/details/domestic`      | None |
| `GET /v1/donation-pledges/wire/details/international` | None |

You may call these from your backend or directly from a client. Authenticated flows should still prefer a backend proxy for consistency.

## Optional: collaborators

To add or remove fund collaborators after opening a fund, see [Manage Collaborators](/advisors/collaboration/manage-collaborators) in the Collaboration endpoint bucket.
