Deletion
Delete mutations in the Moloni ON API permanently remove records. They support bulk operations, return detailed result counts, and enforce business rules that prevent deleting records still in use.
The DeletionError response
All delete mutations return a DeletionError object:
| Field | Type | Description |
|---|---|---|
status | Boolean | true if at least one item was deleted |
deletedCount | Int! | Number of items actually deleted |
elementsCount | Int | Total remaining items of this type after deletion |
errors | [Error]! | Error messages (empty on success) |
{
"data": {
"customerDelete": {
"status": true,
"deletedCount": 3,
"elementsCount": 97,
"errors": []
}
}
}
Basic deletion
All delete mutations accept an array of IDs, even when deleting a single item:
mutation {
customerDelete(companyId: 1, customerId: [42]) {
status
deletedCount
elementsCount
errors { field msg }
}
}
The mutation name follows the pattern {entity}Delete, and the ID parameter accepts an array of the entity's ID type.
Bulk deletion
Pass multiple IDs to delete several records at once:
mutation {
productDelete(companyId: 1, productId: [10, 11, 12, 13, 14]) {
status
deletedCount
elementsCount
errors { field msg }
}
}
Response:
{
"data": {
"productDelete": {
"status": true,
"deletedCount": 5,
"elementsCount": 245,
"errors": []
}
}
}
Deletability rules
Not every record can be deleted. The API checks whether each item is deletable before proceeding. Items that can't be deleted are silently skipped and don't appear in the errors array.
For example, a customer that has associated documents cannot be deleted:
mutation {
customerDelete(companyId: 1, customerId: [42, 43, 44]) {
status
deletedCount
errors { field msg }
}
}
If customer 43 has invoices linked to it:
{
"data": {
"customerDelete": {
"status": true,
"deletedCount": 2,
"errors": []
}
}
}
Customers 42 and 44 were deleted, but 43 was skipped. The deletedCount tells you how many were actually removed.
Common reasons an item is not deletable
| Entity | Reason |
|---|---|
| Customer | Has associated documents (invoices, receipts, etc.) |
| Supplier | Has associated documents or products |
| Product | Is used in existing documents |
Document deletion
Documents (invoices, receipts, credit notes, etc.) follow stricter rules than other entities.
Draft documents
Draft documents (status: 0) can always be deleted:
mutation {
invoiceDelete(companyId: 1, documentId: [1234]) {
status
deletedCount
errors { field msg }
}
}
Finalized documents
Finalized documents (status: 1) can be deleted in some cases, but:
- The document type must allow closed-document deletion
- The document must not be referenced by other documents (e.g. a receipt settling it)
- Any paid commissions must not be already reconciled
When a finalized document is deleted, the API automatically:
- Reverts stock movements
- Reverts commission calculations
- Reverts applied values on related document products
- Reverts payment records
Handling deletion responses
const result = data.customerDelete;
if (result.errors.length > 0) {
// Permission or general error
console.error(result.errors[0].msg);
return;
}
if (result.status) {
console.log(`Deleted ${result.deletedCount} items. ${result.elementsCount} remaining.`);
} else {
console.log('No items were deleted.');
}
When requesting deletion of multiple items, compare deletedCount against the number of IDs you passed to know if any were skipped:
const idsToDelete = [42, 43, 44];
// ... execute mutation ...
if (result.deletedCount < idsToDelete.length) {
const skipped = idsToDelete.length - result.deletedCount;
console.warn(`${skipped} items could not be deleted (in use or not found).`);
}
Permanent deletion
All deletions are permanent. Records are completely removed from the database; there is no soft-delete or recycle bin. Make sure you have the data you need before deleting.
Next steps
- Error Handling: Understand permission errors and the general error model
- Querying Documents: Use the
deletablefield to check before attempting deletion