<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://your-app.azurestaticapps.net/blog</id>
    <title>Knowledge Base Blog</title>
    <updated>2026-08-31T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://your-app.azurestaticapps.net/blog"/>
    <subtitle>Knowledge Base Blog</subtitle>
    <icon>https://your-app.azurestaticapps.net/img/favicon.png</icon>
    <entry>
        <title type="html"><![CDATA[August 2026]]></title>
        <id>https://your-app.azurestaticapps.net/blog/august-2026</id>
        <link href="https://your-app.azurestaticapps.net/blog/august-2026"/>
        <updated>2026-08-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Associated entities let one business pay employees under several ABNs, and the Beam participant sync endpoint reads from Beam instead of restarting registration.]]></summary>
        <content type="html"><![CDATA[<p>Associated entities let one business pay employees under several ABNs, and the Beam participant sync endpoint reads from Beam instead of restarting registration.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="added">Added<a href="https://your-app.azurestaticapps.net/blog/august-2026#added" class="hash-link" aria-label="Direct link to Added" title="Direct link to Added" translate="no">​</a></h2>
<ul>
<li class="">Associated entities: a business can hold several ABN entities under one umbrella and share employees across them. CRUD and logo management under <code>/api/businesses/{businessId}/associated-entities</code>, with <code>associatedentity:read</code>, <code>associatedentity:write</code> and <code>associatedentity:delete</code> scopes, gated on an <code>AssociatedEntities</code> feature flag enabled per tenant. An employee is assigned an entity through their pay run settings.</li>
<li class="">Payslips resolve branding per entity. An employee paid under an associated entity gets that entity's business block and logo, with no fallback to the parent business logo.</li>
<li class="">STP pay events partition by associated entity. One pay run produces one lodgement per entity, and document identifiers are partition agnostic.</li>
<li class="">Beam super contributions split into one employer block per associated entity, grouped by effective ABN. Member verification requests carry the entity's ABN, and <code>GET /api/businesses/{businessId}/beam-participant/employers</code> returns per-entity registration status.</li>
<li class="">Beam validation items carry the entity name and the resolved employer, fund or payment they refer to, on both validate and submit failure paths.</li>
<li class="">A nightly Beam health check reports drift between the local business setup and Beam as a per-business notification. Findings are fingerprinted by code, so a dismissed notification stays dismissed while the same problem persists.</li>
<li class=""><code>POST /api/businesses/{businessId}/teams/{memberId}</code> adds an existing user to a business, requiring <code>team:write</code>.</li>
<li class=""><code>POST /api/businesses/{businessId}/transfer</code> transfers business ownership, requiring <code>businessdetails:write</code>. Only the current owner can transfer, and the incoming owner receives the owner scope preset while keeping their existing scopes.</li>
<li class=""><code>GET /api/businesses/{businessId}/pay-runs/{payRunId}/bank-payments/search</code> and <code>GET /api/businesses/{businessId}/pay-runs/{payRunId}/super-payments/search</code> return the bank and super payments for a pay run, requiring <code>payrun:read</code>.</li>
<li class=""><code>GET /api/businesses/{businessId}/employees/{employeeId}/payslips</code> and <code>GET /api/businesses/{businessId}/employees/{employeeId}/payslips/{payRunId}/download</code> give a business-scoped view and download of an employee's payslips, requiring <code>payrun:read</code>.</li>
<li class=""><code>GET /api/businesses/{businessId}/employees/{employeeId}/employee-portal-access/eligibility</code> reports whether an employee can be granted portal access, requiring <code>employeeuser:read</code>.</li>
<li class="">Pay type definition levels: CRUD under <code>/api/businesses/{businessId}/pay-type-definitions/{payTypeDefinitionId}/levels</code>, using the <code>paytypedefinition</code> scopes and behind the <code>PayTypeDefinitions</code> feature flag.</li>
<li class="">Advanced search accepts null literals, so <code>IS NULL</code> and <code>IS NOT NULL</code> filters work across search endpoints.</li>
<li class=""><code>DaysPerWeek</code> on employee pay run settings.</li>
<li class="">Super contributions and pay event lodgements can be deleted from the Paysense UI when their status permits, gated on <code>supercontribution:delete</code> and <code>stp:write</code>.</li>
<li class="">Payment batch rows show the pay run they came from and link through to it.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="changed">Changed<a href="https://your-app.azurestaticapps.net/blog/august-2026#changed" class="hash-link" aria-label="Direct link to Changed" title="Direct link to Changed" translate="no">​</a></h2>
<ul>
<li class="">The Beam participant endpoints were reworked. <code>POST /api/businesses/{businessId}/beam-participant/sync</code> previously duplicated <code>register</code>, re-running Beam hosted registration and returning a hosted UI token without updating local records, despite its name. It reads Beam and overwrites the local default super fund and bank accounts according to <code>SyncDefaultFund</code> and <code>SyncBankAccounts</code> flags in a request body, where it previously took only a redirect URL. The re-registration behaviour moved unchanged to <code>POST /api/businesses/{businessId}/beam-participant/re-register</code>. <code>GET /api/businesses/{businessId}/beam-participant</code> returns a different payload: Beam's record as at the request, the status this system last stored, and a <code>differences</code> block describing what a sync would change, each block carrying its own timestamp. An unregistered business returns 200 with a single <code>BeamNotRegistered</code> finding.</li>
<li class=""><code>ContactName</code> was split into <code>ContactFirstName</code> and <code>ContactSurname</code> on business create, business details update, the business details response, and employee bulk import. Both are required and capped at 100 characters. The old field has been dropped, so requests still sending <code>ContactName</code> fail validation.</li>
<li class="">Scope enforcement was tightened across pay runs and configuration. Pay run employee and totals endpoints require <code>payrun:read</code> to read, <code>payrun:write</code> to write, and <code>payrun:recalculate</code> and <code>payrun:regenerate</code> for those actions, so a token that reached them without those scopes receives 403. Chart of accounts configuration and bank account deletion are also gated on the caller's scopes.</li>
<li class=""><code>POST /api/businesses/{businessId}/stp/pay-event-lodgements</code> returns a <code>lodgements</code> array in place of a flat <code>Id</code> and <code>Name</code>. A pay run spanning associated entities creates one lodgement per entity, and each item carries that entity's id, name and registration number.</li>
<li class=""><code>GET /api/configuration/app-version</code> returns thresholds per platform under <code>Ios</code> and <code>Android</code> rather than a single <code>CurrentVersion</code> and <code>MinimumVersion</code> pair. The two builds are reviewed and published independently and can diverge.</li>
<li class="">Employee pay definition routes carry the pay type definition level. Search moved from <code>/api/businesses/{businessId}/employee-pay-definitions/{payTypeDefinitionId}/search</code> to <code>/api/businesses/{businessId}/employee-pay-definitions/{payTypeDefinitionId}/level/{payTypeDefinitionLevelId}/search</code>, and get, put, patch and delete moved from <code>/api/businesses/{businessId}/employee-pay-definitions/{payTypeDefinitionId}/{businessPayTypeId}</code> to <code>/api/businesses/{businessId}/employee-pay-definitions/{payTypeDefinitionId}/level/{payTypeDefinitionLevelId}/{businessPayTypeId}</code>. The old paths are gone. These endpoints sit behind the <code>PayTypeDefinitions</code> feature flag.</li>
<li class="">The published surface matches what a tenant can call. The OpenAPI specification omits endpoints whose feature flag is off, and <code>GET /api/admin/scopes</code> returns only business-assignable scopes, excluding those for features the tenant has not enabled. It previously returned every defined scope.</li>
<li class="">Logo upload is documented as it behaves. Business and associated entity logo uploads take <code>multipart/form-data</code>, accept PNG and JPG up to 5MB, and reject SVG. The specification previously claimed SVG support. The returned <code>LogoUrl</code> is served from <code>/api/public/businesses/assets/{blobId}.{extension}</code>.</li>
<li class="">Bank and super payment searches exclude zero-value payments, and the composite employee and member account objects were replaced with flat fields including <code>MemberAccountId</code> and <code>MemberNumber</code>.</li>
<li class="">Employee pay rates are normalised to an hourly rate when saved, and the rate as entered is returned unchanged.</li>
<li class="">A pay run assigned to an associated entity cannot be finalised unless ATO settings report as Intermediary or Tax Agent. Businesses lodging as an intermediary without a registered agent number still produce schema-valid pay events.</li>
<li class="">Super and bank payment splitting rounds each allocation to cents, away from zero, and applies a correction to the final allocation so the parts sum to the total.</li>
<li class="">Employee portal activation emails link to a portal-specific redirect, which offers the MyPaysense (Beta) download for iOS and Android.</li>
<li class="">Audit log search covers associated entity and pay type definition level actions.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="fixed">Fixed<a href="https://your-app.azurestaticapps.net/blog/august-2026#fixed" class="hash-link" aria-label="Direct link to Fixed" title="Direct link to Fixed" translate="no">​</a></h2>
<ul>
<li class="">Under-18 employees on a daily rate accrued no super. The 30-hour weekly eligibility gate counted rate units rather than hours, so a daily-rate employee working 38 hours across 5 days registered as 5 units and never cleared the threshold. Under ATO guidance an employee under 18 is entitled to super guarantee for any week they work more than 30 hours, regardless of what they earn.</li>
<li class="">Super contribution payments were dropped from the Beam payload while the contribution was still marked Submitted. Submission fails fast when the payload loses payments.</li>
<li class="">Payments marked Excluded were still validated, so an excluded payment could block a contribution.</li>
<li class="">Beam validation errors were matched to their subject by ordinal position, so a message could attach to the wrong employer, fund or payment. Errors are resolved through a context index built with the payload.</li>
<li class="">Date-only fields on pay run create and update shifted back a day. They serialise as local <code>yyyy-MM-dd</code>.</li>
<li class="">Pay run employee metadata returned rates without converting them to the pay type's rate unit.</li>
<li class="">Pay type, employee pay type and pay type level search returned no results. Advanced search also attempted to process non-string properties.</li>
<li class="">Nullable enums resolved incorrectly in the OpenAPI schema, including on <code>UpdateEmployeeTaxDetailsRequest</code>.</li>
<li class="">Recurring pay run actions mishandled amount-only leave entries and returned the wrong pay type name.</li>
<li class="">MyPaysense (Beta): the refresh token was discarded on first login when biometrics were enabled immediately afterwards.</li>
</ul>]]></content>
        <author>
            <name>Paysense</name>
            <uri>https://paysense.com.au</uri>
        </author>
        <category label="Release" term="Release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[July 2026]]></title>
        <id>https://your-app.azurestaticapps.net/blog/july-2026</id>
        <link href="https://your-app.azurestaticapps.net/blog/july-2026"/>
        <updated>2026-07-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Payroll API route segments moved to kebab-case plural nouns, so client paths change.]]></summary>
        <content type="html"><![CDATA[<p>Payroll API route segments moved to kebab-case plural nouns, so client paths change.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="added">Added<a href="https://your-app.azurestaticapps.net/blog/july-2026#added" class="hash-link" aria-label="Direct link to Added" title="Direct link to Added" translate="no">​</a></h2>
<ul>
<li class="">Penny, an assistant in the Paysense UI, shipped as a first version behind a <code>AiAssistant</code> feature flag that is off by default. Chat runs over a SignalR hub at <code>/chat</code>. The tool catalogue is generated from the payroll OpenAPI specification, so it tracks the API surface, and every tool dispatch is gated on the calling user's scopes. Conversations persist and resume, reads of personal information are audited and rate limited, tax file numbers are not decrypted for assistant reads, and actions that write require an explicit confirmation step. Model requests are served from an Australian Azure AI Foundry endpoint.</li>
<li class="">Opening suggestions for Penny. An empty thread shows scope-filtered suggestion chips drawn from the current page, unreviewed notifications and a cross-business notification scan, capped in number, with a template greeting when the model is unavailable. Follow-up suggestions are offered after a turn.</li>
<li class="">Leave type definitions: group leave types into reusable named templates and tag them onto an employee's pay run settings. CRUD under <code>/api/businesses/{businessId}/leave-type-definitions</code>, with <code>leavetypedefinition:read</code>, <code>leavetypedefinition:write</code> and <code>leavetypedefinition:delete</code> scopes. Business leave type create, update and search accept an optional <code>LeaveTypeDefinitionId</code>, and employee pay run settings read and write it.</li>
<li class="">Business-scoped and employee-scoped notification endpoints: <code>/api/businesses/{businessId}/notifications/search</code> and <code>/api/businesses/{businessId}/employees/{employeeId}/notifications/search</code>, with matching <code>/reviewed</code> and <code>/ignore</code> writes.</li>
<li class="">Employee work patterns.</li>
<li class="">Employee portal self service for bank account and super fund details, at <code>/api/employees/{employeeId}/bank-accounts</code> and <code>/api/employees/{employeeId}/super-funds</code>.</li>
<li class="">Leave request forecast at <code>/api/businesses/{businessId}/employees/{employeeId}/leave-requests/forecast</code>, returning calculated leave units for a leave type and date range.</li>
<li class=""><code>GET /api/configuration/app-version</code>, an anonymous endpoint returning the current and minimum supported mobile app versions. MyPaysense (Beta) blocks below the minimum and offers an update above it.</li>
<li class="">Reports overview page in the Paysense UI, grouping payroll, tax and compliance reports with tab filtering by category.</li>
<li class="">MyPaysense (Beta): Upcoming and Previous tabs on the leave screen, leave balances moved into a bottom sheet, and leave units populated from the forecast endpoint as the leave type and dates are picked.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="changed">Changed<a href="https://your-app.azurestaticapps.net/blog/july-2026#changed" class="hash-link" aria-label="Direct link to Changed" title="Direct link to Changed" translate="no">​</a></h2>
<ul>
<li class="">Payroll API route segments are now kebab-case and plural. Renamed concepts include <code>businesses</code>, <code>employees</code>, <code>pay-runs</code>, <code>pay-event-lodgements</code>, <code>leave-requests</code>, <code>leave-types</code>, <code>leave-type-definitions</code>, <code>pay-types</code>, <code>pay-type-definitions</code>, <code>payslips</code>, <code>public-holidays</code>, <code>super-funds</code>, <code>timesheets</code>, <code>timesheet-records</code>, <code>timesheet-category-mappings</code>, <code>employee-pay-definitions</code> and <code>employee-pay-types</code>. The singleton resources <code>chart-of-accounts</code> and <code>beam-participant</code> are unchanged. Old paths are not aliased.</li>
<li class="">Notification search and update are scoped to the caller's business memberships. Calls that previously returned tenant-wide notifications return only accessible records, <code>TotalCount</code> counts distinct notifications rather than association rows, and fetching an inaccessible notification by id returns 404.</li>
<li class="">Tenant-level scopes are rejected when assigning business-level scopes, and user invites require an explicit non-empty scope list.</li>
<li class="">Pay run type <code>Initial</code> is rejected on pay run create and update. It is set by the system only.</li>
<li class="">Employee portal access can only be granted or reactivated for fully onboarded employees. Employees in Onboarding status are rejected, and portal access responses include <code>EmployeeStatus</code>.</li>
<li class="">Pay type definition endpoints sit behind a <code>PayTypeDefinitions</code> feature flag, off by default. The pay type definition, employee pay definition and apply pay type definition endpoints return 404 when the flag is off. Default pay types are unaffected.</li>
<li class="">Beam participant calls are recorded in the audit log.</li>
<li class="">Owner scopes are immutable, and re-inviting an existing user is rejected.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="fixed">Fixed<a href="https://your-app.azurestaticapps.net/blog/july-2026#fixed" class="hash-link" aria-label="Direct link to Fixed" title="Direct link to Fixed" translate="no">​</a></h2>
<ul>
<li class="">The payroll journal did not balance. Post-tax deductions were credited without a matching debit, so credits exceeded debits by the total deduction amount. This also blocked Xero import.</li>
<li class="">Super contribution payments stayed in Sending or Submitted when Beam returned a refund, error, cancelled, dishonoured or missing payment response. Failing payments are matched by clearing house identifier and marked Failed with the returned message, and per-payment status is shown in the payments grid.</li>
<li class="">Super fund sync attempted to delete funds still attached to employees.</li>
<li class="">Member verification notifications rendered an empty severity chip because the payload carried <code>Type</code> where the client expected <code>SeverityCode</code>. Historical notifications have been migrated.</li>
<li class="">The MessageXchange client retried non-idempotent HTTP writes, which could duplicate submissions.</li>
<li class="">Payslips showed an hourly rate label for employees paid an annual rate.</li>
<li class="">Payslips omitted the CASH/CHEQUE payment method for cash payments.</li>
<li class="">Pay run settings, the new employee wizard, opening balances and timesheet category mappings returned 404 on pay type and leave type definition lookups when those feature flags were off.</li>
<li class="">The new employee wizard had no pay type definition selector, and pay type search for the selected definition errored.</li>
<li class="">Advanced search treated quoted strings as operator syntax.</li>
<li class="">The business switcher could drift from the business in the route, leaving the switcher, scopes, breadcrumbs and dashboard reading a stale selection.</li>
<li class="">Timesheet earnings mode was editable on employee pay run settings while the Timesheets feature was disabled, allowing a mode the employee could not use.</li>
<li class="">The chart of accounts add account modal failed to submit.</li>
<li class="">Tenant branding fell back to the Paysense default when the first branding request after a cold start timed out.</li>
<li class="">Deep linking or refreshing directly onto a list page's create or edit modal route redirected to the list without opening the modal.</li>
<li class="">MyPaysense (Beta): submitted timesheet entries appeared on the following day. Timesheet and leave timestamps are stored as wall clock time, but several responses and one mobile form path treated them as UTC.</li>
<li class="">MyPaysense (Beta): leave requests overlapping a Declined request were rejected. Processing, Imported and Finalised requests still block.</li>
<li class="">MyPaysense (Beta): the app crashed on a malformed employee context response. A recovery screen is shown instead.</li>
<li class="">MyPaysense (Beta): the dashboard Log hours action reached the timesheet screen while the Timesheets feature was disabled.</li>
</ul>]]></content>
        <author>
            <name>Paysense</name>
            <uri>https://paysense.com.au</uri>
        </author>
        <category label="Release" term="Release"/>
    </entry>
</feed>