跳到主要内容

GLODIPAY iFrame 银行卡 API 规范

版本 2.0.0

目录

使用测试环境。不产生实际费用。

无 3DS4111 1111 1111 111101/30029
无 3DS5555 5555 5555 444401/30029
3DS 付款4012 8888 8888 188101/30029成功:123456 / 失败:111111
3DS 付款5111 1111 1111 111801/30029成功:123456 / 失败:111111
3DS 付款4141 4141 4141 414112/30123成功:123456 / 失败:111111

介绍

本文档描述了 GLODIPAY iFrame 银行卡 API v2,它允许商户使用 HTML <iframe> 将 GLODIPAY 托管的银行卡输入表单嵌入到自己的网页中。

流程概述:

  • 商户服务器发送 POST 请求到 /v2/card/iframe 以创建银行卡会话。
  • GLODIPAY 返回一个已签名的临时 URL,指向托管的银行卡输入表单。
  • 商户在自己的结账页面上将此 URL 嵌入到 <iframe> 中。
  • 买家在 iframe 内的 GLODIPAY 托管表单上输入银行卡详情。
  • GLODIPAY 处理付款,并通过 IPN 将结果发送到 notificationUrl,然后将买家重定向到 callbackUrlerrorUrl

商户页面可以保持其布局,而 GLODIPAY 则安全地处理银行卡数据。银行卡会话 URL 将在 expiresAt 指定的时间过期(默认:24 小时)。

接口地址 (Endpoints)

测试环境将另行提供
生产环境从商户后台的 API Keys 页面获取

签名 (Signature)

所有发送给 GLODIPAY 的请求必须包含 signature 字段。所有来自 GLODIPAY 的响应和 IPN Payload 也包含 signature 字段以验证真实性。

签名使用 RSA with MD5 (md5WithRSAEncryption)。

生成签名 (商户 -> GLODIPAY)

使用您的 商户私钥(可从商户后台获取)。

步骤:

  • 将除 signature 以外的所有请求参数收集为扁平的键值对象。
  • 仅按 自然升序顶层键 进行排序(PHP 中的 SORT_NATURAL / JavaScript 中带有 { numeric: true }localeCompare)。不要对嵌套对象(如 feespaymentMethodDetails)内部的键进行排序。
  • 递归修整所有字符串值的空格。
  • 序列化为 JSON 字符串。
  • 使用 openssl_sign(..., 'md5WithRSAEncryption') 进行签名。
  • 对二进制输出进行 Base64 编码。

验证签名 (GLODIPAY -> 商户)

使用 GLODIPAY 公钥(可在门户网站获取)。

步骤:

  • 从 Payload 中移除 signature
  • 仅按自然升序对 顶层键 进行排序。不要对嵌套对象内部的键进行排序。
  • 递归修整所有字符串值的空格。
  • 序列化为 JSON 字符串。
  • 使用 openssl_verify(..., base64_decode($signature), $publicKey, 'md5WithRSAEncryption') 进行验证。
  • 返回值 1 = 有效。

