Skip to content

Cantilapay SDK reference phase-2

@cantila/cantilapay v0.1.0. Construct one client and access every resource as a property:

import { Cantilapay } from "@cantila/cantilapay";

const cp = new Cantilapay(process.env.CANTILAPAY_SECRET_KEY!);

Every method accepts an optional final RequestOptions argument:

FieldTypeDescription
idempotencyKeystringOverride the auto-generated idempotency key.
noIdempotencybooleanSkip the idempotency key entirely.
timeoutMsnumberPer-request timeout override.

All amounts are integer minor units (1000 = $10.00). Every object carries a mode of test or live matching your API key.

Accounts

Your Cantilapay account is the merchant-of-record account tied to the API key.

MethodParametersReturnsDescription
accounts.retrieve()AccountThe account for the current API key.
accounts.onboardingLink(input){ mode, country, returnUrl }{ url, expiresAt }Hosted KYC link for the given mode.
const account = await cp.accounts.retrieve();
if (!account.testReady) {
  const { url } = await cp.accounts.onboardingLink({
    mode: "test",
    country: "US",
    returnUrl: "https://app.example.com/payments",
  });
  // redirect to `url`
}

Customers

MethodParametersReturnsDescription
customers.create(input){ externalRef?, email?, name?, description?, metadata? }CustomerCreate a customer.
customers.retrieve(id)idCustomerFetch by id.
customers.list(params?){ limit? }{ customers: Customer[] }List customers.
customers.update(id, input)id, { externalRef?, email?, name?, description?, metadata? }CustomerUpdate fields.
customers.del(id)id{ id, deleted }Delete a customer.
const customer = await cp.customers.create({
  email: "buyer@example.com",
  name: "Ada Lovelace",
  externalRef: "user_42",
});

Payment Intents

The core charge object. Lifecycle is driven by status (see enums).

MethodParametersReturnsDescription
paymentIntents.create(input){ amount, currency, customerId?, paymentMethodId?, captureMode?, description?, metadata? }PaymentIntentCreate an intent.
paymentIntents.retrieve(id)idPaymentIntentFetch by id.
paymentIntents.list(params?){ customerId?, limit? }{ payment_intents: PaymentIntent[] }List intents.
paymentIntents.confirm(id, input?)id, { paymentMethodId? }?PaymentIntentConfirm and attempt the charge.
paymentIntents.capture(id)idPaymentIntentCapture a requires_capture intent.
paymentIntents.cancel(id)idPaymentIntentCancel an uncaptured intent.
const intent = await cp.paymentIntents.create({
  amount: 2500,
  currency: "usd",
  customerId: customer.id,
  paymentMethodId: method.id,
  captureMode: "manual", // capture later
});
const confirmed = await cp.paymentIntents.confirm(intent.id);
if (confirmed.status === "requires_capture") {
  await cp.paymentIntents.capture(intent.id);
}

Payment Methods

A pspToken is a payment token captured client-side (e.g. from the Adyen Drop-in component).

MethodParametersReturnsDescription
paymentMethods.create(input){ pspToken, customerId?, metadata? }PaymentMethodTokenize and store a method.
paymentMethods.retrieve(id)idPaymentMethodFetch by id.
paymentMethods.list(params?){ customerId?, limit? }{ payment_methods: PaymentMethod[] }List methods.
paymentMethods.detach(id)idPaymentMethodDetach from its customer.
const method = await cp.paymentMethods.create({
  pspToken: "tok_from_dropin",
  customerId: customer.id,
});
console.log(method.card?.brand, method.card?.last4);

Subscriptions

Recurring billing against a Price.

