انتقل إلى المحتوى الرئيسي

General journals

Overview

The General Ledger Journals API provides comprehensive functionality for creating, managing, and posting financial journal entries with full support for multi-dimensional accounting structures. This API supports the complete journal lifecycle from draft creation through posting and reversal.

Base URL: /general-journals

Key Features

  • Multi-Dimensional Support: Full integration with financial dimensions for detailed classification
  • Interactive Dimension Resolution: Smart account structure detection based on MainAccount
  • Journal Lifecycle Management: Draft → Post → Reverse workflow
  • Multiple Journal Types: Daily, Customer Payment, Vendor Payment, Payroll
  • Fiscal Period Validation: Automatic validation against open periods
  • Currency Support: Multi-currency transaction handling

Core Endpoints

1. Create Journal

Creates a new ledger journal with transactions supporting financial dimensions.

POST /general-journals
Content-Type: application/json

Request Body:

{
"ledger_journal_name_id": "a1b2c3d4-e5f6-7a8b-9c0d-e1f2a3b4c5d6",
"currency_code": "AED",
"transactions": [
{
"voucher": "VOUCHER-2025-001",
"description": "Office supplies purchase",
"debit_amount": 1500.00,
"credit_amount": 0.00,
"currency_code": "AED",
"transaction_date": "2025-03-15T10:00:00.000Z",
"dimension_segments": [
{
"dimension_attribute_id": "00000000-0000-0000-0000-000000000001",
"value": "1100"
},
{
"dimension_attribute_id": "b2c3d4e5-f6a7-8901-2345-678901bcdef0",
"value": "ADMIN"
}
],
"offset_account_id": "9d3e3fa2-4717-4461-7511-5747365e5f67"
}
]
}

Response:

{
"id": "12345678-1234-1234-1234-123456789012",
"document_number": "GJ-2025-001",
"status": "Draft",
"created_date": "2025-03-15T10:00:00.000Z"
}

Status Codes:

  • 200 OK - Journal created successfully
  • 400 Bad Request - Invalid data or validation errors
  • 500 Internal Server Error - Fiscal period closed or other server errors

2. Get Journal by ID

Retrieves a specific journal with all transaction details and dimension information.

GET /general-journals/{journalId}
Accept: application/json

Response:

{
"id": "12345678-1234-1234-1234-123456789012",
"document_number": "GJ-2025-001",
"name": "Daily Operations Journal",
"currency_code": "AED",
"status": "Draft",
"total_debit_amount": 1500.00,
"total_credit_amount": 1500.00,
"created_date": "2025-03-15T10:00:00.000Z",
"transactions": [
{
"id": "87654321-4321-4321-4321-210987654321",
"voucher": "VOUCHER-2025-001",
"description": "Office supplies purchase",
"debit_amount": 1500.00,
"credit_amount": 0.00,
"currency_code": "AED",
"transaction_date": "2025-03-15T10:00:00.000Z",
"account_display": "1100-ADMIN (Assets - Administration)",
"dimension_combination_id": "aabbccdd-1122-3344-5566-778899aabbcc",
"dimension_segments": [
{
"dimension_attribute_name": "MainAccount",
"value": "1100",
"display_value": "Cash and Cash Equivalents"
},
{
"dimension_attribute_name": "Department",
"value": "ADMIN",
"display_value": "Administration"
}
]
}
]
}

Status Codes:

  • 200 OK - Journal found and returned
  • 404 Not Found - Journal with specified ID not found

3. Get All Journals

Retrieves all unposted journals with optional filtering and pagination.

GET /general-journals?status=Draft&take=50&skip=0
Accept: application/json

Query Parameters:

  • status (optional): Filter by journal status (Draft, Posted, Reversed)
  • take (optional): Number of records to return (default: 100)
  • skip (optional): Number of records to skip (default: 0)
  • date_from (optional): Filter by creation date (ISO 8601)
  • date_to (optional): Filter by creation date (ISO 8601)

Response:

[
{
"id": "12345678-1234-1234-1234-123456789012",
"document_number": "GJ-2025-001",
"name": "Daily Operations Journal",
"currency_code": "AED",
"status": "Draft",
"total_debit_amount": 1500.00,
"total_credit_amount": 1500.00,
"created_date": "2025-03-15T10:00:00.000Z"
}
]

