@delopay/sdk (英语)
脚本 SDK 类型 德罗帕 支付API. 零依赖性,在Node 18+和浏览器中工作.
安装
pnpm add @delopay/sdk
npm install @delopay/sdk
yarn add @delopay/sdk
快速启动
import { Delopay } from '@delopay/sdk';
const delopay = new Delopay(process.env.DELOPAY_API_KEY!);
const payment = await delopay.payments.create({
amount: 1000, // in minor units (€10.00)
currency: 'EUR',
description: 'Order 1234',
customer_id: 'cus_abc123',
});
console.log(payment.payment_id, payment.status);
配置
const delopay = new Delopay(apiKey, {
sandbox: true, // Use https://sandbox.delopay.net (default: false → production)
baseUrl: 'https://…', // Override base URL entirely
timeout: 30_000, // Request timeout in ms (default: 30 000)
});
API 密钥 :
prd_…编号 :snd_…——服务器侧密钥. 完全API访问. 保持这个秘密.pk_prd_…编号 :pk_snd_…——客户端可发布密钥. 限于浏览器安全操作.
用法实例
创建付款
永远不要通过SDK发送生卡号码. 德罗帕伊的API不是 生- PAN 端点: 在 Delopay 上收集卡片 主机离职 (或通过支付链接),所以卡片数据从不触及您的服务器并停留 从你的PCI范围。 服务器端您创建付款并交给购买者 关闭; 您只用保存的确认服务器侧
payment_token页:1mandate_id,或重定向方法(如PayPal钱包)——永远不要卡数据.
// Recommended: hosted checkout via a payment link.
const payment = await delopay.payments.create({
amount: 2500,
currency: 'EUR',
payment_link: true,
customer_id: 'cus_abc123',
description: 'Order 1234',
return_url: 'https://example.com/checkout/complete',
});
// Send the buyer here — they pick a method and enter card details on the
// hosted page. Delopay handles 3-D Secure and redirects.
console.log(payment.payment_link?.link);
// Fulfil on the payment_succeeded webhook, or re-check server-side:
const final = await delopay.payments.retrieve(payment.payment_id);
确认服务器侧 没有卡片数据 ——带有被保存的符号(会外):
const confirmed = await delopay.payments.confirm(pending.payment_id, {
payment_token: savedPaymentToken, // from paymentMethods.listForCustomer()
off_session: true,
return_url: 'https://example.com/checkout/complete',
});
console.log(confirmed.status); // 'succeeded' | 'requires_customer_action' | …
或采用完全没有卡片数据的重定向支付方法:
const paypal = await delopay.payments.create({
amount: 2500,
currency: 'EUR',
confirm: true,
payment_method: 'wallet',
payment_method_type: 'paypal',
payment_method_data: { wallet: { paypal_redirect: {} } },
return_url: 'https://example.com/checkout/complete',
});
// paypal.next_action?.redirect_to_url → send the buyer there to approve
创建退款
const refund = await delopay.refunds.create({
payment_id: 'pay_abc123',
amount: 1000, // partial refund; omit for full refund
reason: 'Customer request',
});
console.log(refund.refund_id, refund.status);
管理客户
const customer = await delopay.customers.create({
name: 'Jane Doe',
email: '[email protected]',
metadata: { plan: 'pro' },
});
// List saved payment methods
const { customer_payment_methods } = await delopay.paymentMethods.listForCustomer(
customer.customer_id,
);
// Use a saved method on a new payment
const payment = await delopay.payments.create({
amount: 1000,
currency: 'EUR',
customer_id: customer.customer_id,
payment_token: customer_payment_methods[0]?.payment_token,
confirm: true,
});
从目录上出售
// A product belongs to a shop; every call names the shop last.
const product = await delopay.products.create(
{
name: 'Annual report',
kind: 'one_time',
prices: [{ amount: 2999, currency: 'EUR', is_default: true }],
},
'pro_abc123',
);
// Price a payment from the catalog: no amount, no currency — the server
// freezes the product's active default price (or a named `price_id`) onto it.
const payment = await delopay.payments.create({
product_id: product.id,
profile_id: 'pro_abc123',
payment_link: true,
});
// What the payment sold, as it was when it was created — unchanged by later
// catalog edits or deletion.
const sold = await delopay.payments.productLines(payment.payment_id);
开具发票
// Invoices and credit notes in your name, from a paid payment or subscription
// cycle. Amounts always come from the source.
const invoice = await delopay.invoices.create(
{ source: { payment_id: 'pay_abc123' }, finalize: true },
{ headers: { 'Idempotency-Key': 'invoice-order-1001' } },
);
const pdf = await delopay.invoices.downloadPdf(invoice.id);
// How they look and are taxed: the merchant default, or one shop's override.
const current = await delopay.invoiceSettings.retrieveForShop('pro_abc123');
await delopay.invoiceSettings.updateForShop('pro_abc123', { ...current, locale: 'de' });
处理争议
// Disputes for one payment come from the payment object:
const payment = await delopay.payments.retrieve('pay_abc123');
for (const dispute of payment.disputes ?? []) {
console.log(dispute.dispute_id, dispute.dispute_stage, dispute.dispute_status);
}
// Or list disputes across the account, filtered by status:
const open = await delopay.disputes.list({ dispute_status: 'dispute_opened' });
检查付款失败的原因
// Every attempt on a payment — including retries across connectors — with its
// full failure detail (raw code + Delopay-unified, human-readable reason).
const { size, data } = await delopay.payments.listAttempts('pay_abc123');
for (const attempt of data) {
// e.g. "stripe failure — Insufficient funds (51)"
console.log(
`${attempt.connector ?? 'unknown'} ${attempt.status} — ` +
`${attempt.unified_message ?? attempt.error_message ?? 'no error'}` +
`${attempt.error_code ? ` (${attempt.error_code})` : ''}`,
);
}
管理商店和网关
// Create a shop (business profile)
const shop = await delopay.shops.create(merchantId, {
shop_name: 'My Online Store',
webhook_url: 'https://example.com/webhooks/delopay',
return_url: 'https://example.com/checkout/complete',
});
// Connect Stripe as a payment gateway
const gateway = await delopay.shops.gateways.connect(merchantId, shop.shop_id, {
connector_type: 'payment_processor',
connector_name: 'stripe',
connector_account_details: {
auth_type: 'HeaderKey',
api_key: process.env.STRIPE_SECRET_KEY,
},
test_mode: true,
});
// List connected gateways
const gateways = await delopay.shops.gateways.list(merchantId, shop.shop_id);
订阅
连通商店的帐单处理器( Stripe)
开出账单或付账。 每个订阅电话都是 配置范围 - 通过
店铺 X-Profile-Id 因此后端可以解决计费处理器(您得到
IR_04 否则:
const opts = { headers: { 'X-Profile-Id': profileId } };
浏览计划和估计费用 在创建任何内容之前 :
// List plans (or addons) with their prices. An item the processor lists but
// cannot sell right now comes back with `available: false` and no prices;
// skip it rather than offering it.
const plans = await delopay.subscriptions.getItems({ item_type: 'plan' }, opts);
const priceId = plans.find((item) => item.available)?.price_id[0]?.price_id;
if (!priceId) {
throw new Error('No purchasable plan on this shop');
}
// Preview what the customer will be charged
const estimate = await delopay.subscriptions.getEstimate({ item_price_id: priceId }, opts);
console.log(estimate.amount, estimate.currency, estimate.interval); // 1500 'EUR' 'Month'
从不发送生卡号码. 订阅 API 拒绝
payment_method_data.card用生的PAN来做 卡片由客户端收集 连接器的主机字段( Stripe Elements) , 所以卡片从不触及您 服务器,将原始卡数据保留在 PCI 范围之外。 以主机确认 退出会话或先前保存的代号,如下所示 .
建议:主机离职. 创建订阅服务器侧, 然后发送
delopay的买方与退货人一起办理了离职手续 client_secret编辑
买方在连接器iframe中输入他们的卡片;你从不处理 PAN:
const pending = await delopay.subscriptions.create(
{
item_price_id: priceId,
customer_id: 'cus_abc123',
payment_details: { return_url: 'https://example.com/subscription/complete' },
},
opts,
);
// Redirect the buyer to the hosted checkout to enter their card.
const checkoutUrl =
`https://checkout.delopay.net/pay/${merchantId}/${pending.id}` +
`?cs=${encodeURIComponent(pending.client_secret ?? '')}`;
// → res.redirect(checkoutUrl)
// Activation arrives via the subscription/invoice webhooks; never trust the
// client. Reconcile with subscriptions.retrieve(pending.id, opts).
节省的支付方法(课外). 如果客户已经存了钱, 象征性的支付方法, 用符号确认服务器侧- 仍然没有 PAN :
const sub = await delopay.subscriptions.createAndConfirm(
{
item_price_id: priceId,
customer_id: 'cus_abc123',
payment_details: {
payment_method: 'card',
payment_method_id: savedPaymentMethodId, // token, not a card number
setup_future_usage: 'off_session',
return_url: 'https://example.com/subscription/complete',
},
},
opts,
);
if (sub.redirect_url) {
// Some processors (e.g. PayPal) still need buyer approval — redirect there.
} else {
console.log(sub.status); // 'active'
}
您也可以分割创建和确认 – 呼叫 subscriptions.confirm(id, …) 与
页:1 client_secret (单位:千美元) payment_token 一旦买主有了信物 同样的规则:
(单位:千美元) payment_token 编号 : payment_method_id从来没有生牌.
管理寿命周期. 暂停、恢复和取消可选择的时间和 按比例控制;在没有机构的情况下,它们立即采取行动:
await delopay.subscriptions.pause(sub.id, { pause_option: 'end_of_term' }, opts);
await delopay.subscriptions.resume(sub.id, undefined, opts);
await delopay.subscriptions.cancel(
sub.id,
{ cancel_option: 'immediately', credit_option_for_current_term_charges: 'prorate' },
opts,
);
// Retrieve one, or list for the profile
const current = await delopay.subscriptions.retrieve(sub.id, opts);
const all = await delopay.subscriptions.list({ limit: 20 }, opts);
每个计费周期都开具发票(sub.invoice拥有自己的付款段
(单位:千美元)sub.payment);通过订阅/发票网络呼号跟踪周期结果.
关于目录产品的法案. 而不是处理器 item_price_id名称a
商店的经常性产品(以及可选择的价格之一)。 服务器
解决了账单账户的引用问题,拒绝了请求
当处理器的价格不再匹配时, 任何物品都会被收取。 检查
第一个价格可以开始订阅 :
const { prices } = await delopay.products.billingReadiness(['prd_pro'], profileId);
// state: 'ready' | 'unverified' | 'other_environment' | 'needs_reference'
await delopay.subscriptions.createAndConfirm(
{ product_id: 'prd_pro', customer_id: 'cus_abc123', payment_details: { payment_method_id: pm } },
opts,
);
await delopay.subscriptions.update(sub.id, { product_id: 'prd_pro', price_id: 'prc_yearly' }, opts);
镜像处理器. subscriptions.sync({ subscription_ids }) (1至50个)和
subscriptions.syncOne(id) 从处理器和镜像中读取订阅
它所报道的,没有记载.
取消已有的处理器订阅 . subscriptions.importPreview
列出记账账户的持有情况,并对每行进行分类; importApply 通过
最多25个 单词 capabilities.reason_code 每个行的 note_code
自己; 英语 reason 编号 : note 旁边是API的电话.
const preview = await delopay.subscriptions.importPreview({ merchant_connector_id: mca }, opts);
if (!preview.capabilities.listing || !preview.capabilities.adoption) {
// PayPal cannot be listed (`reason_code: 'listing_unsupported'`); an
// account may list without allowing adoption. Say why, and stop.
showUnavailable(preview.capabilities.reason_code);
} else {
// Rows whose buyer is already a DeloPay customer can be taken over as they
// are; `needs_customer` rows need a customer named first.
const picks = preview.items.flatMap((row) =>
row.classification === 'new' && row.customer_id
? [{ external_subscription_id: row.external_subscription_id, customer_id: row.customer_id }]
: [],
);
// The route takes 1 to 25 selections: send nothing when there is nothing
// to take over, and batch anything larger.
for (let i = 0; i < picks.length; i += 25) {
const { results } = await delopay.subscriptions.importApply(
{ merchant_connector_id: mca, items: picks.slice(i, i + 25) },
opts,
);
// One result per selection: `adopted`, `already_held`, or `failed` with a `reason_code`.
}
}
一个买家从处理器的结账中回来 可以读取订阅的
带有返回符号的状态( e)rt从浏览器运回的 URL :
const session = new CheckoutSession({ merchantId, paymentId: subscriptionId });
const { status, awaiting_processor } = await session.subscriptionReturnStatus(rt);
平台收费规则
按支付方法、连接器、金额、货币或卡对平台收费定价
腾讯网. 构建规则程序 feeProgram() 规则是按顺序进行的,
第一次比赛获胜,否则默认适用:
import { Delopay, feeProgram } from '@delopay/sdk';
const delopay = new Delopay(process.env.DELOPAY_API_KEY ?? '');
const algorithm = feeProgram()
.rule({ name: 'crypto', when: { paymentMethod: 'crypto' }, fee: { percentage: 1.0 } })
.rule({
name: 'card_on_cryptomus',
when: { paymentMethod: 'card', connector: 'cryptomus' },
fee: { percentage: 2.0 },
})
.otherwise({ percentage: 3.0 })
.build();
await delopay.fees.rules.upsert({ algorithm }, 'merchant_abc123');
const program = await delopay.fees.rules.retrieve('merchant_abc123'); // or null
await delopay.fees.rules.delete('merchant_abc123'); // revert to flat schedules
没有规则程序的商人保留现有的统一收费表/音量 等级不变.
Webhook 校验
Delopay在原始请求体上用 HMAC-SHA512 标记每个出局的网页,并在 X-Webhook-Signature-512 头曰. 使用 express.raw() (无) express.json()),所以字节到达验证符不变.
经核实的事件与线体相符: { merchant_id, event_id, event_type, content: { type, object }, timestamp }。 。 。 . event_type 说明发生了什么(例如:. 'payment_succeeded'(三); content.type 标记有效载荷类型(例如:. 'payment_details')——收缩取出打字 content.object (付款/退款/争议 payment_id 页:1.
import express from 'express';
import { Delopay } from '@delopay/sdk';
app.post('/webhooks/delopay', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.header('x-webhook-signature-512') ?? '';
const secret = process.env.DELOPAY_WEBHOOK_SECRET!;
let event;
try {
event = await Delopay.webhooks.verify(req.body, signature, secret);
} catch {
return res.status(400).send('Invalid signature');
}
if (event.content.type === 'payment_details') {
const payment = event.content.object; // typed: PaymentResponse
switch (event.event_type) {
case 'payment_succeeded':
// fulfil order — payment.payment_id, payment.amount, payment.currency
break;
case 'payment_failed':
// notify customer — payment.error_message
break;
}
}
res.json({ received: true });
});
处理错误
所有错误都是 DelopayError数字 :
import { Delopay, DelopayError, DelopayAuthenticationError } from '@delopay/sdk';
try {
const payment = await delopay.payments.retrieve('pay_does_not_exist');
} catch (err) {
if (err instanceof DelopayAuthenticationError) {
// status: 401 — invalid or missing API key
console.error('Check your API key');
} else if (err instanceof DelopayError) {
console.error(err.message); // human-readable message
console.error(err.status); // HTTP status code
console.error(err.code); // machine-readable error code
console.error(err.type); // error category (e.g. 'not_found')
console.error(err.data); // structured context for select codes (see below)
}
}
错误类别 :
| 类 | 何时 |
|---|---|
DelopayError | 所有 API 错误的基准类 |
DelopayAuthenticationError | 401 — 无效或缺失的 API 密钥 |
网络超时 DelopayError 与 code: 'TIMEOUT'。网络失败 code: 'NETWORK'。 。 。 .
导出( E)delopay.export.*, (中文(简体) ), disputes.workspaceExport) 保存到服务器宣布的数 X-Delopay-Record-Count: 带有不同数量记录——或者通过一行或JSON文件以分道扬镳的方式结束——到达的文件 code: 'EXPORT_INCOMPLETE' (单位:千美元)err.data 实值 { expected_records, received_records })而不是解析到缺少行的文件。 过 onProgress 在导出选项中跟踪下载,以及 signal 用于取消.
一条活溪道( A)delopay.live.stream(),仪表板 JWT) 相投 code: 'NOT_EVENT_STREAM' 当服务器以其它方式回答 2xx时 text/event-stream,并与 code: 'TIMEOUT' 当它保持沉默过去 idleTimeoutMs (违约45 s). 它从未被SDK重新连接:参见整合指南 仪表板实时更新。 。 。 .
结构错误上下文( E)err.data: 用于一小组从机器可读提示中受益的代码. 目前:
err.code | err.data 形状 | 含义 |
|---|---|---|
UR_48 | { retry_after_secs: number } | TOTP尝试计数器被锁出——等待这几秒钟再重试. |
UR_63 | { retry_after_secs: number } | Auth-endpoint 速率限制被绊倒了——在重试前等待这多秒. |
类型脚本
SDK是用严格的TypeScript书写的. 所有请求和响应形状全部打入. 需要时直接导入类型 :
import type { PaymentResponse, PaymentCreateRequest, Currency } from '@delopay/sdk';
环境
| 环境 | 基础 URL | API 密钥前缀 |
|---|---|---|
| 生产 | https://api.delopay.net | prd_… 编号 : pk_prd_… |
| 沙盒 | https://sandbox.delopay.net | snd_… 编号 : pk_snd_… |
// Sandbox
const delopay = new Delopay(process.env.DELOPAY_API_KEY!, { sandbox: true });
许可证
麻省理工学院