MethodParametersReturnsDescription
subscriptions.create(input){ customerId, priceId, defaultPaymentMethodId?, trialPeriodDays?, metadata? }SubscriptionStart a subscription.
subscriptions.retrieve(id)idSubscriptionFetch by id.
subscriptions.list(params?){ customerId?, status?, limit? }{ subscriptions: Subscription[] }List subscriptions.
subscriptions.update(id, input)id, { cancelAtPeriodEnd?, defaultPaymentMethodId?, metadata? }SubscriptionUpdate a subscription.
subscriptions.cancel(id, input?)id, { atPeriodEnd? }?SubscriptionCancel now or at period end.
const sub = await cp.subscriptions.create({
  customerId: customer.id,
  priceId: price.id,
  defaultPaymentMethodId: method.id,
  trialPeriodDays: 14,
});
// Cancel at the end of the current period instead of immediately:
await cp.subscriptions.cancel(sub.id, { atPeriodEnd: true });

Refunds

MethodParametersReturnsDescription
refunds.create(input){ paymentIntentId, amount?, reason? }RefundRefund a charge (full or partial).
refunds.retrieve(id)idRefundFetch by id.
refunds.list(params?){ paymentIntentId?, limit? }{ refunds: Refund[] }List refunds.
// Omit `amount` for a full refund.
await cp.refunds.create({
  paymentIntentId: intent.id,
  amount: 500, // partial: $5.00
  reason: "requested_by_customer",
});

Products

MethodParametersReturnsDescription
products.create(input){ name, description?, active?, metadata? }ProductCreate a product.
products.retrieve(id)idProductFetch by id.
products.list(params?){ active?, limit? }{ products: Product[] }List products.
products.update(id, input)id, { name?, description?, active?, metadata? }ProductUpdate a product.
const product = await cp.products.create({ name: "Pro Plan" });

Prices

A price attaches a recurring amount to a product.

MethodParametersReturnsDescription
prices.create(input){ productId, unitAmount, currency, recurring: { interval, intervalCount?, trialPeriodDays? }, metadata? }PriceCreate a price.
prices.retrieve(id)idPriceFetch by id.
prices.list(params?){ productId?, active?, limit? }{ prices: Price[] }List prices.
const price = await cp.prices.create({
  productId: product.id,
  unitAmount: 2900, // $29.00
  currency: "usd",
  recurring: { interval: "month", intervalCount: 1 },
});

Invoices

Invoices are generated for subscription billing. You can read and resolve them, but not create them directly.

MethodParametersReturnsDescription
invoices.retrieve(id)idInvoiceFetch by id.
invoices.list(params?){ customerId?, subscriptionId?, status?, limit? }{ invoices: Invoice[] }List invoices.
invoices.voidInvoice(id)idInvoiceVoid an open invoice.
invoices.markUncollectible(id)idInvoiceMark as uncollectible.
const { invoices } = await cp.invoices.list({
  subscriptionId: sub.id,
  status: "open",
});

Checkout Sessions

A hosted or embedded checkout flow.

MethodParametersReturnsDescription
checkoutSessions.create(input){ sessionMode, uiMode?, customerId?, successUrl, cancelUrl?, returnUrl?, currency, paymentItems?, subscriptionItems?, metadata? }CheckoutSessionCreate a session.
checkoutSessions.retrieve(id)idCheckoutSessionFetch by id.
checkoutSessions.list(params?){ status?, limit? }{ checkout_sessions: CheckoutSession[] }List sessions.
checkoutSessions.complete(id, input)id, { paymentMethodId }CheckoutSessionComplete an embedded session.

sessionMode is payment | subscription | setup; uiMode is hosted | embedded. paymentItems take { name, amount, currency, quantity? }; subscriptionItems take { priceId, quantity? }.

const session = await cp.checkoutSessions.create({
  sessionMode: "payment",
  uiMode: "hosted",
  currency: "usd",
  successUrl: "https://app.example.com/success",
  cancelUrl: "https://app.example.com/cart",
  paymentItems: [{ name: "T-shirt", amount: 1999, currency: "usd", quantity: 2 }],
});
// Redirect the buyer to `session.url`.

Billing Portal

A hosted session where customers manage their own subscriptions and payment methods.

