Skip to main content
These patterns apply across the standard journey steps. Read this once before implementing individual flows.

Environment configuration

Keep base URLs in config and swap by environment:
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.
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 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:
ScopeClaims / purpose
openidOpenID Connect baseline
accountsFDX account data
transactionsFDX transaction data
profilefirst_name, last_name, wallet
emailUser email address
addressUser physical address
offline_accessRefresh 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.

Dev token shortcut

While OAuth is in progress, issue test tokens with the Access Token Issuer Tool. Development only—not for production.

Bearer authentication

Authenticated Endaoment API calls use the user’s access token:
Authorization: Bearer <access_token>
Verify the caller with GET /v1/auth/whoami.

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:
PathHeaders / bodyBest for
A. Registered OAuth user bearerAuthorization: Bearer <access_token>Standard OAuth quickstart after user login
B. API key + body user idx-api-key + partnerUserIdentifier in bodyPure server-to-server; user already provisioned
C. API key + impersonation headerx-api-key + x-endaoment-user-idServer-to-server when you store Endaoment user UUIDs
D. Partner OIDC bearerAuthorization: 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)

PathHeaders / bodyBest for
A. API key + impersonation headerx-api-key + x-endaoment-user-idPartners that track Endaoment user UUIDs
B. API key + body user idx-api-key + partnerUserIdentifier in bodyAPI-key-only when partner inflow routes are enabled and partner has canManageUsers

Other partner endpoints

EndpointTypical auth
POST /v1/auth/partner/usersx-api-key only
GET /v1/funds/partner/{id}x-api-key only
POST /v1/transfers/partner/grant-submissionsx-api-key only
POST /v1/missing-org-reports/tech-platformx-api-key only
See Partner Journey and Partner Endpoints.

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.
import { randomUUID } from 'crypto';

const idempotencyKey = randomUUID();

Amounts in microdollars

Monetary fields use microdollars (1 USD = 1_000_000):
DollarsMicrodollars
$1.001000000
$100.00100000000
const microdollars = Math.round(dollars * 1_000_000);

Public vs authenticated endpoints

Some endpoints do not require a Bearer token:
EndpointAuth
GET /v2/orgs/searchNone
GET /v1/donation-pledges/wire/details/domesticNone
GET /v1/donation-pledges/wire/details/internationalNone
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 in the Collaboration endpoint bucket.