Preview Leffel Consulting Payments is in active development and migrating to Finix — the API isn't publicly live yet, and some examples still reflect the outgoing build. Request early access →

Get Started

Quickstart

Onboard a merchant and take your first payment in four steps.

This walks through the shortest path from zero to a completed payment.

1. Onboard a merchant

Create the merchant’s connected account, then send them through Stripe-hosted onboarding.

# Create the connected account
curl https://payments.leffelconsulting.com/v1/onboarding/account \
  -H "X-Api-Key: lc_live_XXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{ "email": "owner@acme.com", "country": "US" }'

# Get a hosted onboarding link and redirect the merchant to it
curl https://payments.leffelconsulting.com/v1/onboarding/account-link \
  -H "X-Api-Key: lc_live_XXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{ "refreshUrl": "https://acme.com/onboard/refresh", "returnUrl": "https://acme.com/onboard/done" }'

Poll GET /v1/onboarding/status (or listen for the account.updated callback) until chargesEnabled is true.

2. Create a payment

curl https://payments.leffelconsulting.com/v1/payments/intents \
  -H "X-Api-Key: lc_live_XXXXXXXXXXXXXXXXXXXX" \
  -H "Idempotency-Key: order-10432" \
  -H "Content-Type: application/json" \
  -d '{ "amountCents": 4999, "currency": "usd", "orderRef": "10432" }'

The response gives you everything the browser needs:

{
  "lcPaymentId": "lcpay_9f2c4b1e8a7d4c0fb1e2a3d4c5b6a7f8",
  "clientSecret": "pi_3AbC..._secret_xyz",
  "connectedAccountId": "acct_1Nvo...",
  "publishableKey": "pk_live_..."
}

3. Collect payment in the browser

const stripe = Stripe(publishableKey, { stripeAccount: connectedAccountId });
const elements = stripe.elements({ clientSecret });
elements.create("payment").mount("#payment-element");

const { error } = await stripe.confirmPayment({
  elements,
  confirmParams: { return_url: "https://acme.com/order/complete" },
});

4. Fulfill on the callback

Heads up

Don’t fulfill the order based on the browser result alone. Wait for the payment_intent.succeeded webhook callback (or check GET /v1/payments/{id}), then mark the order paid.

That’s the full loop. From here: