This guide explains how business users can send StockSmart sales and purchasing transactions to a PennyPipe account.
What can be synced
You can sync these transaction types:
-
Sales
-
Sales documents
-
Customer payments
-
-
Purchasing
-
Purchase documents
-
Supplier payments
-
Each sync route sends entries to one specific PennyPipe account.
Before you start
Please confirm:
-
You have access to the PennyPipe integration page in StockSmart.
-
You know the target PennyPipe Account ID.
-
You have valid authentication details for PennyPipe (OAuth credentials or a PAT token).
-
Your PennyPipe user/client is allowed to post ledger entries to that account.
-
If using OAuth, your PennyPipe account must allowlist your OAuth client for integration ledger posting (your implementation/support team can help if you see
403).
Step 1: Open PennyPipe integration
In StockSmart, open:
-
Platform -> PennyPipe
Step 2: Create a connection
In OAuth/PAT connections, click Save connection after filling the fields.
Common fields:
-
Label
-
PennyPipe API Base URL (provided by your implementation/support team)
-
Auth Type (
OAuthorPAT)
If using OAuth:
-
Identity Authority
-
Client ID
-
Client Secret
-
Scopes
If using PAT:
-
Personal Access Token
Tip: Give the connection a clear label such as Main Finance Account.
Step 3: Add a stream route
In Stream routes, create one route per target account and business flow.
Required choices:
-
Connection
-
Stream type (
SalesorPurchasing) -
PennyPipe Account ID
-
Enabled = checked
You can maintain separate routes for:
-
Sales -> Account A
-
Purchasing -> Account B
Step 4: Configure rules
Each route has rules for document and payment events.
For each enabled rule, set:
-
EntryType(creditordebit) -
optional
TagNamesandCreateMissingTags -
optional
NoteTemplate -
optional
ReferenceIdSourceProperty(recommended; see below) -
optional
CustomFieldValueMaps(ledger custom fields; see below)
Example note templates
-
Sale #{ReceiptNumber} total {Total} -
Customer payment {Payment} for {CustomerDetails} -
Purchase #{ReceiptNumber} total {Total} -
Supplier payment {Payment} to {SupplierDetails}
Mapping JSON examples (with explanation)
Use route rules JSON to control what StockSmart sends to PennyPipe for each event type. If your users are not editing JSON directly, your implementation/support team can paste these templates for you.
JSON key casing
-
Preferred JSON uses PascalCase keys (example:
SalePayment,CustomFieldValueMaps,FieldDefinitionId). -
The route editor accepts both PascalCase and camelCase when applying JSON, then normalizes it in the editor.
A) Sales mapping example
{
"SaleDocument": {
"Enabled": true,
"EntryType": "credit",
"TagNames": ["Sales", "Retail"],
"CreateMissingTags": true,
"ReferenceIdSourceProperty": "Id",
"NoteTemplate": "Sale #{ReceiptNumber} | Customer: {CustomerDetails} | Total: {Total}",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "11111111-1111-1111-1111-111111111111",
"SourceProperty": "ReceiptNumber"
},
{
"FieldDefinitionId": "22222222-2222-2222-2222-222222222222",
"SourceProperty": "Notes"
}
]
},
"SalePayment": {
"Enabled": true,
"EntryType": "credit",
"TagNames": ["Customer payments"],
"CreateMissingTags": true,
"ReferenceIdSourceProperty": "Id",
"NoteTemplate": "Payment #{ReceiptNumber} | Paid: {Payment} | Customer: {CustomerDetails}",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "33333333-3333-3333-3333-333333333333",
"SourceProperty": "Payment"
},
{
"FieldDefinitionId": "44444444-4444-4444-4444-444444444444",
"SourceProperty": "BankAccountName"
}
]
}
}
B) Purchasing mapping example
{
"PurchaseDocument": {
"Enabled": true,
"EntryType": "debit",
"TagNames": ["Purchases", "Suppliers"],
"CreateMissingTags": true,
"ReferenceIdSourceProperty": "Id",
"NoteTemplate": "Purchase #{ReceiptNumber} | Supplier: {SupplierDetails} | Total: {Total}",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "55555555-5555-5555-5555-555555555555",
"SourceProperty": "ReceiptNumber"
},
{
"FieldDefinitionId": "66666666-6666-6666-6666-666666666666",
"SourceProperty": "Notes"
}
]
},
"SupplierPayment": {
"Enabled": true,
"EntryType": "debit",
"TagNames": ["Supplier payments"],
"CreateMissingTags": true,
"ReferenceIdSourceProperty": "Id",
"NoteTemplate": "Supplier payment #{ReceiptNumber} | Paid: {Payment} | Supplier: {SupplierDetails}",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "77777777-7777-7777-7777-777777777777",
"SourceProperty": "Payment"
},
{
"FieldDefinitionId": "88888888-8888-8888-8888-888888888888",
"SourceProperty": "BankAccountName"
}
]
}
}
What each mapping field means
-
Enabled: turns that event mapping on/off. -
EntryType:creditordebitin PennyPipe. -
TagNames: tags added to the ledger entry. -
CreateMissingTags: iftrue, missing tags are created automatically. -
NoteTemplate: builds the note text using placeholders from StockSmart values. -
CustomFieldValueMaps: maps StockSmart values to PennyPipe custom fields (extra fields). -
ReferenceIdSourceProperty: optional source property used for PennyPipeentry.referenceId(account-scoped upsert key).
About note templates
NoteTemplate is optional but recommended for traceability.
Placeholders are case-insensitive and can reference any public property on the underlying entity for that event (for example {ReceiptNumber}, {Total}, {Payment}, {Notes}, {CustomerDetails}, {SupplierDetails}, {Id}).
If a placeholder value is empty, that part appears blank in the final note.
About extra fields (CustomFieldValueMaps)
Each item in CustomFieldValueMaps connects:
-
FieldDefinitionId: the PennyPipe custom field ID -
SourceProperty: the StockSmart value to send into that field (case-insensitive public property name for that event)
Example:
-
Map PennyPipe field Invoice Ref to
ReceiptNumber -
Map PennyPipe field Internal Note to
Notes -
Map PennyPipe field Paid Amount to
Payment
Tip: Copy FieldDefinitionId from the PennyPipe field list in the integration screen.
About ledger referenceId upserts
-
PennyPipe supports
entry.referenceIdfor account-level upserts (same account + same referenceId = update instead of insert, when supported by PennyPipe). -
StockSmart can send
referenceIdautomatically (enabled by default). In rules, setReferenceIdSourcePropertyper event to control which StockSmart property becomesreferenceId. -
Default is
Id(stable GUID from the StockSmart entity), which is recommended for deterministic re-runs/backfills. -
Keep this value stable over time. Avoid random suffixes.
-
Important: Sale documents may be skipped if a usable
referenceIdcan’t be resolved (to prevent duplicates during migrations/backfills). UsingReferenceIdSourceProperty: "Id"is the safest choice.
Custom field mapping: practical patterns
Below are common business patterns customers usually configure.
Pattern 1: Reference and remarks on sales documents
Goal: keep invoice reference and notes in PennyPipe custom fields.
{
"SaleDocument": {
"Enabled": true,
"EntryType": "credit",
"ReferenceIdSourceProperty": "Id",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "a1111111-1111-1111-1111-111111111111",
"SourceProperty": "ReceiptNumber"
},
{
"FieldDefinitionId": "a2222222-2222-2222-2222-222222222222",
"SourceProperty": "Notes"
}
]
}
}
Pattern 2: Payment-focused mapping
Goal: record paid amount and payment context for customer payments.
{
"SalePayment": {
"Enabled": true,
"EntryType": "credit",
"ReferenceIdSourceProperty": "Id",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "b1111111-1111-1111-1111-111111111111",
"SourceProperty": "Payment"
},
{
"FieldDefinitionId": "b2222222-2222-2222-2222-222222222222",
"SourceProperty": "BankAccountName"
},
{
"FieldDefinitionId": "b3333333-3333-3333-3333-333333333333",
"SourceProperty": "ReceiptNumber"
}
]
}
}
Pattern 3: Supplier-side mapping for purchasing
Goal: mirror supplier reference and comments for purchase-side entries.
{
"PurchaseDocument": {
"Enabled": true,
"EntryType": "debit",
"ReferenceIdSourceProperty": "Id",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "c1111111-1111-1111-1111-111111111111",
"SourceProperty": "ReceiptNumber"
},
{
"FieldDefinitionId": "c2222222-2222-2222-2222-222222222222",
"SourceProperty": "Notes"
}
]
},
"SupplierPayment": {
"Enabled": true,
"EntryType": "debit",
"ReferenceIdSourceProperty": "Id",
"CustomFieldValueMaps": [
{
"FieldDefinitionId": "c3333333-3333-3333-3333-333333333333",
"SourceProperty": "Payment"
},
{
"FieldDefinitionId": "c4444444-4444-4444-4444-444444444444",
"SourceProperty": "BankAccountName"
}
]
}
}
Recommended rollout method for custom fields
-
Start with one event only (for example
SaleDocument). -
Add 1-2 custom fields first (such as
ReceiptNumber,Notes). -
Run a test post and verify values in PennyPipe.
-
Expand mapping to payment events after validation.
Common mapping mistakes to avoid
-
Using a field ID from the wrong PennyPipe account.
-
Mapping payment rules with irrelevant values.
-
Changing many mappings at once and making troubleshooting hard.
-
Leaving old/unused custom fields in the route JSON.
-
Expecting null/blank StockSmart properties to be sent to PennyPipe custom fields (null values are omitted).
Step 5: (Optional) Map custom PennyPipe fields
If you use custom ledger fields in PennyPipe:
-
Load ledger fields in the integration page.
-
Add
CustomFieldValueMapsinside the relevant event rule (for exampleSalePaymentorSupplierPayment). -
Save the route.
Common values used in mapping:
-
ReceiptNumber -
Payment -
Total -
Notes -
CustomerDetails -
SupplierDetails
Step 6: Run a test post
In Test & field definitions:
-
Select the connection.
-
Enter the account ID.
-
Enter a small amount (for example
0.01). -
Click Test post.
If test is successful, you can go live.
Step 7: Go live and validate
Approve a real transaction in StockSmart and verify the ledger entry appears in PennyPipe with:
-
expected amount
-
expected credit/debit direction
-
expected tags
-
expected note/custom fields
Common issues and fixes
Test post says 403 (access denied)
This usually means the token/client does not have permission on that PennyPipe account.
Check:
-
correct account ID
-
correct connection selected
-
token/client has ledger post permission in PennyPipe
Test post fails with authentication errors
Check:
-
OAuth/PAT credentials are correct
-
token is active and not expired/revoked
-
PennyPipe API base URL is correct
Nothing appears in PennyPipe after approval
Check:
-
route is enabled
-
correct stream type (Sales vs Purchasing)
-
correct PennyPipe account on route
-
related event rule is enabled (document/payment)
Best practices
-
Create separate connections for test and production.
-
Use clear labels for each connection and route.
-
Keep token/client credentials secure and rotate regularly.
-
Start with a small test amount before full rollout.
Quick go-live checklist
-
Connection saved successfully
-
Route created for each required stream/account
-
Rules configured and enabled
-
Test post succeeded
-
Live transaction verified in PennyPipe
Payment troubleshooting
-
For purchase invoice payments, verify the route
StreamTypeis Purchasing and ruleSupplierPayment.Enabledistrue. -
If custom field values are empty in PennyPipe, re-check both
FieldDefinitionId(correct account) andSourcePropertynames, and confirm the underlying StockSmart property has a non-empty value for that transaction.