Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Aging Buckets

finance.aging_buckets

ProductionBounded custom (Class B)Deterministicstrictmoderatev1.0.0
No network

Overview

You pass a reference date, open items, and bucket boundaries; we assign each item to a bucket and return totals, counts, and optional item ids per bucket. Mixed currencies are rejected. We never use wall-clock "today" or convert currencies. Do not use this for payment matching or FX conversion.

Silent currency mixing and an implicit "today" make an aging report impossible to reproduce a week later. You pick the date and the ladder, we do the arithmetic in exact decimals and show you anything that fell through.

Reliability

Same input, same report — we read no clock and no rate table. Amounts are exact decimals, rounded HALF_UP to the currency's minor units only when we render them. Anything that matches no bucket lands in unbucketed instead of vanishing. AGING_BUCKETS_OVERLAP — trigger: two of your bucket ranges cover the same day, so an item could belong to either; retryable: no, the same ladder always fails; next: make the ranges disjoint, for example 1-30 then 31-60, and call again. AGING_CURRENCY_MIXED — trigger: your items carry more than one currency code and we never convert; retryable: no; next: split the items per currency and send one call per currency. AGING_ITEM_LIMIT_EXCEEDED — trigger: you sent more than 5,000 items in a single call; retryable: no; next: page your ledger into chunks of 5,000 or fewer and add the bucket totals on your side. AGING_BUCKET_LIMIT_EXCEEDED — trigger: your ladder defines more than 12 buckets; retryable: no; next: merge the narrow ranges until 12 or fewer remain. AMOUNT_INVALID — trigger: an amount, amountPaid, reference date or item date we cannot read, a bucket whose fromDays is greater than its toDays, or an ageBasis or amountBasis outside the accepted values; retryable: no; next: send money as plain decimal strings without thousands separators or exponents, dates as YYYY-MM-DD, and check the message for the item id we named.

Context footprint

Returns bucket totals, percentages, and optional item ids in one reproducible pass. A successful call costs 1 execution credit.

When to use it

When you already know the reference date and the bucket boundaries, and every item is in one currency.

When you still need to convert currencies, allocate payments to invoices, or score collection risk.

Scope

Note
Deterministic AR/AP aging against a reference date and bucket ladder you define.

Non-goals

  • Does not use the server's current date as "today"
  • Does not convert mixed currencies
  • Does not match payments to invoices or score collections risk

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

analysismath

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input512 KB

How we handle your data

Sensitive input, safe output
What this means

This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response does not contain submitted content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
referenceDatestringYesDate every item is aged against as YYYY-MM-DD; never the server clock.
itemsarrayYesUp to 5,000 closed open items sharing one ISO 4217 currency, each with amount and a due or issue date.
bucketsarrayYesFrom 1 through 12 closed bucket definitions evaluated in order with inclusive day bounds that must not overlap.
optionsobjectNoOptional aging controls for which date and amount are bucketed and whether item ids are included; omit it for due_date, outstanding, and item ids included.

Output schema

FieldTypeRequiredDescription
referenceDatestringYesReference date every item was aged from, echoed so a stored ladder can be re-aged without the original request.
currencystringYesSingle ISO 4217 code shared by the items, or EUR when the item list is empty.
bucketsarrayYesYour bucket ladder poured with item counts, totals, percent shares, and optional item ids, in the order you sent.
totalstringYesGrand total across every bucket plus the unbucketed block, as a decimal string.
itemCountintegerYesHow many items were actually aged after fully paid items were dropped under outstanding.
unbucketedobjectYesClosed remainder for items that matched no bucket, with count, total, and optional capped item ids.
findingsarrayYesAging notes such as ladder gaps or excluded settled items; empty when there is nothing to say.
_metaobjectNoSettings the report ran with so a stored ladder explains its age basis, amount basis, and bucket count.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"finance.aging_buckets","input":{"referenceDate":"2026-07-25","items":[{"id":"INV-1","dueDate":"2026-06-30","amount":"1200.00","amountPaid":"200.00","currency":"EUR"}],"buckets":[{"label":"current","fromDays":null,"toDays":0},{"label":"1-30","fromDays":1,"toDays":30},{"label":"31-60","fromDays":31,"toDays":60},{"label":"60+","fromDays":61,"toDays":null}],"options":{"ageBasis":"due_date","amountBasis":"outstanding"}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("finance.aging_buckets", {"options":{"ageBasis":"due_date","amountBasis":"outstanding","includeItemIds":true},"items":[{"id":"INV-1","amount":"1200.00","amountPaid":"200.00","currency":"EUR","dueDate":"2026-06-30"}],"referenceDate":"2026-07-25","buckets":[{"label":"current","fromDays":null,"toDays":0},{"label":"1-30","fromDays":1,"toDays":30},{"label":"31-60","fromDays":31,"toDays":60},{"label":"60+","fromDays":61,"toDays":null}]});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
AGING_BUCKETS_OVERLAP400NoThe request payload failed this skill's input validation.
AGING_CURRENCY_MIXED400NoThe request payload failed this skill's input validation.
AGING_ITEM_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
AGING_BUCKET_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
AMOUNT_INVALID400NoThe request payload failed this skill's input validation.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not use the server's current date as "today"
  • Does not convert mixed currencies
  • Does not match payments to invoices or score collections risk
  • Cross-currency aging without prior conversion
  • Payment allocation or cash-application
  • Collections scoring or dunning decisions

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "finance.aging_buckets",
  "input": {
    "options": {
      "ageBasis": "due_date",
      "amountBasis": "outstanding",
      "includeItemIds": true
    },
    "items": [
      {
        "id": "INV-1",
        "amount": "1200.00",
        "amountPaid": "200.00",
        "currency": "EUR",
        "dueDate": "2026-06-30"
      }
    ],
    "referenceDate": "2026-07-25",
    "buckets": [
      {
        "label": "current",
        "fromDays": null,
        "toDays": 0
      },
      {
        "label": "1-30",
        "fromDays": 1,
        "toDays": 30
      },
      {
        "label": "31-60",
        "fromDays": 31,
        "toDays": 60
      },
      {
        "label": "60+",
        "fromDays": 61,
        "toDays": null
      }
    ]
  }
}