4. Post Journal

Posts a journal entry, making it permanent and updating the general ledger.

PUT /general-journals/{journalId}/post
Content-Type: application/json

Response:

{
"success": true,
"posted_date": "2025-03-15T15:30:00.000Z",
"message": "Journal posted successfully"
}

Status Codes:

  • 200 OK - Journal posted successfully
  • 400 Bad Request - Journal cannot be posted (invalid state, closed period, etc.)
  • 404 Not Found - Journal not found

5. Reverse Journal

Reverses a posted journal entry by creating a new reversal journal.

PUT /general-journals/{journalId}/reverse
Content-Type: application/json

Request Body:

{
"reason": "Correcting accounting error in March entries",
"use_existing_dates": false,
"reversal_date": "2025-03-16T00:00:00.000Z"
}

Response:

{
"reversal_journal_id": "11111111-2222-3333-4444-555555555555",
"reversal_document_number": "GJ-2025-001-REV",
"message": "Journal reversed successfully"
}

Status Codes:

  • 200 OK - Journal reversed successfully
  • 400 Bad Request - Journal cannot be reversed (not posted, already reversed, etc.)
  • 404 Not Found - Journal not found

6. Create Draft Transaction

Adds a new draft transaction line to an existing journal.

POST /general-journals/{journalId}/transactions/draft
Content-Type: application/json

Request Body:

{
"description": "Additional office equipment",
"debit_amount": 800.00,
"credit_amount": 0.00,
"currency_code": "AED",
"transaction_date": "2025-03-15T12:00:00.000Z",
"dimension_segments": [
{
"dimension_attribute_id": "00000000-0000-0000-0000-000000000001",
"value": "1200"
},
{
"dimension_attribute_id": "b2c3d4e5-f6a7-8901-2345-678901bcdef0",
"value": "IT"
}
]
}

Response:

{
"id": "99999999-8888-7777-6666-555555555555",
"voucher": "AUTO-GENERATED-002",
"status": "Draft"
}

7. Get Posted Journals

Retrieves all successfully posted journals.

GET /general-journals/posted?take=50&skip=0
Accept: application/json

Response:

[
{
"id": "12345678-1234-1234-1234-123456789012",
"document_number": "GJ-2025-001",
"name": "Daily Operations Journal",
"currency_code": "AED",
"status": "Posted",
"posted_date": "2025-03-15T15:30:00.000Z",
"total_debit_amount": 1500.00,
"total_credit_amount": 1500.00,
"general_journal_entries": [
{
"account_display": "1100-ADMIN",
"debit_amount": 1500.00,
"credit_amount": 0.00
}
]
}
]

8. Get Journal Types

Retrieves available journal types for creating new journals.

GET /general-journals/journal-types
Accept: application/json

Response:

[
{
"id": 0,
"name": "Daily",
"purpose": "Create daily transactions in a general journal"
},
{
"id": 1,
"name": "Customer Payment",
"purpose": "Create customer payment transactions"
},
{
"id": 2,
"name": "Vendor Payment",
"purpose": "Create vendor disbursement transactions"
},
{
"id": 3,
"name": "Payroll Disbursement",
"purpose": "Create payroll disbursement transactions"
}
]

Dimension Support

Updated Transaction Structure

All journal transactions now support financial dimensions through the dimension_segments array:

{
"dimension_segments": [
{
"dimension_attribute_id": "00000000-0000-0000-0000-000000000001",
"value": "1100"
},
{
"dimension_attribute_id": "b2c3d4e5-f6a7-8901-2345-678901bcdef0",
"value": "SALES"
},
{
"dimension_attribute_id": "5a8e9e4e-0b0c-4c4c-8b8b-0a0a0a0a0a0a",
"value": "CC001"
}
]
}

Dimension Resolution Workflow

  1. User Entry: User enters MainAccount value (e.g., "1100")
  2. Structure Resolution: System resolves appropriate Account Structure
  3. UI Rendering: Frontend displays required dimension fields
  4. Value Creation: System creates dimension values on journal save
  5. Combination Creation: System creates immutable dimension combination
  6. Transaction Linking: Transaction linked to dimension combination

