POST/v1/partner/end_users

Create end user

Registers a new end user within your tenant and provisions a Privy-managed wallet for them on the configured chain. Returns immediately (no on-chain transactions). You supply a stable external_id (your own user identifier) and a user_jwt (a partner-minted JWT for that user). This endpoint is Entra token only (Entra token, no user token).

If the external_id already exists and the existing user is not deleted, the server returns 201 with the existing user object — creation is idempotent on external_id.

Headers

Authorizationstringrequired

Entra M2M access token. Format: Bearer <token>. See Entra authentication.

Content-Typestringrequired

Must be application/json.

Body

external_idstringrequired

Your stable identifier for this user. 1–128 characters; allowed characters: alphanumeric, -, _, .. Must be unique within your tenant. Example: alice-bunq-id.

user_jwtstringrequired

A partner-minted JWT for this user, signed with your RSA-2048 private key. The sub claim must equal external_id. The iss claim must match your registered JWKS issuer URL. See User authentication for the full signing spec and key requirements.

Example request

const baseUrl = process.env.YIELDFORCE_API_BASE_URL ?? 'https://yieldforce.io/api';
 
const res = await fetch(`${baseUrl}/v1/partner/end_users`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${entraToken}`,
  },
  body: JSON.stringify({
    external_id: 'alice-bunq-id',
    user_jwt: 'eyJhbGciOiJSUzI1NiIs...',
  }),
});
const data = await res.json();

Response

201 End user created (or already exists)

{
  "id": "usr_01HZ4KXQM5E8WRTYN3P7VBJD6F",
  "external_id": "alice-bunq-id",
  "tenant_id": "tnt_01HZ4KXQM5ABCDEF12345678",
  "tenant_slug": "bunq",
  "user_source": "partner",
  "wallet_address": "0xabc123...def456",
  "created_at": "2026-05-20T10:00:00.000Z"
}

The user_jwt you supply here is also the X-User-Token for user-scoped endpoints

The JWT you pass in the body during creation is the same credential format used in the X-User-Token header for all user-scoped endpoints (portfolios, deposit, withdraw, etc.). You may generate a fresh JWT at request time — the key requirement is that sub always matches the external_id in the URL.

Errors

400 validation_errorexternal_id contains invalid characters, exceeds 128 chars, or user_jwt is missing. Check the detail field for the specific validation failure.

400 external_id_jwt_sub_mismatch — The external_id in the request body does not match the sub claim in user_jwt. Ensure both values are identical.

401 token_missing — No Authorization: Bearer header on the request.

401 invalid_entra_token — Token is expired, malformed, or has an unexpected audience.

422 jwt_invalid — The user_jwt could not be verified. Ensure the JWT is signed with your registered RSA private key and that iss, aud, and sub claims are correct.