त्वरित शुरुआत
भुगतान का एक न्यूनतम इंटीग्रेशन: API के ज़रिए इनवॉइस बनाना और भुगतान की सूचना को प्रोसेस करना। आख़िरी सेक्शन ऑर्डर पूरा करने के बारे में है। उदाहरण अपने-आप में पूरे हैं; कोई SDK इस्तेमाल नहीं होता।
AI एजेंट के साथ काम कर रहे हैं? उसे इस पृष्ठ का markdown वर्शन दें। इसमें आपकी साइट या स्टोर के लिए इंटीग्रेशन बनाने लायक पूरी जानकारी है।
ज़रूरी चीज़ें
| मान | कहाँ से मिलेगा |
|---|---|
| API कुंजी | इंटीग्रेशन (Integrations) सेक्शन |
| प्रोजेक्ट ID | प्रोजेक्ट (Projects) सेक्शन |
| Webhook की गुप्त कुंजी (Webhook secret) | प्रोजेक्ट सेटिंग्स |
उन्हीं प्रोजेक्ट सेटिंग्स में Webhook URL सेट करें — आपके सर्वर पर सूचना हैंडलर का पता। सिर्फ़ HTTPS; रीडायरेक्ट फ़ॉलो नहीं होते।
उदाहरणों में टेस्ट मान इस्तेमाल हुए हैं — इन्हें अपने मानों से बदल लें।
इनवॉइस बनाना
POST https://api.bitsby.app/invoices/create, API कुंजी Authorization हेडर में भेजी जाती है।
| पैरामीटर | अनिवार्य | मान |
|---|---|---|
projectId | हाँ | प्रोजेक्ट ID, UUID |
amountFiat | हाँ | इनवॉइस की राशि |
currencyFiat | हाँ | मुद्रा: USD, EUR, RUB |
timeToPay | हाँ | भुगतान की समय-सीमा, घंटों में: 0.5, 1, 3, 6, 12 |
description | नहीं | विवरण, ग्राहक को भुगतान पृष्ठ पर दिखता है |
serviceData | नहीं | सर्विस डेटा, ग्राहक को नहीं दिखता। हम ऑर्डर नंबर भेजने की सलाह देते हैं: यह भुगतान की सूचना में वापस आता है |
- cURL
- PHP
- TypeScript
- JavaScript
- Python
curl -X POST https://api.bitsby.app/invoices/create \
-H "Authorization: Token MSvL2ltaDZdWVjmZURURMVWhqSJLT2NURjhL2Fla1Z1T1IxQTltKs1T3Ay" \
-F "projectId=9deea1e2-0c08-41a3-bdc2-a34eada3892d" \
-F "amountFiat=49.90" \
-F "currencyFiat=USD" \
-F "timeToPay=1" \
-F "description=Order 4172" \
-F "serviceData=order-4172"
<?php
$apiKey = 'MSvL2ltaDZdWVjmZURURMVWhqSJLT2NURjhL2Fla1Z1T1IxQTltKs1T3Ay';
$projectId = '9deea1e2-0c08-41a3-bdc2-a34eada3892d';
$ch = curl_init('https://api.bitsby.app/invoices/create');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Authorization: Token '.$apiKey],
CURLOPT_POSTFIELDS => http_build_query([
'projectId' => $projectId,
'amountFiat' => 49.90,
'currencyFiat' => 'USD',
'timeToPay' => 1,
'description' => 'Order 4172',
'serviceData' => 'order-4172', // your order id
]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($response['result'] !== 'success') {
exit('API error: '.$response['data']);
}
$invoice = $response['data'];
// $invoice['id'] — invoice id, store it with the order
// $invoice['url'] — payment page for the customer
const API_KEY = 'MSvL2ltaDZdWVjmZURURMVWhqSJLT2NURjhL2Fla1Z1T1IxQTltKs1T3Ay';
const PROJECT_ID = '9deea1e2-0c08-41a3-bdc2-a34eada3892d';
interface Invoice {
id: string;
uid: string;
url: string;
timeToPayDatetime: string;
}
const response = await fetch('https://api.bitsby.app/invoices/create', {
method: 'POST',
headers: { Authorization: `Token ${API_KEY}` },
body: new URLSearchParams({
projectId: PROJECT_ID,
amountFiat: '49.90',
currencyFiat: 'USD',
timeToPay: '1',
description: 'Order 4172',
serviceData: 'order-4172', // your order id
}),
signal: AbortSignal.timeout(10_000),
});
const result: { result: string; data: Invoice | string } = await response.json();
if (result.result !== 'success') {
throw new Error(`API error: ${result.data}`);
}
const invoice = result.data as Invoice;
// invoice.id — invoice id, store it with the order
// invoice.url — payment page for the customer
const API_KEY = 'MSvL2ltaDZdWVjmZURURMVWhqSJLT2NURjhL2Fla1Z1T1IxQTltKs1T3Ay';
const PROJECT_ID = '9deea1e2-0c08-41a3-bdc2-a34eada3892d';
const response = await fetch('https://api.bitsby.app/invoices/create', {
method: 'POST',
headers: { Authorization: `Token ${API_KEY}` },
body: new URLSearchParams({
projectId: PROJECT_ID,
amountFiat: '49.90',
currencyFiat: 'USD',
timeToPay: '1',
description: 'Order 4172',
serviceData: 'order-4172', // your order id
}),
signal: AbortSignal.timeout(10_000),
});
const result = await response.json();
if (result.result !== 'success') {
throw new Error(`API error: ${result.data}`);
}
const invoice = result.data;
// invoice.id — invoice id, store it with the order
// invoice.url — payment page for the customer
import requests
API_KEY = 'MSvL2ltaDZdWVjmZURURMVWhqSJLT2NURjhL2Fla1Z1T1IxQTltKs1T3Ay'
PROJECT_ID = '9deea1e2-0c08-41a3-bdc2-a34eada3892d'
response = requests.post(
'https://api.bitsby.app/invoices/create',
headers={'Authorization': f'Token {API_KEY}'},
data={
'projectId': PROJECT_ID,
'amountFiat': '49.90',
'currencyFiat': 'USD',
'timeToPay': '1',
'description': 'Order 4172',
'serviceData': 'order-4172', # your order id
},
timeout=10,
)
result = response.json()
if result['result'] != 'success':
raise RuntimeError(f"API error: {result['data']}")
invoice = result['data']
# invoice['id'] — invoice id, store it with the order
# invoice['url'] — payment page for the customer
जवाब:
{
"result": "success",
"data": {
"id": "ade9550d-3dc7-4fd3-b94e-3b4c12aaaa0c",
"uid": "MXNj4m8HhcM4",
"createDatetime": "2026-09-14 10:12:03",
"timeToPayDatetime": "2026-09-14 11:12:03",
"commissionFiatUSD": 0.5,
"amountFiatUSD": 49.9,
"url": "https://dash.bitsby.app/invoices/pay/MXNj4m8HhcM4"
}
}
data.id को ऑर्डर के साथ सेव करें और ग्राहक को data.url पर भेजें — यह भुगतान पृष्ठ है। लिंक किसी भी तरीके से पहुँचाएँ: रीडायरेक्ट, ईमेल, बॉट का संदेश। इनवॉइस timeToPayDatetime (UTC) तक मान्य है।
सूचना को प्रोसेस करना
जब इनवॉइस भुगतान हुआ (Paid) स्थिति में जाता है, तो सेवा प्रोजेक्ट के Webhook URL पर POST अनुरोध भेजती है। बॉडी में JSON होता है; हस्ताक्षर हेडर में होते हैं:
| हेडर | मान |
|---|---|
X-Timestamp | भेजने का समय, सेकंड में unix time |
X-Signature | sha256= + स्ट्रिंग <timestamp>.<request body> का hex HMAC-SHA256 |
साइनिंग कुंजी Webhook की गुप्त कुंजी है। हस्ताक्षर raw अनुरोध बॉडी पर कंप्यूट होता है, इसलिए JSON पार्स करने से पहले हस्ताक्षर की जाँच करें।
- PHP
- TypeScript
- JavaScript
- Python
<?php
$secret = 'k7QwR2mZ9tXbN4vL8sJpH3dF6yA1cE0u';
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
// Reject replayed requests: allow up to 5 minutes of clock drift
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
exit;
}
$expected = 'sha256='.hash_hmac('sha256', $timestamp.'.'.$body, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit;
}
$invoice = json_decode($body, true)['invoice'];
if ($invoice['status'] === 'paid') {
// $invoice['serviceData'] — the order id passed at creation: 'order-4172'
// $invoice['amountFiat'] — the original invoice amount: 49.9
// Issue the order here, see the next section
}
http_response_code(200);
import { createHmac, timingSafeEqual } from 'node:crypto';
import express, { type Request, type Response } from 'express';
const SECRET = 'k7QwR2mZ9tXbN4vL8sJpH3dF6yA1cE0u';
const app = express();
// express.raw: the signature is computed over the raw request body
app.post('/webhook', express.raw({ type: 'application/json' }), (req: Request, res: Response) => {
const timestamp = req.get('X-Timestamp') ?? '';
const signature = req.get('X-Signature') ?? '';
const body = (req.body as Buffer).toString('utf8');
// Reject replayed requests: allow up to 5 minutes of clock drift
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.sendStatus(400);
}
const expected = 'sha256=' + createHmac('sha256', SECRET)
.update(`${timestamp}.${body}`, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return res.sendStatus(403);
}
const { invoice } = JSON.parse(body);
if (invoice.status === 'paid') {
// invoice.serviceData — the order id passed at creation: 'order-4172'
// invoice.amountFiat — the original invoice amount: 49.9
// Issue the order here, see the next section
}
res.sendStatus(200);
});
app.listen(8080);
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';
const SECRET = 'k7QwR2mZ9tXbN4vL8sJpH3dF6yA1cE0u';
const app = express();
// express.raw: the signature is computed over the raw request body
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-Timestamp') ?? '';
const signature = req.get('X-Signature') ?? '';
const body = req.body.toString('utf8');
// Reject replayed requests: allow up to 5 minutes of clock drift
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.sendStatus(400);
}
const expected = 'sha256=' + createHmac('sha256', SECRET)
.update(`${timestamp}.${body}`, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return res.sendStatus(403);
}
const { invoice } = JSON.parse(body);
if (invoice.status === 'paid') {
// invoice.serviceData — the order id passed at creation: 'order-4172'
// invoice.amountFiat — the original invoice amount: 49.9
// Issue the order here, see the next section
}
res.sendStatus(200);
});
app.listen(8080);
import hashlib
import hmac
import time
from flask import Flask, request
SECRET = 'k7QwR2mZ9tXbN4vL8sJpH3dF6yA1cE0u'
app = Flask(__name__)
@app.post('/webhook')
def webhook():
timestamp = request.headers.get('X-Timestamp', '')
signature = request.headers.get('X-Signature', '')
# The signature is computed over the raw request body
body = request.get_data(as_text=True)
# Reject replayed requests: allow up to 5 minutes of clock drift
if abs(time.time() - int(timestamp or 0)) > 300:
return '', 400
expected = 'sha256=' + hmac.new(
SECRET.encode(),
f'{timestamp}.{body}'.encode(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, signature):
return '', 403
invoice = request.get_json()['invoice']
if invoice['status'] == 'paid':
# invoice['serviceData'] — the order id passed at creation: 'order-4172'
# invoice['amountFiat'] — the original invoice amount: 49.9
# Issue the order here, see the next section
pass
return '', 200
10 सेकंड के भीतर 2xx कोड के साथ जवाब दें। कोई भी दूसरा कोड, रीडायरेक्ट या टाइमआउट असफल डिलीवरी माना जाता है: सेवा 5 मिनट से 24 घंटे तक बढ़ते अंतराल पर पुनः प्रयास करती है, फिर रुक जाती है। लंबी प्रोसेसिंग क्यू में डालें: पहले 200 का जवाब दें, फिर ऑर्डर पर काम करें।
सूचना का पूरा फ़ॉर्मैट और फ़ील्ड का विवरण Webhook URL सेक्शन में है।
ऑर्डर पूरा करना
paid स्थिति वाली, जाँची हुई सूचना भुगतान की पुष्टि करती है। ऑर्डर पूरा करने के चरण:
- ऑर्डर खोजें
invoice.serviceDataसे — वह मान, जो इनवॉइस बनाते समय भेजा गया था (order-4172)। invoice.idसे जाँचें कि यह इनवॉइस पहले पूरा तो नहीं हो चुका। एक हीinvoice.idवाली सूचना एक से ज़्यादा बार आ सकती है — ऑर्डर एक ही बार पूरा करें और प्रोसेस हो जाने का फ़्लैग सेव करें।- राशि और मुद्रा की जाँच करें
invoice.amountFiatऔरinvoice.currencyFiatसे — ये इनवॉइस के मूल मान हैं और कभी नहीं बदलते।amountFiatUSDमें असल में मिली राशि लिख दी जाती है। राशियों की तुलना संख्या के रूप में करें, स्ट्रिंग के रूप में नहीं: आख़िर के शून्य हट जाते हैं, इसलिए49.90आता है49.9बनकर। अगर मान ऑर्डर से मेल नहीं खाते, तो इनवॉइस को पूरा करने के बजाय मैन्युअल जाँच में भेजें — ऐसे मामले भुगतान को इनवॉइस से जोड़ना और राशि का अंतर में बताए गए हैं। - ऑर्डर पूरा करें और प्रोसेस हो जाने का फ़्लैग सेट करें।
ऑर्डर पूरा करते समय भुगतान की समय-सीमा न जाँचें: भुगतान timeToPayDatetime के बाद ऑन-चेन कन्फ़र्म हो सकता है, और व्यापारी भुगतान को इनवॉइस से मैन्युअल रूप से जोड़ सकता है। सूचना ख़ुद ही भुगतान की पुष्टि है।
आगे क्या
- API संदर्भ — इनवॉइस की सूचियाँ, रद्द करना, आँकड़े, बैलेंस
- Webhook हस्ताक्षर की जाँच — हस्ताक्षर का पूरा ब्यौरा
- भुगतान को इनवॉइस से जोड़ना और राशि का अंतर — कम भुगतान, अधिक भुगतान, बिना जुड़े भुगतान
- HTML फ़ॉर्म — API के बिना भुगतान स्वीकार करना