Integration with Resolve-and-Suggest-Segments

Before creating transactions, use the dimension combinations API to:

  • Resolve the correct account structure
  • Get required dimension fields for UI
  • Validate dimension values interactively

See Dimension Combinations API documentation for details.


Dimension Support

Updated Transaction Structure

All journal transactions now support financial dimensions through the dimension_segments array:

{
"dimension_segments": [
{
"dimension_attribute_id": "00000000-0000-0000-0000-000000000001",
"value": "1100"
},
{
"dimension_attribute_id": "b2c3d4e5-f6a7-8901-2345-678901bcdef0",
"value": "SALES"
},
{
"dimension_attribute_id": "5a8e9e4e-0b0c-4c4c-8b8b-0a0a0a0a0a0a",
"value": "CC001"
}
]
}

Dimension Resolution Workflow

  1. User Entry: User enters MainAccount value (e.g., "1100")
  2. Structure Resolution: System resolves appropriate Account Structure
  3. UI Rendering: Frontend displays required dimension fields
  4. Value Creation: System creates dimension values on journal save
  5. Combination Creation: System creates immutable dimension combination
  6. Transaction Linking: Transaction linked to dimension combination

Integration with Resolve-and-Suggest-Segments

Before creating transactions, use the dimension combinations API to:

  • Resolve the correct account structure
  • Get required dimension fields for UI
  • Validate dimension values interactively

See Dimension Combinations API documentation for details.


Complete Endpoint Reference

Journal Management

MethodEndpointPurpose
POST/general-journalsCreate new journal
GET/general-journals/{id}Get journal by ID
GET/general-journals/by-id/{id}Alternative get by ID
GET/general-journals/by-document/{docNumber}Get journal by document number
GET/general-journalsGet all journals (with filters)
PUT/general-journals/{id}Update journal
DELETE/general-journals/{id}Delete journal

Journal Lifecycle

MethodEndpointPurpose
PUT/general-journals/{id}/postPost journal
PUT/general-journals/{id}/reverseReverse posted journal
GET/general-journals/postedGet posted journals

Transaction Management

MethodEndpointPurpose
POST/general-journals/{id}/transactionsAdd transaction
POST/general-journals/{id}/transactions/draftCreate draft transaction
PUT/general-journals/{id}/transactions/{txnId}Update transaction
DELETE/general-journals/{id}/transactions/{txnId}Remove transaction
GET/general-journals/transactions/by-document/{doc}Get transactions by document

Reporting & Analytics

MethodEndpointPurpose
GET/general-journals/account-entriesGet all account entries
GET/general-journals/journal-typesGet available journal types

Specialized Journals

