> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwedai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# QWED Tax integration for AI payroll and tax workflows

> Use QWED Tax pre-flight middleware to verify payroll and tax actions in AI agent workflows before execution.

The primary usage patterns for QWED-Tax are the **TaxPreFlight** auditor for intent-based checks and the **QWEDTaxMiddleware** for intercepting AI-generated payroll payloads.

## TaxPreFlight

The `TaxPreFlight` class routes a transaction intent to the guards required for its `action`. Every intent must declare a supported action and include a complete, verifiable claim for that action. `TaxPreFlight` **fails closed**: it blocks execution whenever the payload is missing required fields, contains non-numeric or non-finite values, or references an unsupported action.

<Note>
  `TaxPreFlight` is **fail-closed**. An intent that is empty, not a `dict`, uses an unsupported `action`, or does not contain a complete verifiable claim is **blocked by default** — it never silently passes through.
</Note>

```python theme={null}
from qwed_tax.verifier import TaxPreFlight

# 1. Initialize
preflight = TaxPreFlight()

# 2. Capture Intent (from AI Agent)
intent = {
    "action": "hire",
    "worker_type": "1099",  # LLM Decision
    "worker_facts": {
        "provides_tools": True,       # Fact: We gave them a laptop
        "reimburses_expenses": True,  # Fact: We pay for travel
        "indefinite_relationship": True,
    },
}

# 3. Audit
report = preflight.audit_transaction(intent)

# 4. Enforce
if not report["allowed"]:
    print(f"BLOCKED: {report['blocks']}")
    # Do NOT call Gusto/Stripe API
else:
    print(f"Verified. Checks run: {report['checks_run']}")
    # call_gusto_api()
```

### Supported actions

Every intent must include an `action` field. `TaxPreFlight` normalizes the action (trims whitespace, lowercases, and replaces spaces with underscores) before routing. If the action is missing, not a non-empty string, or not in the supported set, the intent is blocked with a report that lists every supported action.

| Action             | Purpose                                   | Required claim fields                                                                                                                                                                 |
| ------------------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hire`             | Worker classification (W-2 vs 1099)       | `worker_type`, `worker_facts.provides_tools`, `worker_facts.reimburses_expenses`, `worker_facts.indefinite_relationship`                                                              |
| `economic_nexus`   | US sales-tax nexus check                  | `state`, `sales_data.amount`, `sales_data.transactions`, `tax_decision`                                                                                                               |
| `trade_tax`        | Trader set-off or capital gains           | `loss_head`, `offset_head`, `loss_amount` — **or** — `asset_type`, `dates.buy`, `dates.sell`, `claimed_rate`                                                                          |
| `corporate_action` | Related-party loans or startup valuations | `lender_type`, `borrower_role`, `interest_rate`, `market_rate` — **or** — `investment_round="convertible_note"` plus `investment_amount`, `cap_price`, `discount`, `next_round_price` |
| `remit_money`      | International remittance (LRS/TCS)        | `remittance_amount_usd`, `purpose`, `fy_usage`                                                                                                                                        |
| `expense_claim`    | Input Tax Credit eligibility              | `expense_category`, `amount`, `tax_paid`                                                                                                                                              |
| `pay_invoice`      | Withholding / TDS on vendor payment       | `service_type`, `amount`, `ytd_payment`                                                                                                                                               |

The following legacy action names are accepted and canonicalized automatically:

| Alias                   | Canonical action |
| ----------------------- | ---------------- |
| `hire_worker`           | `hire`           |
| `worker_classification` | `hire`           |
| `sales_tax_check`       | `economic_nexus` |
| `sales_tax_assessment`  | `economic_nexus` |

### Fail-closed routing

`audit_transaction` returns `allowed=False` whenever routing cannot produce a complete verifiable claim. The three blocking conditions are:

<Tabs>
  <Tab title="Empty or invalid payload">
    ```python theme={null}
    preflight.audit_transaction({})
    # {
    #   "allowed": False,
    #   "action": None,
    #   "blocks": ["TaxPreFlight requires a non-empty intent payload with an explicit action."],
    #   "checks_run": []
    # }
    ```
  </Tab>

  <Tab title="Unsupported action">
    ```python theme={null}
    preflight.audit_transaction({"action": "refund_customer"})
    # {
    #   "allowed": False,
    #   "action": "refund_customer",
    #   "blocks": [
    #     "TaxPreFlight requires a supported action. Supported actions: "
    #     "corporate_action, economic_nexus, expense_claim, hire, pay_invoice, "
    #     "remit_money, trade_tax."
    #   ],
    #   "checks_run": []
    # }
    ```
  </Tab>

  <Tab title="Incomplete claim">
    ```python theme={null}
    preflight.audit_transaction({"action": "trade_tax", "asset_type": "equity"})
    # {
    #   "allowed": False,
    #   "action": "trade_tax",
    #   "blocks": [
    #     "Action 'trade_tax' did not include a complete verifiable claim. "
    #     "Supported claim shapes: trader_setoff (loss_head, offset_head, loss_amount); "
    #     "capital_gains (asset_type, dates.buy, dates.sell, claimed_rate)."
    #   ],
    #   "checks_run": []
    # }
    ```
  </Tab>
</Tabs>

The report always echoes the canonical action (after alias resolution) in the `action` field and an empty `checks_run` list when the intent was rejected before any guard executed.

### Intent fields reference

`audit_transaction` returns a report with the following fields:

<ResponseField name="allowed" type="boolean">
  `true` only when every selected guard passes. Treat any `false` as a hard block.
</ResponseField>

<ResponseField name="action" type="string | null">
  The canonical action the intent resolved to (for example, `"hire"`). When the caller submits an unsupported action, this echoes back the raw value they sent; when the payload is entirely missing or empty, it is `null`.
</ResponseField>

<ResponseField name="blocks" type="string[]">
  One or more human-readable block reasons when `allowed` is `false`.
</ResponseField>

<ResponseField name="checks_run" type="string[]">
  Names of the guards that actually executed (for example, `["worker_classification"]`). Empty when the intent was rejected before any guard ran.
</ResponseField>

<ResponseField name="advisories" type="string[]">
  Optional advisory messages emitted by guards (for example, required TDS deduction amounts).
</ResponseField>

### Redacting block reasons in untrusted contexts

`report["blocks"]` contains human-readable diagnostics that may echo back fields from the original intent — including worker facts, nexus sales figures, remittance purposes, or vendor service types. Treat these strings as **internal-only**. Log them to your audit trail. Do not render them verbatim in end-user surfaces, demo output, or any context where a downstream consumer could infer protected payroll or customer data.

In example and demo scripts bundled with `qwed-tax` (`examples/verify_tax_expansion.py`), outcomes are printed as high-level pass/fail only and verification details are intentionally redacted:

```python theme={null}
def _print_outcome(label: str, report: dict, allowed_text: str, blocked_text: str) -> None:
    """Print a safe high-level outcome without echoing raw block reasons."""
    print(f"{label}: {allowed_text if report['allowed'] else blocked_text}")
    if report["allowed"]:
        return

    print("   Verification details intentionally redacted.")
