# त्वरित शुरुआत

भुगतान का एक न्यूनतम इंटीग्रेशन: API के ज़रिए इनवॉइस बनाना और भुगतान की सूचना को प्रोसेस करना। आख़िरी सेक्शन ऑर्डर पूरा करने के बारे में है। उदाहरण अपने-आप में पूरे हैं; कोई SDK इस्तेमाल नहीं होता।

:::tip
**AI एजेंट के साथ काम कर रहे हैं?** उसे इस पृष्ठ का [markdown वर्शन](/hi/quick-start.md) दें। इसमें आपकी साइट या स्टोर के लिए इंटीग्रेशन बनाने लायक पूरी जानकारी है।
:::

## ज़रूरी चीज़ें

| मान | कहाँ से मिलेगा |
| --- | --- |
| API कुंजी | [इंटीग्रेशन (Integrations)](https://dash.bitsby.app/integrations/list) सेक्शन |
| प्रोजेक्ट ID | [प्रोजेक्ट (Projects)](https://dash.bitsby.app/projects/list) सेक्शन |
| 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**

```bash showLineNumbers
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**

```php showLineNumbers
<?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
```

**TypeScript**

```typescript showLineNumbers
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
```

**JavaScript**

```js showLineNumbers
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
```

**Python**

```python showLineNumbers
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
```

जवाब:

```json
{
  "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**

```php showLineNumbers
<?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);
```

**TypeScript**

```typescript showLineNumbers
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);
```

**JavaScript**

```js showLineNumbers
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);
```

**Python**

```python showLineNumbers
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](./webhook-url/index.md) सेक्शन में है।

## ऑर्डर पूरा करना

`paid` स्थिति वाली, जाँची हुई सूचना भुगतान की पुष्टि करती है। ऑर्डर पूरा करने के चरण:

1. **ऑर्डर खोजें** `invoice.serviceData` से — वह मान, जो इनवॉइस बनाते समय भेजा गया था (`order-4172`)।
2. **`invoice.id` से जाँचें कि यह इनवॉइस पहले पूरा तो नहीं हो चुका।** एक ही `invoice.id` वाली सूचना एक से ज़्यादा बार आ सकती है — ऑर्डर एक ही बार पूरा करें और प्रोसेस हो जाने का फ़्लैग सेव करें।
3. **राशि और मुद्रा की जाँच करें** `invoice.amountFiat` और `invoice.currencyFiat` से — ये इनवॉइस के मूल मान हैं और कभी नहीं बदलते। `amountFiatUSD` में असल में मिली राशि लिख दी जाती है। राशियों की तुलना संख्या के रूप में करें, स्ट्रिंग के रूप में नहीं: आख़िर के शून्य हट जाते हैं, इसलिए `49.90` आता है `49.9` बनकर। अगर मान ऑर्डर से मेल नहीं खाते, तो इनवॉइस को पूरा करने के बजाय मैन्युअल जाँच में भेजें — ऐसे मामले [भुगतान को इनवॉइस से जोड़ना और राशि का अंतर](./payment-matching.md) में बताए गए हैं।
4. **ऑर्डर पूरा करें और प्रोसेस हो जाने का फ़्लैग सेट करें।**

ऑर्डर पूरा करते समय भुगतान की समय-सीमा न जाँचें: भुगतान `timeToPayDatetime` के बाद ऑन-चेन कन्फ़र्म हो सकता है, और व्यापारी भुगतान को इनवॉइस से मैन्युअल रूप से जोड़ सकता है। सूचना ख़ुद ही भुगतान की पुष्टि है।

## आगे क्या

- [API संदर्भ](./api/index.md) — इनवॉइस की सूचियाँ, रद्द करना, आँकड़े, बैलेंस
- [Webhook हस्ताक्षर की जाँच](./webhook-url/signature-verification.md) — हस्ताक्षर का पूरा ब्यौरा
- [भुगतान को इनवॉइस से जोड़ना और राशि का अंतर](./payment-matching.md) — कम भुगतान, अधिक भुगतान, बिना जुड़े भुगतान
- [HTML फ़ॉर्म](./creating-invoices/html-forms/index.md) — API के बिना भुगतान स्वीकार करना
