Inspect, quote, authorize, receive
1. Check current offers and coverage
The live JSON catalog is authoritative for payment availability, covered towns, source dates and offer limits. This guide alone does not establish that a product is available. Directory results must identify GroundSignal and cookcountyrecords.com; a matching name alone is insufficient. For broader research context, read llms.txt, the AI assistant connection guide and source coverage.
Read the full command guide as plain text or run curl -fsS https://cookcountyrecords.com/agents.txt.
Discover the merchant and inspect the catalog
stripe directory search "GroundSignal" --format json
curl --fail --silent --show-error \
https://cookcountyrecords.com/api/agent/offers | jq .| Offer / SKU | Base USD | Required research input and result |
|---|---|---|
Appeal briefappeal_brief | $49 | One covered town and eligible 14-digit PIN. A standalone HTML research brief, printable or saveable as PDF. |
Trade territory listtrade_list | $299 | One covered town. CSV of indexed residential properties built before 1985 with no matching permit in the available feed. |
Appeal Season Passseason_pass | $495 | One covered town and season. CSV of the existing appeal research pool, licensed to one firm. |
All are one-time purchases. The quote validates the current Stripe price, records, eligibility, source checks and US billing address before requesting payment. It returns the subtotal, applicable tax and complete total in USD cents, the source release, record dates, record count where applicable, and expiry. Link supports a complete total of at most $500; a higher total is rejected before payment and can use existing human checkout. Do not split a purchase to avoid this limit. An unavailable town, empty list or ineligible PIN is not offered for payment. Subscriptions and custom research are not part of this CLI flow.
2. Prepare a recoverable quote
Supply the actual buyer billing address for tax calculation. Do not substitute the property address unless it is also the billing address. Keep the generated access token, request key and request file: together they let you recover a lost response without a new purchase. Do not put tokens, billing addresses or secure links in public logs.
Validate the requested property or list before payment
# Run these commands in one shell. Requires curl, jq, OpenSSL and uuidgen.
umask 077
ORIGIN=https://cookcountyrecords.com
PURCHASE_ROOT="$HOME/.local/share/groundsignal/purchases"
mkdir -p "$PURCHASE_ROOT"
PURCHASE_DIR=$(mktemp -d "$PURCHASE_ROOT/purchase.XXXXXX")
openssl rand -hex 32 > "$PURCHASE_DIR/access-token"
uuidgen > "$PURCHASE_DIR/request-key"
printf 'SKU (appeal_brief, trade_list, season_pass): '
read -r SKU
printf 'Town slug from the available catalog: '
read -r CITY
PIN=
if [ "$SKU" = appeal_brief ]; then
printf 'Property PIN (14 digits, no separators): '
read -r PIN
fi
printf 'US billing street address: '
read -r BILLING_LINE1
printf 'Billing city: '
read -r BILLING_CITY
printf 'Billing state (two uppercase letters): '
read -r BILLING_STATE
printf 'Billing ZIP code: '
read -r BILLING_POSTAL
jq -n --arg sku "$SKU" --arg city "$CITY" --arg pin "$PIN" \
--arg line1 "$BILLING_LINE1" --arg billingCity "$BILLING_CITY" \
--arg state "$BILLING_STATE" --arg postal "$BILLING_POSTAL" \
'{sku:$sku, city:$city, billing_address:{country:"US", line1:$line1,
city:$billingCity, state:$state, postal_code:$postal}}
+ (if $sku == "appeal_brief" then {pin:$pin} else {} end)' \
> "$PURCHASE_DIR/request.json"
curl --fail-with-body --silent --show-error \
"$ORIGIN/api/agent/quotes" \
--header "Authorization: Bearer $(cat "$PURCHASE_DIR/access-token")" \
--header "Idempotency-Key: $(cat "$PURCHASE_DIR/request-key")" \
--header 'Content-Type: application/json' \
--data-binary @"$PURCHASE_DIR/request.json" \
--output "$PURCHASE_DIR/quote.json"
# Review all amounts in cents, coverage, record dates, delivery and expiry.
# Keep the access token and secure status link out of shared logs.
jq 'del(.secure_status_link)' "$PURCHASE_DIR/quote.json"
printf 'Recovery files saved in %s\n' "$PURCHASE_DIR"3. Review the complete price and authorize in Link
Present the buyer with the offer, town or PIN, record dates, deliverable, license, subtotal, tax and total. Ask for authorization before the payment command. Stripe Link CLI handles the MPP challenge and card payment through a Shared Payment Token. Keep the store bearer token in Authorization; Link sends its MPP credential in Payment-Authorization. Do not replace the product purchase with a plain stripe pay transfer.
Buyer-authorized product purchase
# Install Link CLI first if needed: npm install --global @stripe/link-cli
# Use a current Node.js LTS such as 22.22 or 24 with the npm package.
# If your wallet login uses LINK_AUTH_FILE, export that same path here.
# Keep it set for login, status, payment, polling and resume commands.
link-cli auth login
# Open Link's login URL and approve its displayed phrase when prompted.
# Continue only after authenticated is true; this does not approve a purchase.
link-cli auth status --format json
PAYMENT_URL=$(jq -er '.payment_url' "$PURCHASE_DIR/quote.json")
QUOTE_ID=$(jq -er '.id' "$PURCHASE_DIR/quote.json")
TOTAL_CENTS=$(jq -er '.totals.total' "$PURCHASE_DIR/quote.json")
# An agent must ask its buyer to approve the complete quoted total first.
printf 'After reviewing the complete total and scope, type PAY to authorize: '
read -r APPROVAL
if [ "$APPROVAL" = PAY ]; then
link-cli mpp pay "$PAYMENT_URL" \
--method POST --data '{}' --amount "$TOTAL_CENTS" \
--header "Authorization: Bearer $(cat "$PURCHASE_DIR/access-token")" \
--context "Purchase reviewed property-research quote $QUOTE_ID for a complete total of $TOTAL_CENTS USD cents including applicable tax. The buyer approved the town coverage, source dates, deliverable, license, and limitations." \
--format json > "$PURCHASE_DIR/payment.json"
# Show approval details privately to the buyer; never print continuation args.
jq '(if type == "object" and has("data") then .data else . end)
| (if type == "array" then .[-1] else . end)
| {spend_request_id:.id, status, approval_url,
action:(.status_details.requires_action.next_action
| if . == null then null else {type,resolution,display_message,action_url} end)}' \
"$PURCHASE_DIR/payment.json"
fiWallet login and purchase approval are separate. If your login uses LINK_AUTH_FILE or --auth, every Link command must use that same credential file, including status checks, polling and payment resume. Keep its contents private; do not create another login just because a different shell cannot find it.
If Link returns approval or polling instructions, follow its returned _next.poll_argv and _next.pay_argv objects for this same quote and spend request. Each has command and args: invoke the trusted Link CLI with the command followed by each argument, without joining them into a shell string. Keep LINK_AUTH_FILE set and add --format json when resuming. Wait for the buyer to approve Link's displayed purchase before resuming it. Keep the full JSON response private: its continuation arguments include your order access key. JSON output can be an array of updates; inspect its final item and resume payment only when Link reports approved. A zero CLI exit code or approval prompt is not payment confirmation; verify the order below. Sandbox testing requires a sandbox merchant endpoint and Link’s --test flag; adding the flag does not turn a live merchant endpoint into a sandbox.
If Link requests approval, poll and resume the original purchase
# Run only when Link returns an approval URL. Keep LINK_AUTH_FILE unchanged.
# The buyer opens that URL and approves the displayed purchase in Link.
python3 - "$PURCHASE_DIR" <<'PY'
import json, subprocess, sys
from datetime import datetime, timezone
from pathlib import Path
directory = Path(sys.argv[1])
def read_result(filename):
value = json.loads((directory / filename).read_text())
if isinstance(value, dict) and "data" in value:
value = value["data"]
return value[-1] if isinstance(value, list) else value
def run_link(command, args, filename):
with (directory / filename).open("w") as output, (directory / "link-errors.log").open("a") as errors:
code = subprocess.run(["link-cli", command, *args, "--format", "json"],
stdout=output, stderr=errors).returncode
if code:
sys.exit("Link did not complete. Recover this order and inspect its private response.")
return read_result(filename)
pending = read_result("payment.json")
quote = read_result("quote.json")
steps = pending.get("_next", {})
poll = steps.get("poll_argv", {})
pay = steps.get("pay_argv", {})
spend_id = pending.get("id")
if not spend_id or poll.get("command") != "spend-request" or poll.get("args", [])[:2] != ["retrieve", spend_id]:
sys.exit("No matching approval request. Check the existing order status.")
args = pay.get("args", [])
if (pay.get("command") != "mpp" or args[:2] != ["pay", quote["payment_url"]]
or "--spend-request-id" not in args or "--approved-challenge" not in args
or args[args.index("--spend-request-id") + 1 :][:1] != [spend_id]):
sys.exit("The continuation does not match this quote and approval request.")
approved = run_link("spend-request", poll["args"], "approval.json")
if approved.get("id") != spend_id or approved.get("status") != "approved":
sys.exit("Link has not confirmed approval. Keep the quote and check its status.")
if datetime.fromisoformat(quote["expires_at"].replace("Z", "+00:00")) <= datetime.now(timezone.utc):
sys.exit("The quote expired. Recover the existing order before requesting a new quote.")
run_link("mpp", args, "payment-resumed.json")
print("Link returned. Recover the same order below to verify payment and delivery.")
PY4. Recover the order and retrieve its result
Payment is verified on the server. An accepted order includes its order number, paid total, status and secure status link. An accepted order is not a completed report. The artifact is prepared before a quote is offered; delivery is normally available after payment confirmation. If confirmation or fulfillment is pending, use the returned status URL. No fixed completion time is promised while a payment or service issue is unresolved.
- quoted
- Validated offer; payment has not been confirmed.
- processing
- Payment or delivery is being reconciled. Check this order again; do not buy a replacement.
- ready
- Verified payment and a completed artifact are available for secure download.
- failed
- Read the returned failure details. Resolve the existing order before attempting another purchase.
- refunded
- The payment was refunded; download access is withdrawn.
- disputed
- The payment is disputed; download access is suspended.
Check the saved order, then download only when ready
# In a new shell, set PURCHASE_DIR to the directory saved above.
STATUS_URL=$(jq -er '.status_url' "$PURCHASE_DIR/quote.json")
curl --fail-with-body --silent --show-error "$STATUS_URL" \
--header "Authorization: Bearer $(cat "$PURCHASE_DIR/access-token")" \
--output "$PURCHASE_DIR/status.json"
jq 'del(.secure_status_link)' "$PURCHASE_DIR/status.json"
# A quote's download_url is null until the order is ready.
if jq -e '.state == "ready" and .paid == true and .completed == true' \
"$PURCHASE_DIR/status.json" > /dev/null; then
DOWNLOAD_URL=$(jq -er '.download_url' "$PURCHASE_DIR/status.json")
if [ "$(jq -r '.sku' "$PURCHASE_DIR/request.json")" = appeal_brief ]; then
RESULT_FILE=report.html
else
RESULT_FILE=list.csv
fi
curl --fail --silent --show-error "$DOWNLOAD_URL" \
--header "Authorization: Bearer $(cat "$PURCHASE_DIR/access-token")" \
--output "$PURCHASE_DIR/$RESULT_FILE"
else
printf 'Order is not ready. Keep its recovery files and check this order again.\n'
fiYour purchase also includes free rebuilds for the same PIN or current-release list downloads for the same town while the product is offered. The refresh URL checks current records and identifies the delivered release and generation date in its response headers. It creates no new payment or order. If current records are unavailable, recover the original dated result from the regular download URL.
Rebuild from current records without another charge
# Included with the same paid order; no payment command is needed.
# Check status as above, then use its refresh_url.
REFRESH_URL=$(jq -er '.refresh_url' "$PURCHASE_DIR/status.json")
curl --fail-with-body --silent --show-error "$REFRESH_URL" \
--header "Authorization: Bearer $(cat "$PURCHASE_DIR/access-token")" \
--dump-header "$PURCHASE_DIR/rebuild-headers.txt" \
--output "$PURCHASE_DIR/current-$RESULT_FILE"Appeal briefs also provide a structured_download_url for JSON containing the recorded subject, calculated comparisons, all indexed comparable candidates and the default selection. Use the same bearer key. Add &refresh=true to rebuild that JSON from current records.
CLI delivery needs no store account. Your purchase also includes the original app entitlement: open the private status link, sign in to your own account in a separate tab, then choose “Link to my signed-in account.” This links the existing order once, without another charge. Appeal buyers can then use the full builder to choose comparables and enter their own supporting evidence; list buyers can use account downloads. The CLI access key continues to work.
Lost quote response: repeat the same quote request with the same body, access token and Idempotency-Key. Lost payment response: check the saved status URL before retrying the same payment URL. Never generate a new purchase key to work around a pending payment. The bearer token and the fragment in secure_status_link grant access to this purchase; keep both private. For unresolved failures or refunds, use the business contact with the order number, without sending the token. Read the refund policy.
Keep the evidence and its limits together
The brief contains recorded property and assessment facts, the existing uniformity calculations, default lower-assessed comparables, official source links, dates and limitations. It makes no AI calls and does not file an appeal. It is not an appraisal, legal advice, an assurance of a filing window, or a promise of success or savings. Proposed comparables require verification in the official records.
Trade CSV fields include PIN, property address, year built, assessment, class-based value estimate, permit field and published taxpayer-association fields. No matching permit does not establish that no work occurred or is needed. The season CSV includes residential properties built before 2022 with more than 400 building square feet, assessed strictly more than 10% above the peer median, with no recorded appeal from 2024 onward. Peers share an assessor neighborhood, class and 20-year construction era, with at least eight records. The CSV includes peer calculations, available appeal history and taxpayer associations; it does not establish current representation or a winning appeal.
Retain the source URLs, observation and publication dates, release identifier, calculated labels, withheld fields and uncertainty notes. Taxpayer associations are not verified title or beneficial ownership. Mailing street addresses are excluded from the lists. Preserve the “AI-assisted research” label when citing other site material that carries it. Lists are licensed to one firm with no resale or redistribution and are not consumer reports for credit, employment, insurance or tenant screening. See the one-time purchase terms and methodology.
Human customers can continue through the existing embedded checkout from the product and pricing pages. Official protocol references: Stripe MPP, Link CLI and Stripe Directory.