MethodParametersReturnsDescription
billingPortalSessions.create(input){ customerId, returnUrl? }BillingPortalSessionCreate a portal session.
billingPortalSessions.retrieve(id)idBillingPortalSessionFetch by id.
const portal = await cp.billingPortalSessions.create({
  customerId: customer.id,
  returnUrl: "https://app.example.com/account",
});
// Redirect to `portal.url`.

Payouts

Move available balance to your bank account.

MethodParametersReturnsDescription
payouts.create(input?){ amount?, currency? }?PayoutCreate a payout (omit amount to pay out all available).
payouts.retrieve(id)idPayoutFetch by id.
payouts.list(params?){ status?, limit? }{ payouts: Payout[] }List payouts.
await cp.payouts.create({ currency: "usd" }); // pay out all available USD

Balance

MethodParametersReturnsDescription
balance.retrieve(params?){ currency? }?BalanceAvailable and pending balance.
balance.listTransactions(params?){ limit? }?{ balance_transactions: BalanceTransaction[] }Ledger entries.
const balance = await cp.balance.retrieve({ currency: "usd" });
console.log(balance.available, balance.pending);

Tax

MethodParametersReturnsDescription
tax.calculate(input){ amount, currency, customerCountry, customerState?, customerPostalCode?, productCategory? }TaxCalculationCalculate tax for an amount.
tax.retrieve(id)idTaxCalculationFetch a prior calculation.
const calc = await cp.tax.calculate({
  amount: 10000,
  currency: "usd",
  customerCountry: "US",
  customerState: "CA",
  customerPostalCode: "94016",
});
console.log(calc.taxAmount, calc.taxRateBps);

Webhooks

Verify inbound event signatures. See the webhooks guide for a full handler.

MethodParametersReturnsDescription
webhooks.verify(input){ rawBody, signatureHeader, signingSecret, toleranceSeconds? }true (throws on failure)Validate a Cantilapay-Signature header.
cp.webhooks.verify({
  rawBody,
  signatureHeader: req.headers["cantilapay-signature"],
  signingSecret: process.env.CANTILAPAY_WEBHOOK_SECRET!,
});

Errors

Every non-2xx response throws a CantilapayError:

import { Cantilapay, CantilapayError } from "@cantila/cantilapay";

try {
  await cp.paymentIntents.confirm("pi_xxx");
} catch (err) {
  if (err instanceof CantilapayError) {
    console.error(err.status, err.type, err.code, err.message, err.param, err.requestId);
  }
}

CantilapayError fields:

FieldTypeDescription
statusnumberHTTP status (0 for network/timeout).
typeCantilapayErrorTypeError category (see below).
codestringMachine-readable code, e.g. card_declined.
messagestringHuman-readable message.
paramstring?Offending parameter, when applicable.
requestIdstring?Request id for support / log correlation.

Error type values:

TypeMeaning
api_errorServer-side, network, or timeout failure.
invalid_request_errorMalformed request or bad parameters.
authentication_errorMissing or invalid API key.
permission_errorKey lacks permission for the action.
rate_limit_errorToo many requests; back off and retry.
idempotency_errorIdempotency key reused with a different payload.
card_errorCard declined or otherwise unusable.
resource_missingReferenced object does not exist.

Idempotency

Mutating calls (POST, PUT, PATCH, DELETE) auto-attach a generated Cantilapay-Idempotency-Key: auto_<hex> header so retries never apply an operation twice. Control it per call via RequestOptions:

// Use your own key (recommended for important writes):
await cp.paymentIntents.create(
  { amount: 1000, currency: "usd" },
  { idempotencyKey: "order-4821" },
);

// Skip idempotency entirely:
await cp.customers.create({ email: "x@y.com" }, { noIdempotency: true });

Reusing a key with a different payload raises an idempotency_error. You can also disable the auto behaviour globally with autoIdempotency: false in the client options.

Enums

EnumValues
Modetest, live
PaymentIntentStatusrequires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceled, failed
SubscriptionStatusincomplete, trialing, active, past_due, canceled, unpaid
PriceIntervalday, week, month, year