注意 (Node.js):在排序/序列化之前将所有数字值转换为字符串。转义 JSON 字符串中的正斜杠:.replace(///g, '\/')。

POST PAYMENT

创建银行卡 iframe 会话。GLODIPAY 返回一个已签名的 URL,指向托管的银行卡输入表单,商户将其嵌入到 <iframe> 中。

接口地址: POST /v2/card/iframe 请求方法: POST Content-Type: application/x-www-form-urlencoded

请求参数

merchantIdString(1,50)M商户 ID
orderRefString(1,250)M每个商户唯一的交易参考号
amountFloatM发票金额。最小值:1。最多 2 位小数
currencyString(3)MISO 4217 货币代码。例如:USD
cancelUrlString(1,300)M取消时重定向买家的 URL。必须为 https
callbackUrlString(1,300)M付款成功后重定向买家的 URL。必须为 https
notificationUrlString(1,300)M您的服务器接收 IPN Webhook 的接口。必须为 https
errorUrlString(1,300)M出错时重定向买家的 URL。必须为 https
orderDescriptionString(max:3000)M订单简短描述
metadataJSONO附加到会话的键值对。在 IPN 和查询响应中返回
transactionDocumentsJSONO交易的辅助文档
paymentMethodStringM对于 iframe 银行卡会话,必须为 card
feeBySellerNumber(0-100)O商户支付的手续费百分比。0 = 买家支付 100%。最多 2 位小数
billingEmailString(max:255)O买家电子邮件地址
billingCountryStringOISO 3166-1 alpha-2 国家代码
billingFirstNameString(max:255)O账单名字
billingLastNameString(max:255)O账单姓氏
billingStreet1String(max:255)O账单街道 1
billingStreet2String(max:255)O账单街道 2
billingCityString(max:255)O账单城市
billingStateString(2,255)O账单州/省
billingPostalCodeString(max:25)O邮政编码
billingPhoneCountryCodeString(max:10)O电话国家代码
billingPhoneNumberString(max:20)O电话号码
customerIpStringO客户的 IP 地址
websiteUrlString(max:300)O商户网站 URL
brandNameString(1,255)O覆盖在银行卡表单上显示的品牌名称
colorModeString(1,255)O最多 3 种颜色,用 --- 分隔。例如:#2e7d32---#e8f5e9---#81c784
logoSourceString(1,255)O覆盖在银行卡表单上显示的 Logo
signatureString(max:750)MRSA-MD5 签名。请参阅“签名”部分
expiresAtStringOISO 8601 格式的会话过期时间。例如:2025-09-14T14:03:42.102862Z。默认:24 小时

M = 必填,O = 可选

请求示例

{
"merchantId": "1100000123",
"orderRef": "ORDER-001",
"amount": "100.00",
"currency": "USD",
"paymentMethod": "card",
"callbackUrl": "https://yoursite.com/callback",
"notificationUrl": "https://yoursite.com/webhook",
"cancelUrl": "https://yoursite.com/cancel",
"errorUrl": "https://yoursite.com/error",
"orderDescription": "Test order",
"billingFirstName": "John",
"billingLastName": "Doe",
"billingStreet1": "123 Main St",
"billingStreet2": "",
"billingCity": "New York",
"billingEmail": "john@example.com",
"billingState": "NY",
"billingCountry": "US",
"billingPostalCode": "10001",
"billingPhoneCountryCode": "1",
"billingPhoneNumber": "5551234567",
"customerIp": "1.2.3.4",
"signature": "base64-encoded-signature"
}

响应

Content-Type: application/json

statusStringcreated
transactionIdString (ULID)GLODIPAY 交易 ID
urlString已签名的托管银行卡输入表单 URL —— 将此嵌入到 <iframe/>
messageString人类可读的消息

成功示例:

{
"status": "created",
"transactionId": "01jza90dy6w82dfrrqvadn5vs4",
"url": "https://payment.gpayprocessing.com/v2/card-iframe/01jza90dy6w82dfrrqvadn5vs4?...",
"message": "Iframe card created successfully"
}

错误示例:

{
"status": "error",
"transactionId": null,
"url": null,
"message": "No active payment service providers found. Please contact support."
}

嵌入 iFrame

收到 url 后,将其嵌入到您的页面中:

<iframe
src="{url}"
width="100%"
height="600"
frameborder="0"
scrolling="no"
allowtransparency="true">
</iframe>

该 URL 已签名并将在 expiresAt 到期。请勿在当前结账会话之外存储或共享它。买家必须在会话到期时间内完成付款。

交易查询 (TRANSACTION QUERY)

查询交易的当前状态和完整详情。

接口地址: POST /v2/checkout/query 请求方法: POST Content-Type: application/json

请求 (Request)

transactionIdString (ULID)MGLODIPAY 交易 ID
signatureString(max:750)MRSA-MD5 签名

响应 (Response)

Content-Type: application/json

merchantIdString商户 ID
transactionIdStringGLODIPAY 交易 ID (ULID)
transactionNumberStringGLODIPAY 人类可读的交易编号
refString商户的 orderRef
currencyStringISO 4217 货币代码
amountFloat发票金额
paidAmountFloat实际向买家收取的金额(包括买家费用)
settlementAmountFloat结算给商户的金额
estimationSettlementAtISO 8601 datetime预计结算日期时间
feesJSON费用明细。请参阅 fees 对象
statusString交易状态。请参阅“状态值”部分
statusCodeNumber数字状态码。请参阅“状态码”部分
metadataJSON原始会话中的键值对
transactionDocumentsJSON辅助文档
paymentMethodDetailsJSON所使用的付款方式。请参阅 paymentMethodDetails 对象
messageString人类可读的状态消息
descriptorString交易描述符
transactionCreatedAtISO 8601 datetimeGLODIPAY 系统中的交易创建时间
originalTransactionCreatedAtISO 8601 datetime支付渠道侧的交易创建时间
signatureStringRSA-MD5 签名 —— 使用 GLODIPAY 公钥验证

通知 (NOTIFICATION)

当交易达到终端状态时,GLODIPAY 会向您的 notificationUrl 发送 HTTP POST 请求。

请求方法: POST Content-Type: application/json

重试策略: GLODIPAY 可能会重新发送尚未确认交易的 IPN。您的服务器应在收到通知后立即返回 {"returnCode":"100"}

Payload

merchantIdStringM商户 ID
transactionIdStringMGLODIPAY 交易 ID (ULID)
transactionNumberStringMGLODIPAY 人类可读的交易编号
refStringM商户的 orderRef
currencyStringMISO 4217 货币代码
amountFloatM发票金额
paidAmountFloatO实际向买家收取的金额(包括买家费用)
settlementAmountFloatO结算给商户的金额
estimationSettlementAtISO 8601 datetimeO预计结算日期时间
feesJSONO费用明细。请参阅 fees 对象
paymentMethodDetailsJSONO所使用的付款方式。请参阅 paymentMethodDetails 对象
statusStringM交易状态。请参阅“状态值”部分
statusCodeNumberM数字状态码。请参阅“状态码”部分
metadataJSONO原始会话中的键值对
transactionDocumentsJSONO辅助文档
messageStringO人类可读的状态消息
descriptorStringO交易描述符
transactionCreatedAtISO 8601 datetimeMGLODIPAY 系统中的交易创建时间
originalTransactionCreatedAtISO 8601 datetimeM支付渠道侧的交易创建时间
signatureStringMRSA-MD5 签名 —— 使用 GLODIPAY 公钥验证

fees 对象

buyerFloat面向买家的费用金额
sellerFloat商户费用金额
rollingFloat滚动保证金金额
operateFloat总运营费用(渠道商 + GLODIPAY + 合作伙伴)
estimationRollingReleaseAtISO 8601 datetime预计滚动保证金释放日期时间

paymentMethodDetails 对象

displayNameString付款方式标签
groupString付款方式组类型
familyString付款方式系列类型
typeString付款方式类型
{type}JSON可选。付款方式特定的详细信息。键名等于 type 的值(如 card)。仅在银行卡详细信息可用时出现在银行卡付款中。请参阅下面的 card 对象

card 对象 (paymentMethodDetails.card)

name持卡人姓名
firstSixDigits卡号前 6 位 (BIN)
lastFourDigits卡号后 4 位
expiryMonth过期月份 (MM)
expiryYear过期年份 (YY)
type银行卡品牌 (visa, mastercard, amex 等)
issuer发卡行名称 (取决于渠道)
issuerCountryCode发卡行国家代码 (ISO 3166-1 alpha-2) (取决于渠道)
funding银行卡资金类型 (credit, debit, prepaid) (取决于渠道)
authorizationCode发卡行授权码 (取决于渠道)
clientIP付款时的客户 IP 地址 (取决于渠道)
checksAVS/CVC 验证结果 (取决于渠道)
threeDSecure3D Secure 认证详细信息 (取决于渠道)

IPN Payload 示例:

{
"merchantId": "1100000123",
"transactionId": "01jza90dy6w82dfrrqvadn5vs4",
"transactionNumber": "2604-1713100800",
"ref": "ORDER-001",
"currency": "USD",
"amount": 100.00,
"paidAmount": 105.00,
"settlementAmount": 95.00,
"estimationSettlementAt": "2026-04-16T00:00:00+00:00",
"fees": {
"buyer": 5.00,
"seller": 5.00,
"rolling": 2.00,
"operate": 3.00,
"estimationRollingReleaseAt": "2026-05-14T00:00:00+00:00"
},
"status": "successful",
"statusCode": 6,
"paymentMethodDetails": {
"displayName": "Credit / Debit Card",
"group": "card",
"family": "card",
"type": "card"
},
"metadata": { "orderId": "12345" },
"transactionCreatedAt": "2026-04-14T10:00:00+00:00",
"originalTransactionCreatedAt": "2026-04-14T10:00:01+00:00",
"signature": "base64-encoded-rsa-signature"
}

响应 (商户 -> GLODIPAY)

您的服务器必须在 30 秒 内响应:

{
"returnCode": "100",
"description": "Received"
}
returnCodeStringR必须为 "100" 以确认收到
descriptionString(1,1500)O可选描述

模拟付款

使用测试环境。不产生实际费用。

无 3DS4111 1111 1111 111101/30029
无 3DS5555 5555 5555 444401/30029
3DS 付款4012 8888 8888 188101/30029成功:123456 / 失败:111111
3DS 付款5111 1111 1111 111801/30029成功:123456 / 失败:111111
3DS 付款4141 4141 4141 414112/30123成功:123456 / 失败:111111

附录

状态值

在 IPN Payload 和查询响应的 status 字段中返回的字符串值。

incomplete交易已发起,等待操作
pending等待付款确认
under_review交易审核中
successful付款成功完成
failed付款失败
error发生系统错误
canceled交易已取消
rejected交易被拒绝
expired交易已过期
released资金已释放 / 结算
documents_uploaded辅助文档已上传
refund_initiated退款请求已发起
refund_under_review退款审核中
refund_successful退款成功完成
refund_failed退款失败
refund_partially_successful部分退款完成
refund_partially_failed部分退款失败
void_initiated撤销已发起
void_under_review撤销审核中
void_successful撤销成功完成
void_failed撤销失败
void_partially_successful部分撤销完成
void_partially_failed部分撤销失败
chargeback_alert收到拒付警报
chargebacked交易已拒付
dispute争议已开启

状态码

在 IPN Payload 和查询响应的 statusCode 字段中的数字代码。

1incomplete交易已发起
2pending等待确认
3error系统错误
4failed付款失败
5under_review审核中
6successful付款成功
7released已释放 / 结算
8refund_initiated退款已发起
9refund_failed退款失败
10refund_under_review退款审核中
11refund_successful退款成功
12refund_partially_failed部分退款失败
13refund_partially_successful部分退款成功
14canceled已取消
15rejected已拒绝
16expired已过期
17documents_uploaded文档已上传
18void_initiated撤销已发起
19void_under_review撤销审核中
20void_successful撤销成功
21void_failed撤销失败
22void_partially_successful部分撤销成功
23void_partially_failed部分撤销失败
24chargeback_alert拒付警报
25chargebacked已拒付
26dispute争议已开启

货币代码

GLODIPAY 遵循 ISO 4217 标准。此接口目前仅接受 USD

USD美元

国家代码

GLODIPAY 在 billingCountry 字段中使用 ISO 3166-1 alpha-2 两位字母代码。

AD安道尔
AE阿拉伯联合酋长国
AF阿富汗
AG安提瓜和巴布达
AI安圭拉
AL阿尔巴尼亚
AM亚美尼亚
AO安哥拉
AQ南极洲
AR阿根廷
AS美属萨摩亚
AT奥地利
AU澳大利亚
AW阿鲁巴
AX奥兰群岛
AZ阿塞拜疆
BA波斯尼亚和黑塞哥维那
BB巴巴多斯
BD孟加拉国
BE比利时
BF布基纳法索
BG保加利亚
BH巴林
BI布隆迪
BJ贝宁
BL圣巴泰勒米
BM百慕大
BN文莱达鲁萨兰国
BO多民族玻利维亚国
BQ博内尔、圣尤斯特歇斯和萨巴
BR巴西
BS巴哈马
BT不丹
BV布韦岛
BW博茨瓦纳
BY白俄罗斯
BZ伯利兹
CA加拿大
CC科科斯(基林)群岛
CD刚果民主共和国
CF中非共和国
CG刚果
CH瑞士
CI科特迪瓦
CK库克群岛
CL智利
CM喀麦隆
CN中国
CO哥伦比亚
CR哥斯达黎加
CU古巴
CV佛得角
CW库拉索
CX圣诞岛
CY塞浦路斯
CZ捷克
DE德国
DJ吉布提
DK丹麦
DM多米尼克
DO多米尼加共和国
DZ阿尔及利亚
EC厄瓜多尔
EE爱沙尼亚
EG埃及
EH西撒哈拉
ER厄立特里亚
ES西班牙
ET埃塞俄比亚
FI芬兰
FJ斐济
FK福克兰群岛
FM密克罗尼西亚
FO法罗群岛
FR法国
GA加蓬
GB英国
GD格林纳达
GE格鲁吉亚
GF法属圭亚那
GG根西岛
GH加纳
GI直布罗陀
GL格陵兰
GM冈比亚
GN几内亚
GP瓜德罗普
GQ赤道几内亚
GR希腊
GS南乔治亚岛和南桑威奇群岛
GT危地马拉
GU关岛
GW几内亚比绍
GY圭亚那
HK香港
HM赫德岛和麦克唐纳群岛
HN洪都拉斯
HR克罗地亚
HT海地
HU匈牙利
ID印度尼西亚
IE爱尔兰
IL以色列
IM马恩岛
IN印度
IO英属印度洋领地
IQ伊拉克
IR伊朗
IS冰岛
IT意大利
JE泽西岛
JM牙买加
JO约旦
JP日本
KE肯尼亚
KG吉尔吉斯斯坦
KH柬埔寨
KI基里巴斯
KM科摩罗
KN圣基茨和尼维斯
KP朝鲜
KR韩国
KW科威特
KY开曼群岛
KZ哈萨克斯坦
LA老挝
LB黎巴嫩
LC圣卢西亚
LI列支敦士登
LK斯里兰卡
LR利比里亚
LS莱索托
LT立陶宛
LU卢森堡
LV拉脱维亚
LY利比亚
MA摩洛哥
MC摩纳哥
MD摩尔多瓦
ME黑山
MF圣马丁 (法属)
MG马达加斯加
MH马绍尔群岛
MK北马其顿
ML马里
MM缅甸
MN蒙古
MO澳门
MP北马里亚纳群岛
MQ马提尼克
MR毛里塔尼亚
MS蒙特塞拉特
MT马耳他
MU毛里求斯
MV马尔代夫
MW马拉维
MX墨西哥
MY马来西亚
MZ莫桑比克
NA纳米比亚
NC新喀里多尼亚
NE尼日尔
NF诺福克岛
NG尼日利亚
NI尼加拉瓜
NL荷兰
NO挪威
NP尼泊尔
NR瑙鲁
NU纽埃
NZ新西兰
OM阿曼
PA巴拿马
PE秘鲁
PF法属波利尼西亚
PG巴布亚新几内亚
PH菲律宾
PK巴基斯坦
PL波兰
PM圣皮埃尔和密克隆
PN皮特凯恩
PR波多黎各
PS巴勒斯坦
PT葡萄牙
PW帕劳
PY巴拉圭
QA卡塔尔
RE留尼汪
RO罗马尼亚
RS塞尔维亚
RU俄罗斯
RW卢旺达
SA沙特阿拉伯
SB所罗门群岛
SC塞舌尔
SD苏丹
SE瑞典
SG新加坡
SH圣赫勒拿
SI斯洛文尼亚
SJ斯瓦尔巴和扬马延
SK斯洛伐克
SL塞拉利昂
SM圣马力诺
SN塞内加尔
SO索马里
SR苏里南
SS南苏丹
ST圣多美和普林西比
SV萨尔瓦多
SX圣马丁 (荷属)
SY叙利亚
SZ斯威士兰
TC特克斯和凯科斯群岛
TD乍得
TF法属南部领土
TG多哥
TH泰国
TJ塔吉克斯坦
TK托克劳
TL东帝汶
TM土库曼斯坦
TN突尼斯
TO汤加
TR土耳其
TT特立尼达和多巴哥
TV图瓦卢
TW台湾
TZ坦桑尼亚
UA乌克兰
UG乌干达
UM美国本土外小岛屿
US美国
UY乌拉圭
UZ乌兹别克斯坦
VA圣座
VC圣文森特和格林纳丁斯
VE委内瑞拉
VG英属维尔京群岛
VI美属维尔京群岛
VN越南
VU瓦努阿图
WF瓦利斯和富图纳
WS萨摩亚
YE也门
YT马约特
ZA南非
ZM赞比亚
ZW津巴布韦

卡类型

1VISAvisa
2MASTERCARDmastercard
3AMERICAN EXPRESSamex
4JCBjcb
5MAESTROmaestro
6DISCOVERdiscover
7UNION PAYunion-pay
8DINERSdiners

代码示例

PHP

<?php

function generateSignature(array $data): string
{
$privateKey = openssl_pkey_get_private("-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----
");

ksort($data, SORT_NATURAL);
array_walk_recursive(
$data,
static function (&$field) {
$field = trim($field);
}
);

openssl_sign(json_encode($data), $signature, $privateKey, 'md5WithRSAEncryption');

return base64_encode($signature);
}

// 示例:创建一个 v2 card iframe 会话
$payload = [
'merchantId' => '1100000123',
'orderRef' => 'ORDER-' . time(),
'amount' => '100.00',
'currency' => 'USD',
'paymentMethod' => 'card',
'callbackUrl' => 'https://yoursite.com/payment/callback',
'notificationUrl' => 'https://yoursite.com/payment/webhook',
'cancelUrl' => 'https://yoursite.com/payment/cancel',
'errorUrl' => 'https://yoursite.com/payment/error',
'orderDescription' => 'Test order',
'billingEmail' => 'customer@example.com',
];

$payload['signature'] = generateSignature($payload);

$ch = curl_init('https://payment-sandbox.gpayprocessing.com/v2/card/iframe');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);

// 在您的结账页面上将 $result['url'] 嵌入到 iframe 中
echo '<iframe src="' . htmlspecialchars($result['url']) . '" width="100%" height="600" frameborder="0"></iframe>';

Node.js

// Save as script.mjs and run: node script.mjs
import { createSign } from 'crypto';
import https from 'https';

const PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----`;

function phpCast(v) {
if (typeof v === 'number') return String(v);
if (typeof v === 'boolean') return v ? '1' : '';
if (typeof v === 'string') return v.trim();
if (Array.isArray(v)) return v.map(phpCast);
if (v && typeof v === 'object') return Object.fromEntries(Object.entries(v).map(([k, val]) => [k, phpCast(val)]));
return v;
}

function generateSignature(data) {
const sorted = {};
Object.keys(data)
.filter(k => k !== 'signature')
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }))
.forEach(k => { sorted[k] = data[k]; });

const canonical = JSON.stringify(phpCast(sorted))
.replace(/\//g, '\\/')
.replace(/[\u0080-\uffff]/g, c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'));

const sign = createSign('md5WithRSAEncryption');
sign.update(canonical);
return sign.sign(PRIVATE_KEY, 'base64');
}

// 示例:创建一个 card iframe 会话
const payload = {
merchantId: '1100000123',
orderRef: 'ORDER-001',
amount: '100.00',
currency: 'USD',
paymentMethod: 'card',
callbackUrl: 'https://yoursite.com/payment/callback',
notificationUrl: 'https://yoursite.com/payment/webhook',
cancelUrl: 'https://yoursite.com/payment/cancel',
errorUrl: 'https://yoursite.com/payment/error',
orderDescription: 'Test order',
billingEmail: 'customer@example.com',
};

payload.signature = generateSignature(payload);

const postData = new URLSearchParams(payload).toString();
const options = {
hostname: 'payment-sandbox.gpayprocessing.com',
path: '/v2/card/iframe',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData),
},
};

const req = https.request(options, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
const result = JSON.parse(body);
console.log('Iframe URL:', result.url);
});
});

req.on('error', console.error);
req.write(postData);
req.end();

Bookmarks

No bookmarks yet.
Hover over a heading and click to save a section.