Billbee Custom Shop SDK
Connect your custom .NET e-commerce platform to Billbee in minutes, not weeks.

A complete .NET SDK that transforms the complex Billbee Custom Shop API into simple method implementations. No HTTP handling, no authentication complexity, no routing headaches.
⚠️ Authorization Required: The Billbee Custom Shop API requires explicit permission from Billbee GmbH.
⚠️ Unofficial: This SDK is maintained by Mr. & Mrs. Panda, not Billbee GmbH.
Why This SDK?
Without this SDK:
With this SDK:
public class MyShop : BillbeeCustomShopService
{
protected override async Task<OrderResponse> GetOrdersAsync(DateTime startDate, int page, int pageSize)
=> await _database.GetOrdersSince(startDate, page, pageSize);
protected override string GetApiKey() => _config["Billbee:ApiKey"];
}
What Is Billbee?
Billbee is a multichannel e-commerce management platform that centralizes:
- Order Management - Unified inbox for all sales channels
- Inventory Sync - Real-time stock across platforms
- Automated Fulfillment - Shipping labels and tracking
- Financial Management - Invoicing and accounting integration
While Billbee supports major platforms (Shopify, Amazon, eBay), custom shops need this API.
Installation
dotnet add package Panda.Billbee.CustomShopSdk
dotnet add package Panda.Billbee.CustomShopSdk.AspNetCore
Quick Start
1. Create Your Service
using Panda.Billbee.CustomShopSdk.Services;
using Panda.Billbee.CustomShopSdk.Models;
using Panda.Billbee.CustomShopSdk.Models.Orders;
using Panda.Billbee.CustomShopSdk.Models.Products;
public class MyShopService : BillbeeCustomShopService
{
private readonly IMyDatabase _database;
private readonly IConfiguration _config;
public MyShopService(IMyDatabase database, IConfiguration config)
{
_database = database;
_config = config;
}
protected override string GetApiKey() => _config["Billbee:ApiKey"];
protected override async Task<OrderResponse> GetOrdersAsync(DateTime startDate, int page, int pageSize)
{
var orders = await _database.GetOrdersSince(startDate, page, pageSize);
return new OrderResponse
{
Orders = orders.Select(MapToOrder).ToList(),
Paging = new PagingInfo
{
Page = page,
PageSize = pageSize,
TotalCount = await _database.CountOrdersSince(startDate)
}
};
}
protected override async Task<Order?> GetOrderAsync(string orderId)
{
var order = await _database.GetOrderById(orderId);
return order == null ? null : MapToOrder(order);
}
protected override async Task AckOrderAsync(string orderId)
{
await _database.MarkOrderAsAcknowledged(orderId);
}
protected override async Task SetOrderStateAsync(SetOrderStateRequest request)
{
await _database.UpdateOrderStatus(request.OrderId, request.NewStateId, request.Comment);
if (!string.IsNullOrEmpty(request.TrackingCode))
await _database.SetTrackingInfo(request.OrderId, request.TrackingCode, request.TrackingUrl);
}
protected override async Task<Product?> GetProductAsync(string productId)
{
var product = await _database.GetProductById(productId);
return product == null ? null : MapToProduct(product);
}
protected override async Task<ProductResponse> GetProductsAsync(int page, int pageSize)
{
var products = await _database.GetProducts(page, pageSize);
return new ProductResponse
{
Products = products.Select(MapToProduct).ToList(),
Paging = new PagingInfo { Page = page, PageSize = pageSize, TotalCount = await _database.CountProducts() }
};
}
protected override async Task SetStockAsync(SetStockRequest request)
{
if (request.AvailableStock.HasValue)
await _database.UpdateStock(request.ProductId, request.AvailableStock.Value);
}
protected override async Task<List<ShippingProfile>> GetShippingProfilesAsync()
{
return new List<ShippingProfile>
{
new() { Id = "standard", Name = "Standard Shipping" },
new() { Id = "express", Name = "Express Shipping" }
};
}
private Order MapToOrder(MyOrderModel order) => new()
{
OrderId = order.Id.ToString(),
OrderNumber = order.Number,
OrderDate = order.CreatedAt,
Email = order.CustomerEmail,
CurrencyCode = order.Currency,
ShipCost = order.ShippingCost,
InvoiceAddress = MapToAddress(order.BillingAddress),
DeliveryAddress = MapToAddress(order.ShippingAddress),
OrderProducts = order.Items?.Select(MapToOrderProduct).ToList()
};
private Product MapToProduct(MyProductModel product) => new()
{
Id = product.Id.ToString(),
Title = product.Name,
Description = product.Description,
Price = product.Price,
Quantity = product.Stock,
Sku = product.Sku,
Weight = product.Weight
};
}
2. Create Controller
using Microsoft.AspNetCore.Mvc;
using Panda.Billbee.CustomShopSdk.AspNetCore.Controllers;
[ApiController]
[Route("api/billbee")]
public class BillbeeController : BillbeeControllerBase
{
private readonly MyShopService _shopService;
public BillbeeController(MyShopService shopService) => _shopService = shopService;
protected override IBillbeeCustomShopService BillbeeService => _shopService;
}
3. Register Services
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddScoped<MyShopService>();
builder.Services.AddScoped<IMyDatabase, MyDatabase>();
var app = builder.Build();
app.MapControllers();
app.Run();
4. Configure Billbee
In your appsettings.json:
{
"Billbee": {
"ApiKey": "your-secret-api-key-from-billbee"
}
}
In Billbee dashboard:
- Settings → Channels → Custom Shop
- Set URL:
https://yourshop.com/api/billbee
- Set the same API key
- Test connection
Done! 🎉 Your shop is now integrated with Billbee.
API Reference
The SDK automatically handles these endpoints:
GET | ?Action=GetOrders&StartDate=2024-01-01&Page=1&PageSize=100 | Fetch orders since date |
GET | ?Action=GetOrder&OrderId=12345 | Get single order |
GET | ?Action=GetProduct&ProductId=67890 | Get single product |
GET | ?Action=GetProducts&Page=1&PageSize=50 | Get products list |
GET | ?Action=GetShippingProfiles | Get shipping methods |
POST | ?Action=AckOrder | Acknowledge order receipt |
POST | ?Action=SetOrderState | Update order status |
POST | ?Action=SetStock | Update product inventory |
Core Models
Order
public class Order
{
public string? OrderId { get; set; }
public string? OrderNumber { get; set; }
public DateTime? OrderDate { get; set; }
public string? Email { get; set; }
public string? CurrencyCode { get; set; }
public decimal ShipCost { get; set; }
public Address? InvoiceAddress { get; set; }
public Address? DeliveryAddress { get; set; }
public List<OrderProduct>? OrderProducts { get; set; }
}
Product
public class Product
{
public string? Id { get; set; }
public string? Title { get; set; }
public string? Description { get; set; }
public string? Sku { get; set; }
public decimal? Price { get; set; }
public decimal? Quantity { get; set; }
public decimal? Weight { get; set; }
public List<ProductImage>? Images { get; set; }
}
Advanced Usage
Error Handling & Logging
public class BillbeeController : BillbeeControllerBase
{
public BillbeeController(MyShopService shopService, ILogger<BillbeeController> logger)
: base(logger)
{
_shopService = shopService;
}
protected override async Task NotifyErrorAsync(ServiceResult serviceResult)
{
await base.NotifyErrorAsync(serviceResult);
if (serviceResult.ErrorType == ServiceErrorType.InternalServerError)
{
await _alertingService.SendAlert(serviceResult.GetErrorMessage());
}
}
}
Additional Authentication
protected override string GetApiKey() => _config["Billbee:ApiKey"];
protected override (string? Username, string? Password) GetBasicAuthCredentials()
=> (_config["Billbee:Username"], _config["Billbee:Password"]);
Multiple Shops
Create separate service classes and controllers:
BookstoreService
with /bookstore-api
route
ElectronicsService
with /electronics-api
route
- Each with their own API keys and configurations
Development Mode
protected override string? GetApiKey()
{
#if DEBUG
return null;
#else
return _config["Billbee:ApiKey"];
#endif
}
Troubleshooting
"Action parameter is required" | Ensure Billbee sends ?Action=GetOrders in URL |
401 Unauthorized | Verify API key matches Billbee configuration |
404 Not Found | Check controller route matches Billbee webhook URL |
Orders not syncing | Verify OrderDate and date filtering logic |
Stock updates failing | Implement SetStockAsync and check ProductId mapping |
Best Practices
✅ Always use HTTPS in production
✅ Implement proper async/await patterns
✅ Handle time zones correctly (Billbee uses UTC)
✅ Monitor performance for large datasets
✅ Test with small batches before going live
✅ Log important events (orders exported, stock updated)
Data Flow
Billbee ──GET──→ Your API ──→ Your Database
↑ ↓ ↓
│ (Fetch Orders) (Load Data)
│ ↓ ↓
└─────JSON Response ←──── SDK Mapping
- Billbee periodically calls your API endpoints
- Your API (via this SDK) routes to your service methods
- Your Service fetches data from your database
- SDK handles JSON serialization and HTTP responses
- Billbee processes the data for order management
Migration from v1.x
Before (complex):
public class MyShop : BillbeeCustomShopService
{
protected override IOrderService GetOrderService() => new MyOrderService();
protected override IProductService GetProductService() => new MyProductService();
}
After (simple):
public class MyShop : BillbeeCustomShopService
{
protected override async Task<OrderResponse> GetOrdersAsync(DateTime startDate, int page, int pageSize)
=> await LoadOrdersFromDatabase(startDate, page, pageSize);
}
License & Support
Legal Notice: Using the Billbee Custom Shop API requires permission from Billbee GmbH.