Receipt Management Guide
Learn how to create and manage receipts using Payme Subscribe API.
Overview
Receipts allow you to:
- Create payment invoices
- Pay with saved card tokens
- Send invoices via SMS
- Track payment status
- Cancel unpaid receipts
Receipt Flow
1. receiptsCreate (create invoice)
↓
2. receiptsPay (pay with card token)
↓
3. receiptsCheck (verify payment)
↓
4. receiptsGet (get details)Creating Receipts
Basic Receipt
typescript
import { PaymeSubscribe } from '@joyida/payme';
const subscribeServer = new PaymeSubscribe({
merchantId: process.env.PAYME_MERCHANT_ID!,
password: process.env.PAYME_PASSWORD!
}, 'server');
const receipt = await subscribeServer.receiptsCreate({
amount: 500000, // 5000 UZS in tiyin
account: { order_id: '123' },
description: 'Payment for order #123'
});
console.log('Receipt ID:', receipt.receipt._id);
console.log('State:', receipt.receipt.state); // 0 (waiting for payment)Receipt with Fiscal Details
typescript
const receipt = await subscribeServer.receiptsCreate({
amount: 500000,
account: { order_id: '123' },
description: 'Payment for order #123',
detail: {
receipt_type: 0,
items: [
{
title: 'Product Name',
price: 500000,
count: 1,
code: '00702001001000001', // IKPU code
vat_percent: 15,
package_code: '123456'
}
]
}
});Receipt with Multiple Items
typescript
const receipt = await subscribeServer.receiptsCreate({
amount: 1000000, // 10000 UZS
account: { order_id: '123' },
description: 'Order #123',
detail: {
receipt_type: 0,
shipping: {
title: 'Delivery',
price: 50000 // 500 UZS
},
items: [
{
title: 'Product 1',
price: 300000,
count: 2,
code: '00702001001000001',
vat_percent: 15,
package_code: '123456'
},
{
title: 'Product 2',
price: 400000,
count: 1,
code: '00702001001000002',
vat_percent: 15,
package_code: '123457'
}
]
}
});Paying Receipts
Pay with Card Token
typescript
const payment = await subscribeServer.receiptsPay({
id: receipt.receipt._id,
token: 'card_token_here'
});
if (payment.receipt.state === 1) {
console.log('✅ Payment successful!');
}Pay with Payer Info
typescript
const payment = await subscribeServer.receiptsPay({
id: receipt.receipt._id,
token: 'card_token_here',
payer: {
phone: '998901234567'
}
});Sending Receipts
Send receipt invoice via SMS:
typescript
const result = await subscribeServer.receiptsSend({
id: receipt.receipt._id,
phone: '998901234567'
});
if (result.success) {
console.log('✅ SMS sent to customer');
}Checking Receipt Status
Quick Status Check
typescript
const status = await subscribeServer.receiptsCheck({
id: receipt.receipt._id
});
console.log('Receipt state:', status.state);
// 0 = waiting for payment
// 1 = paid
// 2 = cancelled
// 3 = cancelled after paymentGet Full Receipt Details
typescript
const details = await subscribeServer.receiptsGet({
id: receipt.receipt._id
});
console.log('Amount:', details.receipt.amount);
console.log('State:', details.receipt.state);
console.log('Description:', details.receipt.description);
console.log('Card:', details.receipt.card?.number);
console.log('Create time:', new Date(details.receipt.create_time));
console.log('Pay time:', new Date(details.receipt.pay_time));Cancelling Receipts
Cancel Unpaid Receipt
typescript
const cancelled = await subscribeServer.receiptsCancel({
id: receipt.receipt._id
});
console.log('Cancelled at:', new Date(cancelled.receipt.cancel_time));
console.log('State:', cancelled.receipt.state); // 2 (cancelled)Cancel Paid Receipt (Refund)
typescript
// If receipt is already paid, cancellation will initiate refund
const refunded = await subscribeServer.receiptsCancel({
id: receipt.receipt._id
});
console.log('State:', refunded.receipt.state); // 3 (cancelled after payment)Getting All Receipts
Get Receipts for Period
typescript
const result = await subscribeServer.receiptsGetAll({
from: Date.now() - 86400000, // 24 hours ago
to: Date.now(),
limit: 50
});
console.log('Found receipts:', result.receipts.length);
result.receipts.forEach(receipt => {
console.log(`${receipt._id}: ${receipt.state} - ${receipt.amount} tiyin`);
});Get Receipts with Pagination
typescript
const limit = 50;
let offset = 0;
let allReceipts = [];
while (true) {
const result = await subscribeServer.receiptsGetAll({
from: Date.now() - 86400000,
to: Date.now(),
offset,
limit
});
allReceipts.push(...result.receipts);
if (result.receipts.length < limit) {
break; // No more receipts
}
offset += limit;
}
console.log('Total receipts:', allReceipts.length);Receipt States
typescript
import { RECEIPT_STATES } from '@joyida/payme';
// State constants
RECEIPT_STATES.WAITING // 0 - Waiting for payment
RECEIPT_STATES.PAID // 1 - Paid
RECEIPT_STATES.CANCELLED // 2 - Cancelled
RECEIPT_STATES.CANCELLED_AFTER_PAY // 3 - Cancelled after payment
// Usage
if (receipt.state === RECEIPT_STATES.PAID) {
console.log('Receipt paid');
} else if (receipt.state === RECEIPT_STATES.WAITING) {
console.log('Waiting for payment');
}Complete Receipt Example
typescript
import { PaymeSubscribe, RECEIPT_STATES, PaymeError } from '@joyida/payme';
const subscribeServer = new PaymeSubscribe({
merchantId: process.env.PAYME_MERCHANT_ID!,
password: process.env.PAYME_PASSWORD!
}, 'server');
async function processReceiptPayment(
orderId: string,
amount: number,
cardToken: string,
customerPhone: string
) {
try {
// 1. Create receipt
console.log('📝 Creating receipt...');
const receipt = await subscribeServer.receiptsCreate({
amount,
account: { order_id: orderId },
description: `Payment for order ${orderId}`,
detail: {
receipt_type: 0,
items: [
{
title: 'Order Payment',
price: amount,
count: 1,
code: '00702001001000001',
vat_percent: 15,
package_code: '123456'
}
]
}
});
console.log('✅ Receipt created:', receipt.receipt._id);
// 2. Send SMS invoice (optional)
console.log('📱 Sending SMS invoice...');
await subscribeServer.receiptsSend({
id: receipt.receipt._id,
phone: customerPhone
});
console.log('✅ SMS sent');
// 3. Pay with card token
console.log('💳 Processing payment...');
const payment = await subscribeServer.receiptsPay({
id: receipt.receipt._id,
token: cardToken,
payer: {
phone: customerPhone
}
});
if (payment.receipt.state === RECEIPT_STATES.PAID) {
console.log('✅ Payment successful!');
// 4. Get full receipt details
const details = await subscribeServer.receiptsGet({
id: receipt.receipt._id
});
return {
success: true,
receiptId: details.receipt._id,
amount: details.receipt.amount,
card: details.receipt.card?.number,
payTime: details.receipt.pay_time
};
} else {
throw new Error('Payment failed');
}
} catch (error) {
if (error instanceof PaymeError) {
console.error('Payme error:', error.code, error.message);
// Cancel receipt if payment failed
try {
await subscribeServer.receiptsCancel({
id: receipt.receipt._id
});
console.log('Receipt cancelled');
} catch (cancelError) {
console.error('Failed to cancel receipt:', cancelError);
}
}
throw error;
}
}
// Usage
processReceiptPayment('ORD-123', 500000, 'card_token_here', '998901234567')
.then(result => console.log('Payment result:', result))
.catch(error => console.error('Payment error:', error));Database Integration
Receipt Schema
sql
CREATE TABLE IF NOT EXISTS receipts (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL,
amount INTEGER NOT NULL,
state INTEGER NOT NULL DEFAULT 0,
card_token TEXT,
create_time INTEGER NOT NULL,
pay_time INTEGER DEFAULT 0,
cancel_time INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_receipts_order_id ON receipts(order_id);
CREATE INDEX idx_receipts_state ON receipts(state);Save Receipt
typescript
import { Database } from 'bun:sqlite';
const db = new Database('app.db');
function saveReceipt(data: {
id: string;
orderId: string;
amount: number;
state: number;
createTime: number;
}) {
db.run(`
INSERT INTO receipts (id, order_id, amount, state, create_time)
VALUES (?, ?, ?, ?, ?)
`, [data.id, data.orderId, data.amount, data.state, data.createTime]);
}
function updateReceiptState(
id: string,
state: number,
payTime?: number,
cancelTime?: number
) {
if (payTime) {
db.run(`
UPDATE receipts
SET state = ?, pay_time = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`, [state, payTime, id]);
} else if (cancelTime) {
db.run(`
UPDATE receipts
SET state = ?, cancel_time = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`, [state, cancelTime, id]);
}
}Best Practices
✅ Do's
Save receipt ID
typescriptsaveReceipt({ id: receipt.receipt._id, orderId: orderId, amount: amount, state: receipt.receipt.state, createTime: receipt.receipt.create_time });Check card token before payment
typescriptconst cardCheck = await subscribeServer.cardsCheck({ token: cardToken }); if (!cardCheck.card.verify) { throw new Error('Card not verified'); }Handle payment errors
typescripttry { await subscribeServer.receiptsPay(params); } catch (error) { // Cancel receipt if payment failed await subscribeServer.receiptsCancel({ id: receipt.receipt._id }); }Send SMS invoices
typescriptawait subscribeServer.receiptsSend({ id: receipt.receipt._id, phone: customerPhone });
❌ Don'ts
- Don't lose receipt ID
- Don't pay with unverified cards
- Don't forget to cancel failed receipts
- Don't skip error handling
Next Steps
- Learn about Card Tokenization
- Explore Database Integration
- Check Subscribe API Reference
- See Recurring Payment Examples