```

Mirror this pattern when surfacing preflight results outside a trusted audit boundary.

### Supported actions

Every intent must set `action` to one of the supported values below. Actions are normalized (trimmed, lowercased, spaces converted to underscores) before routing, and the listed aliases are accepted for backwards compatibility.

| Action             | Aliases                                   | Runs                                |
| ------------------ | ----------------------------------------- | ----------------------------------- |
| `hire`             | `hire_worker`, `worker_classification`    | ClassificationGuard                 |
| `economic_nexus`   | `sales_tax_check`, `sales_tax_assessment` | NexusGuard                          |
| `trade_tax`        | —                                         | SpeculationGuard, CapitalGainsGuard |
| `corporate_action` | —                                         | RelatedPartyGuard, ValuationGuard   |
| `remit_money`      | —                                         | RemittanceGuard                     |
| `expense_claim`    | —                                         | InputCreditGuard                    |
| `pay_invoice`      | —                                         | TDSGuard                            |

Any other `action` (including missing, empty, or non-string values) is blocked with a message listing the supported actions.

### Required fields per action

Each action requires a complete claim shape. If any listed field is missing, `null`, or empty, the transaction is blocked before guards run — no guard is invoked with partial inputs.

| Action                         | Required fields                                                                                                          |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `hire`                         | `worker_type`, `worker_facts.provides_tools`, `worker_facts.reimburses_expenses`, `worker_facts.indefinite_relationship` |
| `economic_nexus`               | `state`, `sales_data.amount`, `sales_data.transactions`, `tax_decision`                                                  |
| `trade_tax` (trader set-off)   | `loss_head`, `offset_head`, `loss_amount`                                                                                |
| `trade_tax` (capital gains)    | `asset_type`, `dates.buy`, `dates.sell`, `claimed_rate`                                                                  |
| `corporate_action` (loans)     | `lender_type`, `borrower_role`, `interest_rate`, `market_rate`                                                           |
| `corporate_action` (valuation) | `investment_round`, `investment_amount`, `cap_price`, `discount`, `next_round_price`                                     |
| `remit_money`                  | `remittance_amount_usd`, `purpose`, `fy_usage`                                                                           |
| `expense_claim`                | `expense_category`, `amount`, `tax_paid`                                                                                 |
| `pay_invoice`                  | `service_type`, `amount`, `ytd_payment`                                                                                  |

<Note>
  For `trade_tax` and `corporate_action`, at least one of the claim shapes above must be fully present. Providing trigger fields for a claim but omitting any of its required fields is treated as an incomplete claim and fails closed. Startup valuation (`corporate_action`) additionally only runs when `investment_round == "convertible_note"`; other rounds are blocked with an explicit message.
</Note>

### Numeric inputs must be finite

Guards that work with money — `RemittanceGuard` and `TDSGuard` — reject non-numeric, `NaN`, and infinite values. The surrounding `audit_transaction` call surfaces these as block reasons so an upstream LLM cannot smuggle through a malformed number.

````python theme={null}
report = preflight.audit_transaction({
    "action": "pay_invoice",
    "service_type": "PROFESSIONAL_FEES",
    "amount": float("inf"),
    "ytd_payment": 0,
})
# report["allowed"] = False
# report["blocks"] contains:
#   "TDS verification requires finite invoice_amount and ytd_payment values."
| `worker_type` | `str` | ClassificationGuard |
| `worker_facts` | `dict` | ClassificationGuard |
| `state` | `str` | NexusGuard |
| `sales_data` | `dict` (`amount`, `transactions`) | NexusGuard |
| `tax_decision` | `str` | NexusGuard |
| `loss_head` | `str` | SpeculationGuard |
| `loss_amount` | `float` | SpeculationGuard |
| `offset_head` | `str` | SpeculationGuard |
| `asset_type` | `str` | CapitalGainsGuard |
| `dates` | `dict` (`buy`, `sell`) | CapitalGainsGuard |
| `claimed_rate` | `str` | CapitalGainsGuard |
| `lender_type` | `str` | RelatedPartyGuard |
| `borrower_role` | `str` | RelatedPartyGuard |
| `interest_rate` | `float` | RelatedPartyGuard |
| `market_rate` | `float` | RelatedPartyGuard |
| `investment_round` | `str` | ValuationGuard (when `"convertible_note"`) |
| `investment_amount` | `str` | ValuationGuard |
| `cap_price` | `str` | ValuationGuard |
| `discount` | `str` | ValuationGuard |
| `next_round_price` | `str` | ValuationGuard |
| `remittance_amount_usd` | `float` | RemittanceGuard |
| `purpose` | `str` | RemittanceGuard |
| `fy_usage` | `float` | RemittanceGuard |
| `expense_category` | `str` | InputCreditGuard |
| `amount` | `float` | InputCreditGuard, TDSGuard |
| `tax_paid` | `float` | InputCreditGuard |
| `service_type` | `str` | TDSGuard |
| `ytd_payment` | `float` | TDSGuard |

### Capital gains date validation

For `action="trade_tax"`, the capital-gains route requires both `dates.buy` and `dates.sell` along with `asset_type` and `claimed_rate`. If any required field is missing, the transaction is blocked with a field-level diagnostic:

```python
report = preflight.audit_transaction({
    "action": "trade_tax",
    "asset_type": "equity",
    "dates": {"buy": "2024-01-01"},  # sell missing
    "claimed_rate": "20"
})
# report["allowed"] = False
# report["blocks"] = [
#   "Action 'trade_tax' is missing required fields for capital_gains: dates.sell."
# ]
````