Examples

One overdue EUR invoice lands in the 1–30 day bucket

Inputjson
{
  "options": {
    "ageBasis": "due_date",
    "amountBasis": "outstanding",
    "includeItemIds": true
  },
  "items": [
    {
      "id": "INV-1",
      "amount": "1200.00",
      "amountPaid": "200.00",
      "currency": "EUR",
      "dueDate": "2026-06-30"
    }
  ],
  "referenceDate": "2026-07-25",
  "buckets": [
    {
      "label": "current",
      "fromDays": null,
      "toDays": 0
    },
    {
      "label": "1-30",
      "fromDays": 1,
      "toDays": 30
    },
    {
      "label": "31-60",
      "fromDays": 31,
      "toDays": 60
    },
    {
      "label": "60+",
      "fromDays": 61,
      "toDays": null
    }
  ]
}
Expected outputjson
{
  "referenceDate": "2026-07-25",
  "buckets": [
    {
      "label": "current",
      "fromDays": null,
      "toDays": 0,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    },
    {
      "label": "1-30",
      "fromDays": 1,
      "toDays": 30,
      "itemCount": 1,
      "total": "1000.00",
      "percentOfTotal": "100.00",
      "itemIds": [
        "INV-1"
      ]
    },
    {
      "label": "31-60",
      "fromDays": 31,
      "toDays": 60,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    },
    {
      "label": "60+",
      "fromDays": 61,
      "toDays": null,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    }
  ],
  "findings": [],
  "itemCount": 1,
  "currency": "EUR",
  "unbucketed": {
    "itemCount": 0,
    "itemIds": [],
    "total": "0.00"
  },
  "total": "1000.00",
  "_meta": {
    "ageBasis": "due_date",
    "amountBasis": "outstanding",
    "bucketCount": 4
  }
}

Current bucket catches items not yet due

Inputjson
{
  "referenceDate": "2026-07-25",
  "buckets": [
    {
      "label": "current",
      "fromDays": null,
      "toDays": 0
    },
    {
      "label": "1-30",
      "fromDays": 1,
      "toDays": 30
    },
    {
      "label": "31-60",
      "fromDays": 31,
      "toDays": 60
    },
    {
      "label": "60+",
      "fromDays": 61,
      "toDays": null
    }
  ],
  "items": [
    {
      "amount": "500.00",
      "currency": "EUR",
      "dueDate": "2026-08-15",
      "id": "INV-2"
    }
  ]
}
Expected outputjson
{
  "referenceDate": "2026-07-25",
  "buckets": [
    {
      "label": "current",
      "fromDays": null,
      "toDays": 0,
      "itemCount": 1,
      "total": "500.00",
      "percentOfTotal": "100.00",
      "itemIds": [
        "INV-2"
      ]
    },
    {
      "label": "1-30",
      "fromDays": 1,
      "toDays": 30,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    },
    {
      "label": "31-60",
      "fromDays": 31,
      "toDays": 60,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    },
    {
      "label": "60+",
      "fromDays": 61,
      "toDays": null,
      "itemCount": 0,
      "total": "0.00",
      "percentOfTotal": "0.00",
      "itemIds": []
    }
  ],
  "findings": [],
  "itemCount": 1,
  "currency": "EUR",
  "unbucketed": {
    "itemCount": 0,
    "itemIds": [],
    "total": "0.00"
  },
  "total": "500.00",
  "_meta": {
    "ageBasis": "due_date",
    "amountBasis": "outstanding",
    "bucketCount": 4
  }
}
  • Build a standard AR aging ladder for a month-end close
  • Summarize overdue payables by days past due
  • Agent-generated aging reports with reproducible totals

Avoid for

  • Cross-currency aging without prior conversion
  • Payment allocation or cash-application
  • Collections scoring or dunning decisions

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

mathanalysisagingcurrencyfinance