> For the complete documentation index, see [llms.txt](https://developers.share.inc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.share.inc/concepts/scheduled-jobs.md).

# Scheduled jobs

Plenty of what happens on the Share platform is driven not by an API call but by a scheduled job that runs on a fixed cadence: cycles renew, suspended subscriptions get caught up, in-flight payments are reconciled, Splynx is re-synced, RADIUS is re-checked. This page tells you what those jobs are, how often they run, and — most importantly — which ones cause state you can see (a webhook, a Splynx change, a RADIUS update) and which ones are internal bookkeeping you can ignore.

> All schedules are in **UTC** unless otherwise stated.

## How to use this page

Pick the section that matches what you're investigating. If you're asking *"why did this subscriber's status flip just now?"* check [Billing and subscription lifecycle](#billing-and-subscription-lifecycle). If you're asking *"why did my Splynx tariff just change?"* check [Splynx mirroring](#splynx-mirroring). If you're asking *"my payment landed, when will the webhook fire?"* check [Payments and reconciliation](#payments-and-reconciliation).

The full table at [the bottom](#full-schedule-reference), sorted by frequency, lists every partner-observable job in one place.

## Billing and subscription lifecycle

The cycle clock runs once a day, plus a twice-daily expiry check and a daily migration pass. These are the jobs you'll most often correlate to status changes on your subscriptions.

| Job                             | Cadence                          | What it does (partner-visible)                                                                                                                                               |
| ------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Billing run**                 | Daily, 03:00 UTC                 | Closes cycles that ended in the last 24h, opens the next cycle for every active subscription, triggers payment collection on renewal. Drives most `subscription.*` webhooks. |
| **Plan migration pass**         | Daily, 04:00 UTC                 | Applies queued plan changes (`nextPlanId`) for any subscription whose renewal landed in the previous hour. Pushes the new tariff to Splynx and re-provisions RADIUS.         |
| **Subscription expiry check**   | Twice daily, 00:00 and 12:00 UTC | Suspends subscriptions whose grace period has run out. Generates `subscription.suspended` webhooks and removes RADIUS credentials.                                           |
| **Installation window cleanup** | Daily, 02:00 UTC                 | Expires installation appointment windows that were never honoured. Generates `installation.expired` webhooks on Share's side and clears the Splynx task.                     |
| **Scheduled communications**    | Daily, 08:00 UTC                 | Sends time-of-day notifications (low-balance reminders, cycle-ending warnings, etc.). Does not change subscription state.                                                    |

What this implies in practice:

* A renewal you expect on day *D* lands during the 03:00 UTC run on day *D*. Your webhook arrives a few seconds later. If you don't see it by 03:15 UTC, that's a real problem worth raising.
* A queued plan migration takes effect during the 04:00 UTC pass on the renewal day — about an hour after the renewal itself. Until then the subscriber stays on the old plan even if their cycle has technically rolled over.
* Suspensions don't fire continuously — they're batched at midnight and noon UTC. A subscriber who hits their grace deadline at 13:00 UTC will be visibly active until midnight, then suspended.

## Payments and reconciliation

Payments have three jobs working together: a fast one that confirms in-flight transactions, a medium one that pulls newly-settled transactions from the bank rail, and a safety-net that catches up if the first two miss something.

| Job                           | Cadence      | What it does (partner-visible)                                                                                                                                        |
| ----------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Payment status sync**       | Every minute | Re-checks any payment transaction that is still pending. When one confirms, fires the `payment.completed` webhook and triggers settlement.                            |
| **Payment transaction pull**  | Every 15 min | Pulls newly-settled transactions from the bank rail. Catches paybill payments where the rail's callback never arrived. New rows appear in the Splynx customer ledger. |
| **Settlement reconciliation** | Every 5 min  | Catches up on settlement bookings that didn't complete on the first try. Invisible to the customer; partner sees the revenue-split webhook a few minutes late.        |

What this implies in practice:

* A successful STK push or paybill payment normally produces a `payment.completed` webhook within seconds — via the bank rail's own callback. The 1-minute and 15-minute jobs are the fallback if that callback was missed.
* If you don't see a webhook within 15 minutes of a confirmed payment, raise it — you've fallen outside the safety net.

## Splynx mirroring

Splynx writes are queued and drained continuously; there is also an hourly fallback poll that catches anything Splynx's webhook delivery might have dropped.

| Job                      | Cadence             | What it does (partner-visible)                                                                                                                                                       |
| ------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Splynx write drain**   | Every 1 s           | Drains the queue of outbound writes to Splynx — tariff updates, customer mirrors, service status changes, scheduling tasks, payment ledger entries. Visible in the Splynx audit log. |
| **Splynx fallback poll** | Hourly, on the hour | Polls Splynx for any customer or service edits where Splynx's inbound webhook delivery to Share might have failed. Synthesises the missed events and reprocesses them.               |

What this implies in practice:

* Splynx state usually catches up with Share within a few seconds. If Splynx is unreachable from Share, the write queues durably and retries with exponential backoff — no events are lost.
* If your CSR edits a customer in Splynx and Share doesn't react within a few minutes, the hourly fallback will pick it up on the next hour boundary. You can correlate this against the `received_at` field on the eventual Share webhook.

## Network provisioning

RADIUS state is checked very frequently because divergence between the platform and the network is the most expensive kind of bug — a customer paying but unable to connect, or a suspended customer still online.

| Job                          | Cadence    | What it does (partner-visible)                                                                                           |
| ---------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------ |
| **Provisioning queue drain** | Every 5 s  | Drains queued RADIUS writes: user activation, deactivation, session disconnects, credential rotation.                    |
| **RADIUS reconciler**        | Every 30 s | Compares Share's view of who-should-be-online against FreeRADIUS's actual records. Auto-heals drift in either direction. |

What this implies in practice:

* After a renewal payment lands and the subscription activates, the customer is able to connect within \~5 seconds.
* After a suspension, the customer is disconnected within \~5 seconds.
* A `radius.divergence_repaired` audit event (visible in your audit log if subscribed) is normal occasional traffic — it means the reconciler caught and fixed a small drift. Frequent ones for the same subscriber are worth raising.

## KYC and account opening

| Job                      | Cadence     | What it does (partner-visible)                                                                                                                   |
| ------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **KYC subscriber sync**  | Every 5 min | Polls the KYC provider for verification status on subscribers awaiting verification. Updates `subscriber.kycStatus`; fires the relevant webhook. |
| **KYC partner sync**     | Every 5 min | Same as above but for partner / SME account verifications.                                                                                       |
| **KYC document retry**   | Every 5 min | Retries any KYC document upload that failed (network blip, provider unavailable).                                                                |
| **Account opening sync** | Every 5 min | Syncs the status of bank-account-opening requests for partners onboarding their wallet.                                                          |

What this implies in practice:

* A submitted KYC record typically takes one cycle of this job (up to 5 minutes) to show its verified status on Share once the provider confirms.

## Full schedule reference

Sorted by cadence — fastest first.

| Cadence                        | Job                         | Partner-observable     |
| ------------------------------ | --------------------------- | ---------------------- |
| Every 1 s                      | Splynx write drain          | Yes (Splynx state)     |
| Every 5 s                      | Provisioning queue drain    | Yes (RADIUS)           |
| Every 30 s                     | RADIUS reconciler           | Yes (RADIUS)           |
| Every 1 min                    | Payment status sync         | Yes (webhooks)         |
| Every 1 min                    | Ledger transfer executor    | Yes (settlement)       |
| Every 5 min                    | Settlement reconciliation   | Yes (webhooks)         |
| Every 5 min                    | KYC subscriber sync         | Yes                    |
| Every 5 min                    | KYC partner sync            | Yes                    |
| Every 5 min                    | KYC document retry          | Yes                    |
| Every 5 min                    | Account opening sync        | Yes                    |
| Every 15 min                   | Payment transaction pull    | Yes (webhooks)         |
| Hourly (on the hour)           | Splynx fallback poll        | Yes (state)            |
| Daily, 02:00 UTC               | Installation window cleanup | Yes                    |
| Daily, 03:00 UTC               | Billing run                 | Yes (webhooks, RADIUS) |
| Daily, 04:00 UTC               | Plan migration pass         | Yes (Splynx, RADIUS)   |
| Daily, 08:00 UTC               | Scheduled communications    | Yes (customer-facing)  |
| Twice daily, 00:00 & 12:00 UTC | Subscription expiry check   | Yes (webhooks, RADIUS) |

### Internal-only jobs

These run on a cadence too, but the only effect partners can observe from them is that the platform's own balance sheet stays consistent. They don't generate webhooks or change subscriber-facing state.

* **Ledger balance check** — every 6 hours.
* **Ledger balance reconciliation** — daily, 02:00 UTC.
* **Payment-to-ledger reconciliation** — hourly.
* **Subscriber cleanup** — daily, 03:00 UTC.
* **Revenue split retry** — every 5 min.
* **SME wallet pool refresh** — every 30 min.

## Glossary

* **Cadence.** How often a job runs. *Every 5 minutes* means the job fires twelve times an hour, not "within 5 minutes of an event".
* **Grace period.** The configurable window after a cycle ends during which a subscriber is still connected but the next cycle has not been paid for. Per-partner; ask your account manager for your configured value.
* **Drain.** A worker that empties a queue of pending writes. Drains run continuously; their cadence is how often the queue is checked for new work.
* **Reconciler.** A safety-net that compares two systems' views of the same state and fixes any divergence. Reconcilers don't drive normal flow — they exist to catch bugs and outages.