### TDS advisories now block

When `action="pay_invoice"` requires a TDS deduction, the transaction is **blocked** and the required deduction is surfaced in both `advisories` and `blocks`. The agent must re-issue the payment net of TDS before execution can proceed:

```python theme={null}
report = preflight.audit_transaction({
    "action": "pay_invoice",
    "service_type": "PROFESSIONAL_FEES",
    "amount": 50000,
    "ytd_payment": 0,
})
# report["allowed"] = False
# report["advisories"] = ["TDS Required: Deduct 5000.00 from payment."]
# report["blocks"] = [
#     "Invoice payment requires TDS deduction of 5000.00 before execution."
# ]
```

### Example: unsupported action

```python theme={null}
report = preflight.audit_transaction({"action": "do_everything"})
# report["allowed"] = False
# report["action"] = "do_everything"
# report["blocks"] = [
#     "TaxPreFlight requires a supported action. Supported actions: "
#     "corporate_action, economic_nexus, expense_claim, hire, "
#     "pay_invoice, remit_money, trade_tax."
# ]
```

## TaxVerifier

The `TaxVerifier` class provides jurisdiction-scoped access to guards. Initialize with `"US"` or `"INDIA"` to load the appropriate guard set.

```python theme={null}
from qwed_tax.verifier import TaxVerifier

# US jurisdiction
us_verifier = TaxVerifier(jurisdiction="US")
result = us_verifier.verify_us_payroll(entry=payroll_entry)

# India jurisdiction
india_verifier = TaxVerifier(jurisdiction="INDIA")
result = india_verifier.verify_india_crypto(
    losses={"VDA": Decimal("-5000")},
    gains={"BUSINESS": Decimal("10000")}
)

# Deposit rate verification (India)
result = india_verifier.verify_india_deposit(
    age=65,
    base_rate=Decimal("7.00"),
    claimed_rate=Decimal("7.50"),
    senior_premium=Decimal("0.50")
)
```

