Available on: Business and Enterprise plans
The TallySale API lets you create and manage invoices programmatically from your own applications — SaaS platforms, e-commerce sites, ERPs, or any system that needs to issue invoices.
Prerequisites
- A Business or Enterprise seller level (API access is not available on Starter)
- A Seller App with API Key and Secret (created by an administrator under Seller Apps)
Authentication
TallySale uses HMAC-SHA256 API key authentication. Every request must include three headers:
| Header | Description |
|---|---|
X-API-Key |
Your Seller App's app_key (starts with ts_) |
X-API-Signature |
HMAC-SHA256 signature of the request |
X-API-Timestamp |
Current Unix timestamp (seconds) |
Signature Calculation
The signature is calculated as:
signature = HMAC-SHA256(app_secret, method + path + timestamp + body)
Where:
method— HTTP method in uppercase (GET,POST,PUT,DELETE)path— Request path (e.g.,/v1/invoices)timestamp— Same value asX-API-Timestampheaderbody— Request body as a string (empty string for GET requests)
Security: Never expose your API Secret in client-side code (browser JavaScript, mobile apps). All API calls must originate from your server.
Base URL
https://api.tallysale.com/v1
Endpoints
Invoices
| Method | Path | Description |
|---|---|---|
GET |
/v1/invoices |
List all invoices |
GET |
/v1/invoices/{id} |
Get invoice detail |
Invoices listed here are read-only in the admin portal. They are created via the Seller Invoice endpoints below.
Seller Invoices
| Method | Path | Description |
|---|---|---|
GET |
/v1/seller-invoices |
List invoices |
POST |
/v1/seller-invoices |
Create a new invoice |
GET |
/v1/seller-invoices/{id} |
Get invoice detail |
PUT |
/v1/seller-invoices/{id} |
Update a draft invoice |
POST |
/v1/seller-invoices/{id}/finalize |
Finalize (lock for payment) |
POST |
/v1/seller-invoices/{id}/send |
Send via email |
POST |
/v1/seller-invoices/{id}/void |
Cancel the invoice |
POST |
/v1/seller-invoices/{id}/mark-paid |
Record manual payment |
POST |
/v1/seller-invoices/{id}/duplicate |
Duplicate as new draft |
GET |
/v1/seller-invoices/{id}/pdf |
Download PDF |
Other Endpoints
| Method | Path | Description |
|---|---|---|
GET |
/v1/seller-invoices/summary |
Dashboard summary stats |
GET |
/v1/seller-invoices/customers/search |
Search customers |
GET |
/v1/seller-invoices/payments |
Payment history |
GET |
/v1/seller-invoices/credit-notes |
List credit notes |
Creating an Invoice — Request
POST /v1/seller-invoices
Content-Type: application/json
{
"customer_email": "customer@example.com",
"customer_name": "Aung Aung",
"customer_phone": "+959123456789",
"due_date": "2026-07-15",
"notes": "Thank you for your business",
"line_items": [
{
"description": "Web Development Service",
"quantity": 1,
"unit_price": 500000
},
{
"description": "Hosting (Monthly)",
"quantity": 12,
"unit_price": 25000
}
],
"discount_type": "percentage",
"discount_value": 5
}
Creating an Invoice — Response
{
"message": "Invoice created successfully",
"data": {
"id": "1234567890123456789",
"invoice_number": "INV-2026-0042",
"status": "DRAFT",
"customer_email": "customer@example.com",
"customer_name": "Aung Aung",
"subtotal": 800000,
"discount_amount": 40000,
"total_amount": 760000,
"currency": "MMK",
"due_date": "2026-07-15",
"source": "api",
"checkout_url": "https://pay.tallysale.com/c/abc123",
"created_at": "2026-06-24T12:00:00Z"
}
}
Code Examples
Node.js
const crypto = require('crypto');
const axios = require('axios');
const API_KEY = 'ts_your_app_key_here';
const API_SECRET = 'your_app_secret_here';
const BASE_URL = 'https://api.tallysale.com';
function createSignature(method, path, timestamp, body = '') {
const payload = method + path + timestamp + body;
return crypto
.createHmac('sha256', API_SECRET)
.update(payload)
.digest('hex');
}
async function createInvoice() {
const method = 'POST';
const path = '/v1/seller-invoices';
const timestamp = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({
customer_email: 'customer@example.com',
customer_name: 'Aung Aung',
due_date: '2026-07-15',
line_items: [
{
description: 'Web Development Service',
quantity: 1,
unit_price: 500000
}
]
});
const signature = createSignature(method, path, timestamp, body);
try {
const response = await axios({
method: method,
url: BASE_URL + path,
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
'X-API-Signature': signature,
'X-API-Timestamp': timestamp
},
data: body
});
console.log('Invoice created:', response.data);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
createInvoice();
PHP
<?php
$apiKey = 'ts_your_app_key_here';
$apiSecret = 'your_app_secret_here';
$baseUrl = 'https://api.tallysale.com';
function createSignature(string $method, string $path, string $timestamp, string $body = ''): string {
global $apiSecret;
$payload = $method . $path . $timestamp . $body;
return hash_hmac('sha256', $payload, $apiSecret);
}
function createInvoice(): void {
global $apiKey, $baseUrl;
$method = 'POST';
$path = '/v1/seller-invoices';
$timestamp = (string) time();
$body = json_encode([
'customer_email' => 'customer@example.com',
'customer_name' => 'Aung Aung',
'due_date' => '2026-07-15',
'line_items' => [
[
'description' => 'Web Development Service',
'quantity' => 1,
'unit_price' => 500000,
],
],
]);
$signature = createSignature($method, $path, $timestamp, $body);
$ch = curl_init($baseUrl . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-API-Key: ' . $apiKey,
'X-API-Signature: ' . $signature,
'X-API-Timestamp: ' . $timestamp,
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Status: {$httpCode}\n";
echo "Response: {$response}\n";
}
createInvoice();
Python
import hmac
import hashlib
import time
import json
import requests
API_KEY = 'ts_your_app_key_here'
API_SECRET = 'your_app_secret_here'
BASE_URL = 'https://api.tallysale.com'
def create_signature(method: str, path: str, timestamp: str, body: str = '') -> str:
payload = method + path + timestamp + body
return hmac.new(
API_SECRET.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
def create_invoice():
method = 'POST'
path = '/v1/seller-invoices'
timestamp = str(int(time.time()))
body = json.dumps({
'customer_email': 'customer@example.com',
'customer_name': 'Aung Aung',
'due_date': '2026-07-15',
'line_items': [
{
'description': 'Web Development Service',
'quantity': 1,
'unit_price': 500000,
},
],
})
signature = create_signature(method, path, timestamp, body)
response = requests.post(
BASE_URL + path,
headers={
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
'X-API-Signature': signature,
'X-API-Timestamp': timestamp,
},
data=body,
)
print(f'Status: {response.status_code}')
print(f'Response: {response.json()}')
return response.json()
if __name__ == '__main__':
create_invoice()
Listing Invoices — Example (Node.js)
async function listInvoices(page = 1, perPage = 20) {
const method = 'GET';
const path = '/v1/seller-invoices';
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = createSignature(method, path, timestamp);
const response = await axios({
method: method,
url: `${BASE_URL}${path}?page=${page}&per_page=${perPage}`,
headers: {
'X-API-Key': API_KEY,
'X-API-Signature': signature,
'X-API-Timestamp': timestamp
}
});
console.log(`Found ${response.data.meta.total} invoices`);
return response.data;
}
Webhooks
Available on: Business and Enterprise plans
If your Seller App has webhooks enabled, TallySale will send HTTP POST callbacks to your backend_callback_url when invoice events occur:
| Event | Trigger |
|---|---|
invoice.paid |
Customer completes payment |
invoice.partially_paid |
Customer makes a partial payment |
invoice.voided |
Invoice is cancelled |
invoice.refunded |
Credit note issued against the invoice |
Webhook Payload
{
"event": "invoice.paid",
"timestamp": "2026-06-24T15:30:00Z",
"data": {
"invoice_id": "1234567890123456789",
"invoice_number": "INV-2026-0042",
"status": "PAID",
"total_amount": 760000,
"paid_amount": 760000,
"currency": "MMK",
"customer_email": "customer@example.com",
"payment_method": "kbz_pay"
},
"signature": "hmac_sha256_signature_here"
}
Verifying Webhook Signatures
Always verify the webhook signature to ensure the request is from TallySale:
function verifyWebhook(payload, signature) {
const expected = crypto
.createHmac('sha256', API_SECRET)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
Rate Limits
API requests are rate-limited based on your Seller Level:
| Level | Read Requests | Write Requests |
|---|---|---|
| Business | 60 / minute | 30 / minute |
| Enterprise | Unlimited | 120 / minute |
Rate-limited responses return HTTP 429 Too Many Requests with a Retry-After header.
Error Responses
All errors follow a standard format:
{
"message": "Validation error",
"data": {
"customer_email": ["The customer email field is required."],
"line_items": ["At least one line item is required."]
}
}
| HTTP Code | Meaning |
|---|---|
200 |
Success |
201 |
Resource created |
400 |
Bad request (invalid input) |
401 |
Authentication failed (invalid API key or signature) |
403 |
Forbidden (insufficient permissions or feature not available) |
404 |
Resource not found |
422 |
Validation error |
429 |
Rate limit exceeded |
500 |
Server error |