MethodEndpointPurpose
*/general-journals/customer-payments/*Customer payment operations
*/general-journals/vendor-payments/*Vendor payment operations

Error Handling

Common Error Responses

Fiscal Period Closed (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "The transaction date 2026-01-10 falls within a fiscal period that is not open."
}

Dimension Validation Error (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Validation Error",
"status": 400,
"detail": "Invalid dimension value 'INVALID_DEPT' for attribute 'Department'",
"errors": {
"dimension_segments[1].value": ["The value 'INVALID_DEPT' is not a valid Department"]
}
}

Journal Not Found (404 Not Found):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"detail": "Journal with ID '12345678-1234-1234-1234-123456789012' was not found."
}

Cannot Modify Posted Journal (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Business Rule Violation",
"status": 400,
"detail": "Cannot modify transactions on a posted journal. Use reversal instead."
}

Best Practices

1. Dimension Entry Workflow

// Step 1: User enters MainAccount
const mainAccount = "1100";

// Step 2: Call resolve-and-suggest-segments
const resolution = await resolveAndSuggestSegments({
ledger_id: ledgerId,
segment_inputs: [
{ dimension_attribute_id: mainAccountDimId, value: mainAccount }
]
});

// Step 3: Render required dimension fields
resolution.required_levels.forEach(level => {
if (level.is_mandatory) {
renderDimensionInput(level);
}
});

// Step 4: Create journal with complete dimensions
const journal = await createJournal({
transactions: [{
dimension_segments: completeDimensionSegments,
// ... other transaction data
}]
});

2. Transaction Management Best Practices

  • Draft First: Create transactions as drafts, then update with complete data
  • Validate Early: Use dimension resolution API before creating transactions
  • Batch Operations: Add multiple transactions before posting for better performance
  • Error Recovery: Implement proper error handling for fiscal period and dimension validation

3. Error Handling

  • Always validate fiscal periods before posting
  • Use dimension resolution API before creating transactions
  • Handle dimension validation errors gracefully
  • Provide clear error messages to users

4. Performance Optimization

  • Use pagination for large journal lists
  • Cache dimension attribute metadata
  • Validate dimensions interactively, not just on save
  • Batch multiple operations when possible

Testing

Complete Test Workflow

# 1. Create journal with dimensions
POST /general-journals
{
"ledger_journal_name_id": "...",
"currency_code": "AED",
"transactions": [{
"transaction_date": "2025-03-15",
"dimension_segments": [...],
...
}]
}

# 2. Add additional transaction
POST /general-journals/{id}/transactions
{
"description": "Second transaction",
"dimension_segments": [...],
...
}

# 3. Update transaction
PUT /general-journals/{id}/transactions/{txnId}
{
"description": "Updated transaction",
...
}

# 4. Post journal
PUT /general-journals/{id}/post

# 5. Verify posted status
GET /general-journals/{id}

# 6. Get account entries
GET /general-journals/account-entries?fromDate=2025-03-15

# 7. Reverse journal
PUT /general-journals/{id}/reverse
{ "reason": "Test reversal" }

# 8. Cleanup - delete draft journals
DELETE /general-journals/{draft-id}

# 9. Error scenarios
POST /general-journals
{
"transactions": [{ "transaction_date": "2026-01-15", ... }]
}
# Should fail with fiscal period error

Transaction-Level Testing

# Create draft transaction
POST /general-journals/{id}/transactions/draft

# Update with complete data
PUT /general-journals/{id}/transactions/{txnId}
{ "dimension_segments": [...], ... }

# Remove if needed
DELETE /general-journals/{id}/transactions/{txnId}

Common Error Responses

Fiscal Period Closed (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "The transaction date 2026-01-10 falls within a fiscal period that is not open."
}

Dimension Validation Error (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Validation Error",
"status": 400,
"detail": "Invalid dimension value 'INVALID_DEPT' for attribute 'Department'",
"errors": {
"dimension_segments[1].value": ["The value 'INVALID_DEPT' is not a valid Department"]
}
}

Journal Not Found (404 Not Found):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"detail": "Journal with ID '12345678-1234-1234-1234-123456789012' was not found."
}

Best Practices

1. Dimension Entry Workflow

// Step 1: User enters MainAccount
const mainAccount = "1100";

// Step 2: Call resolve-and-suggest-segments
const resolution = await resolveAndSuggestSegments({
ledger_id: ledgerId,
segment_inputs: [
{ dimension_attribute_id: mainAccountDimId, value: mainAccount }
]
});

// Step 3: Render required dimension fields
resolution.required_levels.forEach(level => {
if (level.is_mandatory) {
renderDimensionInput(level);
}
});

// Step 4: Create journal with complete dimensions
const journal = await createJournal({
transactions: [{
dimension_segments: completeDimensionSegments,
// ... other transaction data
}]
});

2. Error Handling

  • Always validate fiscal periods before posting
  • Use dimension resolution API before creating transactions
  • Handle dimension validation errors gracefully
  • Provide clear error messages to users

3. Performance Optimization

  • Use pagination for large journal lists
  • Cache dimension attribute metadata
  • Validate dimensions interactively, not just on save
  • Batch multiple operations when possible

Testing

Sample Test Workflow

# 1. Create journal (should succeed)
POST /general-journals
{
"ledger_journal_name_id": "...",
"currency_code": "AED",
"transactions": [{ "transaction_date": "2025-03-15", ... }]
}

# 2. Post journal (should succeed)
PUT /general-journals/{id}/post

# 3. Verify posted status
GET /general-journals/{id}

# 4. Reverse journal
PUT /general-journals/{id}/reverse
{ "reason": "Test reversal" }

# 5. Create journal with future date (should fail)
POST /general-journals
{
"transactions": [{ "transaction_date": "2026-01-15", ... }]
}