| Jurisdiction | Available methods                                                        |
| ------------ | ------------------------------------------------------------------------ |
| `US`         | `verify_us_payroll(entry)` — runs PayrollGuard gross-to-net check        |
| `INDIA`      | `verify_india_crypto(losses, gains)` — runs CryptoTaxGuard set-off check |
| `INDIA`      | `verify_india_deposit(**kwargs)` — runs DepositRateGuard FD rate check   |

<Note>
  The US verifier also includes a `TaxPreFlight` instance accessible via `us_verifier.preflight` for intent-based auditing.
</Note>

## QWEDTaxMiddleware (Gusto interceptor)

The `QWEDTaxMiddleware` intercepts AI-generated payroll payloads before they reach execution APIs like Gusto. It validates the payload schema using Pydantic models and then runs deterministic gross-to-net verification.

```python theme={null}
from qwed_tax.middleware.gusto_interceptor import QWEDTaxMiddleware

middleware = QWEDTaxMiddleware()

# Simulate an AI-generated payroll payload
ai_payload = {
    "payroll_entry": {
        "employee_id": "E001",
        "gross_pay": "5000.00",
        "taxes": [
            {"name": "Federal Income Tax", "amount": "800.00"},
            {"name": "Social Security", "amount": "310.00"}
        ],
        "deductions": [
            {"name": "401k", "amount": "250.00", "type": "PRE_TAX"}
        ],
        "net_pay_claimed": "3640.00"
    }
}

decision = middleware.process_ai_payroll_request(ai_payload)
```

### Response format

<Tabs>
  <Tab title="Verified">
    ```json theme={null}
    {
      "status": "VERIFIED",
      "message": "AI tax logic mathematically verified. Safe to execute.",
      "execution_permitted": true,
      "validated_payload": { ... }
    }
    ```
  </Tab>

  <Tab title="Blocked (hallucination)">
    ```json theme={null}
    {
      "status": "BLOCKED",
      "risk": "TAX_LOGIC_HALLUCINATION",
      "reason": "Mathematical discrepancy detected. Claimed Net: 3640.00, Calculated: 3640.00.",
      "execution_permitted": false
    }
    ```
  </Tab>

  <Tab title="Blocked (invalid payload)">
    ```json theme={null}
    {
      "status": "BLOCKED",
      "risk": "INVALID_PAYLOAD",
      "reason": "Missing or empty 'payroll_entry' in payload.",
      "execution_permitted": false
    }
    ```
  </Tab>
</Tabs>

<ResponseField name="status" type="string">
  `VERIFIED` or `BLOCKED`.
</ResponseField>

<ResponseField name="execution_permitted" type="boolean">
  Whether the payload is safe to forward to the execution API.
</ResponseField>

<ResponseField name="risk" type="string">
  Risk code when blocked: `TAX_LOGIC_HALLUCINATION`, `INVALID_PAYLOAD`, or `VERIFIER_ERROR`.
</ResponseField>

<ResponseField name="reason" type="string">
  Human-readable explanation of why the payload was blocked.
</ResponseField>

<ResponseField name="validated_payload" type="object">
  The validated payload (JSON-serialized) when execution is permitted.
</ResponseField>

## Standalone guard usage

You can also use specific guards individually found in `qwed_tax.jurisdictions` and `qwed_tax.guards`.

```python theme={null}
from qwed_tax.jurisdictions.us.payroll_guard import PayrollGuard

pg = PayrollGuard()
result = pg.verify_fica_tax(gross_ytd=180000, current_gross=5000, claimed_ss_tax=310)
print(result.message)
# -> "FICA Error: Expected $68.20, Claimed $310. Limit logic failed? (Hit Limit this period...)"
```

## TypeScript SDK

Run compliance checks proactively in the browser or frontend.

```bash theme={null}
npm install @qwed-ai/tax
```

```typescript theme={null}
import { TaxPreFlight } from '@qwed-ai/tax';

const result = TaxPreFlight.audit({
  action: "hire",
  worker_type: "1099",
  worker_facts: {
    provides_tools: true,
    reimburses_expenses: true,
    indefinite_relationship: true,
  },
});

if (!result.allowed) {
   alert("Compliance Block: " + result.blocks.join(", "));
}
```
