Document Service
Note: The sales order model has been replaced by the generic Document model. All endpoints are now under
/api/v1/Documents. The document approach supports multiple document types (sales orders, credit notes, quotes, etc.) through theDocumentTypeIdfield.
Overview
Documents represent transactional records — sales orders, credit notes, quotes, and any other document type defined in ref.DocumentType.
Documents provide a consistent reference for:
- recording and processing customer orders
- tracking status, fulfillment, and dispatch
- stamping immutable billing and shipping address snapshots at creation time
- attaching line items, files, and time entries
- reporting and analytics
Soft delete is supported — deleted documents have IsDeleted = true and a DeletedAt timestamp rather than being physically removed.
All document operations are tenant-aware.
Database tables
sales.Documentsales.DocumentLinesales.DocumentAddressSnapshotref.DocumentTyperef.DocumentCategory
Endpoints
GET
/api/v1/Documents
Returns a paginated, filterable list of documents.
Query parameters (pagination):
page(int, default: 1) — page number (1-based)pageSize(int, default: 20, max: 100) — items per page. Pass0to receive onlytotalCountwith an emptyitemsarraysortBy(string, optional) — field to sort by:ordernumber,orderdate,grandtotal,createdatsortDesc(bool, default: false) — sort descending
Query parameters (filters):
search(string, optional) — search across order number and courier referenceentityId(long, optional) — filter by customer/entity IDdocumentTypeId(int, optional) — filter by document typeisComplete(bool, optional) — filter by completion statusorderDate(yyyy-MM-dd, optional) — filter by exact order date; ignored whendateFrom/dateToare used
Query parameters (date window):
dateFrom(yyyy-MM-dd, optional) — start of date range, inclusivedateTo(yyyy-MM-dd, optional) — end of date range, inclusivedateProperty(string, default:"orderdate") — column to filter on:"orderdate"or"createdat"
Example — all documents for entity 5 in April 2026:
GET /api/v1/Documents?entityId=5&dateFrom=2026-04-01&dateTo=2026-04-30&dateProperty=orderdate&pageSize=0
Response:
PagedResponse<DocumentModel>
Authorization:
- Requires Bearer Token
- Permission:
OrdersRead
GET
/api/v1/Documents/{id}
Returns a single document by its numeric identifier, including all lines.
Route parameters:
id(long, required) — document identifier
Behavior:
- Returns
404if not found
Response:
DocumentModel(includesLineslist)
Authorization:
- Requires Bearer Token
- Permission:
OrdersRead
GET
/api/v1/Documents/ref/{orderNumber}/entity/{entityId}
Returns a document matching both order reference and entity ID.
Route parameters:
orderNumber(string, required) — order reference numberentityId(long, required) — entity identifier
Behavior:
- Returns
404if no match found
Response:
DocumentModel
Authorization:
- Requires Bearer Token
- Permission:
FullRead
GET
/api/v1/Documents/{id}/files
Returns a paginated list of file attachments linked to a document.
Route parameters:
id(long, required) — document identifier
Query parameters: see FileFilterRequest (standard pagination + search)
Response:
PagedResponse<FileMetadataModel>
Authorization:
- Requires Bearer Token
POST
/api/v1/Documents
Creates a new document.
Request body (DocumentModel):
- See Document Model for full field reference
OrderNumber,EntityId,OrderDate,Currency,DocumentTypeId,GrandTotal >= 0are required
Behavior:
- Validation is handled in the service layer
- Successful creation writes an audit log entry
Response:
201 Created—DocumentModel
Authorization:
- Requires Bearer Token
- Permission:
OrdersWrite
POST
/api/v1/Documents/{documentId}/files/assign
Assigns one or more existing files to a document.
Route parameters:
documentId(long, required)
Request body (FileIdsRequest):
FileIds(List, required)
Response:
204 No Content
Authorization:
- Requires Bearer Token
- Permission:
FullManage
PUT
/api/v1/Documents/{id}
Updates an existing document.
Route parameters:
id(int, required) — document identifier
Request body (DocumentModel):
Idis set from the routeId > 0,EntityId > 0,DocumentTypeId > 0are required
Behavior:
- Updates all provided fields
- Successful update writes an audit log entry
Response:
200 OK—DocumentModel
Authorization:
- Requires Bearer Token
- Permission:
OrdersWrite
DELETE
/api/v1/Documents/{id}
Soft-deletes a document.
Route parameters:
id(long, required) — document identifier
Behavior:
- Sets
IsDeleted = trueandDeletedAtto current UTC time - Record is retained in the database
- Successful deletion writes an audit log entry
Response:
204 No Content
Authorization:
- Requires Bearer Token
- Permission:
FullManage
DELETE
/api/v1/Documents/{documentId}/files/remove
Removes one or more file associations from a document (does not delete the file itself).
Route parameters:
documentId(long, required)
Request body (FileIdsRequest):
FileIds(List, required)
Response:
204 No Content
Authorization:
- Requires Bearer Token
- Permission:
FullManage
Models
DocumentModel
Represents a document (sales order, credit note, quote, etc.).
Fields:
Id (type: long)— internal identifierOrderNumber (type: string?)— order reference numberEntityId (type: long?)— customer entity identifierUserId (type: long?)— user who created the documentStatusId (type: int?)— order statusOrderDate (type: DateTime?)— order creation dateCurrency (type: string?)— order currencyBillingDocumentAddressSnapshotId (type: long?)— FK to billing address snapshotShippingDocumentAddressSnapshotId (type: long?)— FK to shipping address snapshotPriceListId (type: long?)— price list appliedSubtotal (type: decimal?)— subtotal amountTaxTotal (type: decimal?)— tax totalShippingTotal (type: decimal?)— shipping totalGrandTotal (type: decimal?)— final totalNotes (type: string?)— order notesCreatedAt (type: DateTime?)— creation timestampDueDate (type: DateTime?)— payment due datePromotionId (type: int?)— applied promotionPaidDate (type: DateTime?)— payment dateCompletedDate (type: DateTime?)— completion dateDispatchDate (type: DateTime?)— dispatch/shipping dateCourier (type: string?)— courier nameCourierRef (type: string?)— courier reference numberDocumentTypeId (type: int?)— document type FKInProgressDate (type: DateTime?)— date moved to in-progressPurchaseOrderRef (type: string?)— customer PO referenceAdditionalRef (type: string?)— secondary referenceDocumentCategoryId (type: int?)— document category FKTags (type: string?)— comma-separated tagsDescription (type: string?)— document descriptionActionNotes (type: string?)— internal action notesOther1 (type: string?)— configurable field 1Other2 (type: string?)— configurable field 2Other3 (type: string?)— configurable field 3OtherNotes (type: string?)— additional notesLines (type: List<DocumentLineModel>?)— line items (populated on read, ordered byLineNumber)Status (type: OrderStatus?)— resolved status objectDocumentType (type: DocumentTypeModel?)— resolved document type objectEntity (type: EntityModel?)— resolved entity objectDocumentCategory (type: DocumentCategoryModel?)— resolved category objectBillingAddress (type: DocumentAddressSnapshotModel?)— immutable billing address snapshotShippingAddress (type: DocumentAddressSnapshotModel?)— immutable shipping address snapshot
Validation:
IsReadyToAdd()— requiresEntityId,OrderNumber,OrderDate,Currency,DocumentTypeId,GrandTotal >= 0IsReadyToUpdate()— requiresId > 0,EntityId > 0,DocumentTypeId > 0
DocumentLineModel
Represents a single line item within a document.
Fields:
Id (type: long?)— internal identifierDocumentId (type: long?)— parent documentLineNumber (type: int?)— line sequence numberProductId (type: long?)— product identifierProductVariantId (type: long?)— product variant identifierSku (type: string?)— product SKU at time of orderTitle (type: string?)— product title at time of orderDescription (type: string?)— line descriptionQuantity (type: decimal?)— quantity orderedUnitPrice (type: decimal?)— price per unitDefaultSalePrice (type: decimal?)— catalogue price before any overrideDiscountAmount (type: decimal?)— discount appliedTaxRate (type: decimal?)— tax rate appliedTaxAmount (type: decimal?)— tax amountLineTotal (type: decimal?)— line total after discounts and taxWarehouseId (type: long?)— warehouse the goods are allocated fromEntityUserId (type: long?)— user who created the lineNotes (type: string?)— additional notesQuantityFulfilled (type: decimal?)— fulfilled quantityQuantityReturned (type: decimal?)— returned quantityReturnedDate (type: DateTime?)— date of return
Validation:
IsReadyToAdd()— requiresDocumentId,LineNumber,ProductId,Quantity > 0,UnitPrice >= 0,LineTotal >= 0IsReadyToUpdate()— requiresId > 0,DocumentId > 0,ProductId > 0,Quantity >= 0,UnitPrice >= 0
DocumentAddressSnapshotModel
An immutable copy of an address stamped at the time the document was created (via cart convert or manual creation).
Fields:
Id (type: long)— internal identifierName (type: string?)— address name / companyLine1 (type: string?)— street address line 1Line2 (type: string?)— street address line 2City (type: string?)— cityStateRegion (type: string?)— state or regionPostalCode (type: string?)— postal/ZIP codeCountryCode (type: string?)— ISO country codePhone (type: string?)— phoneEmail (type: string?)— emailCreatedAt (type: DateTime?)— snapshot creation timestamp
Notes
- All operations are tenant-aware
- All state-changing operations are audited
pageSize=0returns onlytotalCountwith an emptyitemsarray — useful for count-only dashboard queries- Document lines are always returned ordered by
LineNumber, soft-deleted lines are excluded - Address snapshots are immutable — they do not reflect subsequent changes to the entity's address
- Internal errors are logged but not exposed to clients