Create Invoice
The Create Invoice endpoint enables you to generate professional invoices for customers with products, payment terms, and delivery options. Invoices support multiple payment methods, automatic numbering, tax calculations, and optional payment link generation for seamless customer payment processing.
Endpoint DetailsCopied!
-
Method:
POST
-
URL:
/api/v0/invoices
-
Content-Type:
application/json
-
Authentication: Required (API Key & Secret)
-
Rate Limiting: 100 requests per minute
-
Idempotency: Supported (recommended for invoice creation)
Request ParametersCopied!
Required Fields
Field |
Type |
Description |
Example |
---|---|---|---|
|
string |
Invoice name/title |
|
|
string |
Customer email address |
|
|
string (UUID) |
Existing customer identifier |
|
|
string (UUID) |
Wallet for payment processing |
|
|
array |
Products/services on the invoice |
See item structure below |
|
string (date) |
Payment due date (YYYY-MM-DD) |
|
|
enum |
Delivery method |
|
|
boolean |
Generate payment link |
|
|
array |
Accepted payment methods |
|
|
enum |
Invoice status |
|
|
boolean |
Allow partial payments |
|
Optional Fields
Field |
Type |
Description |
Example |
---|---|---|---|
|
string |
Customer address |
|
|
string |
Customer phone number |
|
|
string (date) |
Invoice send date (YYYY-MM-DD) |
|
|
string (URL) |
Company logo URL |
|
|
string (UUID) |
Tax configuration ID |
|
Item Structure
Each item in the items
array requires:
Field |
Type |
Description |
Example |
---|---|---|---|
|
string (UUID) |
Product identifier |
|
|
number |
Quantity of the product |
|
Enums
InvoiceStatus:
-
DRAFT
- Invoice is being prepared -
OPEN
- Invoice sent and awaiting payment -
PAID
- Invoice has been paid -
PASTDUE
- Invoice is overdue -
PARTIALLYPAID
- Partial payment received
DeliveryMethod:
-
EMAIL
- Send via email automatically -
MANUALLY
- Manual delivery/pickup
PaymentMethod:
-
CRYPTO
- Cryptocurrency payments -
BANK_TRANSFER
- Bank transfer/ACH -
CREDIT_CARD
- Credit card payments -
CASH
- Cash payments -
MOBILE_MONEY
- Mobile payment methods
Request ExamplesCopied!
Basic Invoice Creation
curl -X POST "https://api.devdraft.com/api/v0/invoices" \
-H "x-client-key: YOUR_CLIENT_KEY" \
-H "x-client-secret: YOUR_CLIENT_SECRET" \
-H "x-idempotency-key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Website Development Services",
"email": "client@example.com",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"items": [
{
"product_id": "prod_123456789",
"quantity": 1
}
],
"due_date": "2024-02-15",
"delivery": "EMAIL",
"payment_link": true,
"payment_methods": ["CRYPTO", "BANK_TRANSFER"],
"status": "OPEN",
"partial_payment": false
}'
Comprehensive Invoice with Multiple Items
curl -X POST "https://api.devdraft.com/api/v0/invoices" \
-H "x-client-key: YOUR_CLIENT_KEY" \
-H "x-client-secret: YOUR_CLIENT_SECRET" \
-H "x-idempotency-key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Q1 2024 Services Invoice",
"email": "finance@clientcompany.com",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"address": "123 Corporate Blvd, Suite 500, Business City, BC 12345",
"phone_number": "+1-555-987-6543",
"logo": "https://mycompany.com/assets/logo.png",
"items": [
{
"product_id": "prod_consulting_001",
"quantity": 40
},
{
"product_id": "prod_development_002",
"quantity": 80
},
{
"product_id": "prod_maintenance_003",
"quantity": 1
}
],
"due_date": "2024-02-28",
"send_date": "2024-01-15",
"delivery": "EMAIL",
"payment_link": true,
"payment_methods": ["CRYPTO", "BANK_TRANSFER", "CREDIT_CARD"],
"status": "OPEN",
"partial_payment": true,
"taxId": "tax_550e8400-e29b-41d4-a716-446655440123"
}'
Draft Invoice for Review
curl -X POST "https://api.devdraft.com/api/v0/invoices" \
-H "x-client-key: YOUR_CLIENT_KEY" \
-H "x-client-secret: YOUR_CLIENT_SECRET" \
-H "x-idempotency-key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Draft - Custom Development Project",
"email": "project@startup.io",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"items": [
{
"product_id": "prod_custom_dev_001",
"quantity": 160
}
],
"due_date": "2024-03-01",
"delivery": "MANUALLY",
"payment_link": false,
"payment_methods": ["CRYPTO"],
"status": "DRAFT",
"partial_payment": false
}'
JavaScript/Node.js Examples
// Basic invoice creation
const createInvoice = async (invoiceData) => {
try {
const response = await fetch('https://api.devdraft.com/api/v0/invoices', {
method: 'POST',
headers: {
'x-client-key': 'YOUR_CLIENT_KEY',
'x-client-secret': 'YOUR_CLIENT_SECRET',
'x-idempotency-key': generateUUID(),
'Content-Type': 'application/json'
},
body: JSON.stringify(invoiceData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const invoice = await response.json();
return invoice;
} catch (error) {
console.error('Error creating invoice:', error);
throw error;
}
};
// Invoice builder utility
class InvoiceBuilder {
constructor() {
this.invoice = {
items: [],
payment_methods: [],
payment_link: true,
partial_payment: false,
delivery: 'EMAIL',
status: 'DRAFT'
};
}
setBasicInfo(name, email, customerId, walletId) {
this.invoice.name = name;
this.invoice.email = email;
this.invoice.customer_id = customerId;
this.invoice.walletId = walletId;
return this;
}
setDueDate(dueDate) {
this.invoice.due_date = dueDate;
return this;
}
addItem(productId, quantity) {
this.invoice.items.push({
product_id: productId,
quantity: quantity
});
return this;
}
setPaymentMethods(methods) {
this.invoice.payment_methods = methods;
return this;
}
setDelivery(method) {
this.invoice.delivery = method;
return this;
}
setStatus(status) {
this.invoice.status = status;
return this;
}
enablePartialPayments() {
this.invoice.partial_payment = true;
return this;
}
addCustomerDetails(address, phoneNumber) {
if (address) this.invoice.address = address;
if (phoneNumber) this.invoice.phone_number = phoneNumber;
return this;
}
setLogo(logoUrl) {
this.invoice.logo = logoUrl;
return this;
}
async create() {
return await createInvoice(this.invoice);
}
}
// Usage examples
try {
// Using the builder pattern
const invoice = await new InvoiceBuilder()
.setBasicInfo(
'Web Development Services',
'client@example.com',
'550e8400-e29b-41d4-a716-446655440000',
'abcd1234-5678-90ef-ghij-klmnopqrstuv'
)
.setDueDate('2024-02-15')
.addItem('prod_web_dev_001', 1)
.addItem('prod_hosting_001', 12)
.setPaymentMethods(['CRYPTO', 'BANK_TRANSFER'])
.setStatus('OPEN')
.enablePartialPayments()
.addCustomerDetails('123 Business St, City, State', '+1-555-123-4567')
.create();
console.log('Invoice created:', invoice.invoice_number);
// Direct object creation
const quickInvoice = await createInvoice({
name: 'Monthly Subscription',
email: 'subscriber@example.com',
customer_id: '550e8400-e29b-41d4-a716-446655440000',
walletId: 'abcd1234-5678-90ef-ghij-klmnopqrstuv',
items: [{ product_id: 'prod_subscription_001', quantity: 1 }],
due_date: '2024-02-01',
delivery: 'EMAIL',
payment_link: true,
payment_methods: ['CRYPTO'],
status: 'OPEN',
partial_payment: false
});
console.log('Quick invoice created:', quickInvoice.invoice_number);
} catch (error) {
console.error('Invoice creation failed:', error);
}
Python Example
import requests
import json
import uuid
from datetime import datetime, timedelta
def create_invoice(invoice_data, client_key, client_secret):
"""Create a new invoice"""
url = "https://api.devdraft.com/api/v0/invoices"
headers = {
'x-client-key': client_key,
'x-client-secret': client_secret,
'x-idempotency-key': str(uuid.uuid4()),
'Content-Type': 'application/json'
}
try:
response = requests.post(url, headers=headers, json=invoice_data)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"Failed to create invoice: {e}")
class InvoiceBuilder:
"""Invoice builder for easier invoice creation"""
def __init__(self):
self.invoice = {
'items': [],
'payment_methods': [],
'payment_link': True,
'partial_payment': False,
'delivery': 'EMAIL',
'status': 'DRAFT'
}
def set_basic_info(self, name, email, customer_id, wallet_id):
self.invoice.update({
'name': name,
'email': email,
'customer_id': customer_id,
'walletId': wallet_id
})
return self
def set_due_date(self, days_from_now=30):
due_date = datetime.now() + timedelta(days=days_from_now)
self.invoice['due_date'] = due_date.strftime('%Y-%m-%d')
return self
def add_item(self, product_id, quantity):
self.invoice['items'].append({
'product_id': product_id,
'quantity': quantity
})
return self
def set_payment_methods(self, methods):
self.invoice['payment_methods'] = methods
return self
def set_status(self, status):
self.invoice['status'] = status
return self
def enable_partial_payments(self):
self.invoice['partial_payment'] = True
return self
def add_customer_details(self, address=None, phone_number=None):
if address:
self.invoice['address'] = address
if phone_number:
self.invoice['phone_number'] = phone_number
return self
def create(self, client_key, client_secret):
return create_invoice(self.invoice, client_key, client_secret)
# Usage examples
try:
# Using builder pattern
invoice = (InvoiceBuilder()
.set_basic_info(
"Consulting Services",
"client@example.com",
"550e8400-e29b-41d4-a716-446655440000",
"abcd1234-5678-90ef-ghij-klmnopqrstuv"
)
.set_due_date(30)
.add_item("prod_consulting_001", 20)
.add_item("prod_analysis_001", 1)
.set_payment_methods(["CRYPTO", "BANK_TRANSFER"])
.set_status("OPEN")
.enable_partial_payments()
.add_customer_details("123 Business Ave", "+1-555-123-4567")
.create("YOUR_CLIENT_KEY", "YOUR_CLIENT_SECRET"))
print(f"Invoice created: {invoice['invoice_number']}")
# Direct creation
simple_invoice = create_invoice({
'name': 'Software License',
'email': 'customer@example.com',
'customer_id': '550e8400-e29b-41d4-a716-446655440000',
'walletId': 'abcd1234-5678-90ef-ghij-klmnopqrstuv',
'items': [{'product_id': 'prod_license_001', 'quantity': 1}],
'due_date': '2024-02-15',
'delivery': 'EMAIL',
'payment_link': True,
'payment_methods': ['CRYPTO'],
'status': 'OPEN',
'partial_payment': False
}, "YOUR_CLIENT_KEY", "YOUR_CLIENT_SECRET")
print(f"Simple invoice created: {simple_invoice['invoice_number']}")
except Exception as e:
print(f"Error: {e}")
Response FormatCopied!
Success Response (201 Created)
{
"id": "inv_550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "INV-000001",
"name": "Website Development Services",
"app_id": "app_123456789",
"email": "client@example.com",
"address": "123 Business St, City, State",
"phone_number": "+1-555-123-4567",
"logo": "https://mycompany.com/assets/logo.png",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"due_date": "2024-02-15T00:00:00.000Z",
"send_date": "2024-01-15T00:00:00.000Z",
"date_created": "2024-01-15T10:30:00.000Z",
"status": "OPEN",
"payment_methods": ["CRYPTO", "BANK_TRANSFER"],
"delivery": "EMAIL",
"payment_link": true,
"partial_payment": false,
"reminder_sent": false,
"paidAt": null,
"paymentMetadata": null,
"paymentStatus": null,
"taxId": "tax_550e8400-e29b-41d4-a716-446655440123",
"currency": "USDC",
"app": {
"id": "app_123456789",
"name": "My Business App"
},
"customer": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "client@example.com",
"name": "John Doe",
"status": "ACTIVE"
},
"wallet": {
"id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"address": "0x742d35Cc6635C0532925a3b8d",
"blockchain": "ETHEREUM",
"type": "APP"
},
"tax": {
"id": "tax_550e8400-e29b-41d4-a716-446655440123",
"name": "Standard Sales Tax",
"rate": 8.5,
"type": "PERCENTAGE"
},
"items": [
{
"invoice_id": "inv_550e8400-e29b-41d4-a716-446655440000",
"productId": "prod_123456789",
"quantity": 1,
"product": {
"id": "prod_123456789",
"name": "Website Development",
"price": 2500.00,
"currency": "USD"
}
}
],
"transactions": []
}
Error ResponsesCopied!
Validation Error (400 Bad Request)
{
"statusCode": 400,
"message": [
"due_date must be a valid date in YYYY-MM-DD format",
"customer_id must be a valid UUID",
"items should not be empty"
],
"error": "Bad Request"
}
Customer Not Found (404 Not Found)
{
"statusCode": 404,
"message": "Customer not found",
"error": "Not Found"
}
Wallet Not Found (404 Not Found)
{
"statusCode": 404,
"message": "Wallet could not be found",
"error": "Not Found"
}
Product Not Found (400 Bad Request)
{
"statusCode": 400,
"message": "Product with ID 'prod_invalid' not found",
"error": "Bad Request"
}
Date Validation Error (400 Bad Request)
{
"statusCode": 400,
"message": "Due date cannot be in the past",
"error": "Bad Request"
}
Authentication Error (401 Unauthorized)
{
"statusCode": 401,
"message": "Invalid or missing API credentials",
"error": "Unauthorized"
}
Rate Limit Error (429 Too Many Requests)
{
"statusCode": 429,
"message": "Rate limit exceeded. Maximum 100 requests per minute.",
"error": "Too Many Requests",
"retryAfter": 60
}
Business Logic & FeaturesCopied!
Automatic Invoice Numbering
-
Sequential numbering:
INV-000001
,INV-000002
, etc. -
Per-application: Each app maintains its own sequence
-
Collision-safe: Atomic increment ensures unique numbers
-
Customizable format: Number format can be configured
Payment Link Generation
-
Automatic creation: When
payment_link: true
-
Secure URLs: Unique, non-guessable payment URLs
-
Multiple methods: Supports all specified payment methods
-
Expiration: Links can be configured to expire with due date
Tax Calculations
-
Automatic computation: When
taxId
is provided -
Multiple tax types: Percentage, fixed amount, compound taxes
-
Regional support: Different tax rules by jurisdiction
-
Inclusive/exclusive: Configurable tax application methods
Email Delivery
-
Automatic sending: When
delivery: "EMAIL"
-
Professional templates: Branded invoice emails
-
PDF attachments: Auto-generated PDF invoices
-
Delivery tracking: Email open and click tracking
Status Management
-
DRAFT: Invoice being prepared, not yet sent
-
OPEN: Invoice sent, awaiting payment
-
PAID: Full payment received
-
PASTDUE: Payment overdue
-
PARTIALLYPAID: Partial payment received
Advanced Use CasesCopied!
Recurring Invoice Creation
// Create recurring invoices with template
const createRecurringInvoice = async (templateData, scheduleOptions) => {
const { frequency, count, startDate } = scheduleOptions;
const invoices = [];
for (let i = 0; i < count; i++) {
const dueDate = new Date(startDate);
switch (frequency) {
case 'MONTHLY':
dueDate.setMonth(dueDate.getMonth() + i);
break;
case 'QUARTERLY':
dueDate.setMonth(dueDate.getMonth() + (i * 3));
break;
case 'ANNUALLY':
dueDate.setFullYear(dueDate.getFullYear() + i);
break;
}
const invoiceData = {
...templateData,
name: `${templateData.name} - ${dueDate.toISOString().slice(0, 7)}`,
due_date: dueDate.toISOString().slice(0, 10),
send_date: new Date(dueDate.getTime() - (7 * 24 * 60 * 60 * 1000))
.toISOString().slice(0, 10) // 7 days before due date
};
try {
const invoice = await createInvoice(invoiceData);
invoices.push(invoice);
} catch (error) {
console.error(`Failed to create invoice ${i + 1}:`, error);
}
}
return invoices;
};
// Usage
const recurringInvoices = await createRecurringInvoice({
name: 'Monthly Subscription',
email: 'client@example.com',
customer_id: '550e8400-e29b-41d4-a716-446655440000',
walletId: 'abcd1234-5678-90ef-ghij-klmnopqrstuv',
items: [{ product_id: 'prod_subscription_001', quantity: 1 }],
delivery: 'EMAIL',
payment_link: true,
payment_methods: ['CRYPTO'],
status: 'DRAFT', // Will be updated to OPEN when sent
partial_payment: false
}, {
frequency: 'MONTHLY',
count: 12,
startDate: '2024-02-01'
});
Bulk Invoice Creation
// Create multiple invoices for different customers
const createBulkInvoices = async (invoiceList) => {
const results = [];
const batchSize = 10;
for (let i = 0; i < invoiceList.length; i += batchSize) {
const batch = invoiceList.slice(i, i + batchSize);
const batchPromises = batch.map(async (invoiceData, index) => {
try {
const invoice = await createInvoice(invoiceData);
return { success: true, invoice, originalIndex: i + index };
} catch (error) {
return {
success: false,
error: error.message,
originalIndex: i + index,
data: invoiceData
};
}
});
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
// Rate limiting delay
if (i + batchSize < invoiceList.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return {
successful: results.filter(r => r.success),
failed: results.filter(r => !r.success),
summary: {
total: invoiceList.length,
successful: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length
}
};
};
Invoice Templates
// Predefined invoice templates
const invoiceTemplates = {
consulting: {
name: 'Consulting Services Invoice',
payment_methods: ['CRYPTO', 'BANK_TRANSFER'],
delivery: 'EMAIL',
payment_link: true,
partial_payment: true,
status: 'OPEN'
},
subscription: {
name: 'Monthly Subscription',
payment_methods: ['CRYPTO'],
delivery: 'EMAIL',
payment_link: true,
partial_payment: false,
status: 'OPEN'
},
oneTime: {
name: 'One-time Service',
payment_methods: ['CRYPTO', 'BANK_TRANSFER'],
delivery: 'EMAIL',
payment_link: true,
partial_payment: false,
status: 'OPEN'
}
};
const createFromTemplate = async (templateName, customData) => {
const template = invoiceTemplates[templateName];
if (!template) {
throw new Error(`Template '${templateName}' not found`);
}
const invoiceData = {
...template,
...customData,
// Ensure required fields are present
items: customData.items || [],
due_date: customData.due_date ||
new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
.toISOString().slice(0, 10)
};
return await createInvoice(invoiceData);
};
Invoice Validation & Preview
// Validate invoice data before creation
const validateInvoiceData = (invoiceData) => {
const errors = [];
// Required field validation
const required = ['name', 'email', 'customer_id', 'walletId', 'items', 'due_date'];
required.forEach(field => {
if (!invoiceData[field]) {
errors.push(`${field} is required`);
}
});
// Date validation
if (invoiceData.due_date) {
const dueDate = new Date(invoiceData.due_date);
if (dueDate < new Date()) {
errors.push('Due date cannot be in the past');
}
}
if (invoiceData.send_date && invoiceData.due_date) {
const sendDate = new Date(invoiceData.send_date);
const dueDate = new Date(invoiceData.due_date);
if (sendDate > dueDate) {
errors.push('Send date cannot be after due date');
}
}
// Items validation
if (invoiceData.items && invoiceData.items.length === 0) {
errors.push('At least one item is required');
}
// Email validation
if (invoiceData.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(invoiceData.email)) {
errors.push('Invalid email format');
}
return {
isValid: errors.length === 0,
errors
};
};
// Preview invoice calculations
const previewInvoice = async (invoiceData) => {
const validation = validateInvoiceData(invoiceData);
if (!validation.isValid) {
return { error: 'Validation failed', errors: validation.errors };
}
// Calculate totals (simplified - actual calculation would involve API calls)
let subtotal = 0;
const itemDetails = [];
for (const item of invoiceData.items) {
// In real implementation, fetch product details
const product = await fetchProduct(item.product_id);
const lineTotal = product.price * item.quantity;
itemDetails.push({
product: product.name,
quantity: item.quantity,
unitPrice: product.price,
lineTotal
});
subtotal += lineTotal;
}
// Calculate tax if applicable
let taxAmount = 0;
if (invoiceData.taxId) {
const tax = await fetchTax(invoiceData.taxId);
taxAmount = subtotal * (tax.rate / 100);
}
const total = subtotal + taxAmount;
return {
preview: {
subtotal,
taxAmount,
total,
items: itemDetails,
dueDate: invoiceData.due_date,
paymentMethods: invoiceData.payment_methods
},
validation
};
};
Integration PatternsCopied!
Error Handling & Retry Logic
// Robust invoice creation with retry
const createInvoiceWithRetry = async (invoiceData, maxRetries = 3) => {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await createInvoice(invoiceData);
} catch (error) {
lastError = error;
// Don't retry for validation errors
if (error.message.includes('400') || error.message.includes('404')) {
throw error;
}
// Exponential backoff for retryable errors
const delay = Math.pow(2, attempt) * 1000;
console.warn(`Invoice creation attempt ${attempt} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error(`Invoice creation failed after ${maxRetries} attempts: ${lastError.message}`);
};
Webhook Integration
// Handle invoice events via webhooks
const handleInvoiceWebhook = (webhookData) => {
const { event, invoice } = webhookData;
switch (event) {
case 'invoice.created':
console.log(`Invoice ${invoice.invoice_number} created`);
// Update internal systems
updateCRM(invoice);
break;
case 'invoice.paid':
console.log(`Invoice ${invoice.invoice_number} paid`);
// Fulfill services
fulfillOrder(invoice);
break;
case 'invoice.overdue':
console.log(`Invoice ${invoice.invoice_number} is overdue`);
// Send reminder
sendOverdueReminder(invoice);
break;
}
};
Best PracticesCopied!
Data Validation
-
Validate all inputs before API calls
-
Check customer existence before creating invoices
-
Verify product availability and pricing
-
Ensure wallet accessibility for payment processing
Error Management
-
Handle validation errors gracefully with user-friendly messages
-
Implement retry logic for transient failures
-
Log all creation attempts for audit and debugging
-
Provide fallback options when primary methods fail
Performance Optimization
-
Cache product data to reduce API calls during bulk operations
-
Use bulk operations when creating multiple invoices
-
Implement pagination for large invoice lists
-
Optimize database queries for better performance
Security Considerations
-
Validate user permissions before allowing invoice creation
-
Sanitize all input data to prevent injection attacks
-
Use idempotency keys to prevent duplicate invoices
-
Audit all invoice operations for compliance
Next StepsCopied!
After creating an invoice, you can:
-
Send Invoice: Automatically deliver to customer via email
-
Track Payments: Monitor payment status and process transactions
-
Send Reminders: Automated follow-up for overdue invoices
-
Generate Reports: Analyze invoice performance and trends
-
Update Status: Manage invoice lifecycle and status changes
For more information, see: