Skip to content

Posting Service API

The Posting Service manages the transition of journal entries from PENDING to POSTED status, providing both automated and manual posting capabilities.

Overview

All transactions in Keshless start as PENDING journal entries. The Posting Service handles:

  • Single entry posting
  • Batch posting
  • Auto-posting based on validation period
  • Entry validation before posting
  • Review workflows for flagged entries

Service Methods

postEntry(journalId, options)

Post a single pending journal entry.

Parameters:

ParameterTypeRequiredDescription
journalIdstringYesThe journal entry ID (e.g., JE-000123)
options.postedBystringNoAdmin ID who posted
options.ipAddressstringNoIP address for audit
options.requestIdstringNoRequest ID for tracing
options.notesstringNoAdditional notes

Returns: JournalEntry

Validation:

  • Journal must exist
  • Status must be PENDING
  • Debits must equal credits (balanced)

Example:

typescript
const postedEntry = await postingService.postEntry('JE-000123', {
  postedBy: 'admin-456',
  notes: 'Approved after manual review'
});

autoPostPendingEntries(olderThanMinutes, options)

Automatically post pending entries older than specified time.

Parameters:

ParameterTypeDefaultDescription
olderThanMinutesnumber30Age threshold in minutes
options.maxEntriesnumberAllMaximum entries to process
options.dryRunbooleanfalsePreview without posting

Returns:

typescript
{
  processed: number;
  posted: number;
  failed: number;
  skipped: number;  // AML-flagged or unbalanced
  errors: Array<{ journalId: string; error: string }>;
}

Skip Conditions:

  • Entry is not balanced
  • AML status is FLAGGED or BLOCKED

Example:

typescript
// Auto-post entries older than 30 minutes (dry run)
const result = await postingService.autoPostPendingEntries(30, { dryRun: true });
console.log(`Would post ${result.posted} entries`);

// Execute auto-posting
const result = await postingService.autoPostPendingEntries(30);

batchPost(journalIds, options)

Post multiple pending entries in a batch.

Parameters:

ParameterTypeRequiredDescription
journalIdsstring[]YesArray of journal IDs
options.postedBystringNoAdmin ID
options.ipAddressstringNoIP address
options.stopOnErrorbooleanNoStop on first error

Returns:

typescript
{
  posted: number;
  failed: number;
  errors: Array<{ journalId: string; error: string }>;
}

getPendingEntries(options)

Get pending entries awaiting posting.

Parameters:

ParameterTypeDescription
options.entityIdstringFilter by user/vendor ID
options.entityTypestringUser or Vendor
options.olderThanMinutesnumberAge threshold
options.limitnumberMaximum results

Returns: JournalEntry[]


getPostingStats(startDate?, endDate?)

Get posting statistics for reporting.

Returns:

typescript
{
  totalPosted: number;
  totalPending: number;
  totalCancelled: number;
  totalReversed: number;
  averagePostingDelayMinutes: number;
  oldestPendingMinutes?: number;
}

validatePendingEntry(journalId)

Validate an entry before posting.

Returns:

typescript
{
  isValid: boolean;
  errors: string[];   // Blocking issues
  warnings: string[]; // Non-blocking concerns
}

Checks Performed:

  • Status is PENDING
  • Debits equal credits
  • AML status (blocked = error, flagged = warning)
  • Age check (>24 hours = warning)

cancelEntry(journalId, reason, options)

Cancel a pending entry.

Parameters:

ParameterTypeRequiredDescription
journalIdstringYesJournal ID
reasonstringYesCancellation reason
options.cancelledBystringNoAdmin ID
options.ipAddressstringNoIP address

reviewEntry(journalId, action, options)

Review and approve/reject pending entries (admin workflow).

Parameters:

ParameterTypeRequiredDescription
journalIdstringYesJournal ID
action'approve' | 'reject'YesReview decision
options.reviewedBystringYesAdmin ID
options.notesstringNoReview notes
options.reasonstringNoRejection reason
options.ipAddressstringNoIP address

getEntriesForReview(options)

Get entries requiring manual review.

Parameters:

ParameterTypeDescription
options.amlFlaggedbooleanOnly AML-flagged entries
options.highValuenumberAmount threshold (E)
options.limitnumberMaximum results

Workflow Diagrams

Standard Posting Flow

Transaction Created


  PENDING Status

        ├─── Auto-post (after 30 min)
        │           │
        ▼           ▼
 Manual Review ──► POSTED

        └─── Reject


          CANCELLED

AML-Flagged Entry Flow

Transaction Created


  PENDING + AML FLAGGED


 Manual Review Required

        ├─── Approve (after investigation)
        │           │
        ▼           ▼
   POSTED with notes

        └─── Reject (suspicious)


          CANCELLED + SAR filed

Best Practices

  1. Always validate before posting:

    typescript
    const validation = await postingService.validatePendingEntry(journalId);
    if (!validation.isValid) {
      console.error('Cannot post:', validation.errors);
    }
  2. Use dry-run for auto-posting:

    typescript
    // Preview first
    await postingService.autoPostPendingEntries(30, { dryRun: true });
    // Then execute
    await postingService.autoPostPendingEntries(30);
  3. Monitor posting stats:

    typescript
    const stats = await postingService.getPostingStats();
    if (stats.oldestPendingMinutes > 60) {
      console.warn('Entries stuck in pending');
    }

Internal use only - Keshless Payment Platform