How it is built
Every tool in Remedy, the one job it does, and where it lives in the code. Live status is on the Status page.
- PayPal
Pays refunds instantly, and refunds to the original purchase inside 180 days.
How it works and where it lives
Payouts to an email, a phone number or Venmo; a refund to the original capture when the owner bought with PayPal in the last 180 days; Orders v2 for the sample shop and for safe replacements. A firm can connect its own PayPal REST app, checked with PayPal and stored sealed, and its refunds and payouts then run on it; the sample firm pays from the platform's sandbox account. Every status comes from webhooks verified with PayPal (the signature, or PayPal's own copy of the event looked up by id), and every payment writes to the hash-chained ledger. Check C6 (not already refunded) reads the purchase's order, its captures and refunds, through PayPal's own MCP server with its read-only get_order tool, and from the Orders API when that server cannot answer.
paypal/client.tspaypal/mcp.tspaypal/firm-account.tspayments/router.tslib/audit.ts
- Claude Opus 5.5
Reads each remedy into a checklist, verifies photos, and runs the two reviewers.
How it works and where it lives
claude-opus-5-5 with structured outputs validated by Zod and server-side fallbacks. Proof rules for every photo-refund recall are extracted with the Message Batches API. The money math, the decision and the payment route are plain code, never the model.
- Elastic
Searches every recall, keyword and semantic, reranked.
How it works and where it lives
Hybrid search over every US consumer recall since 2024: keyword and semantic retrieval fused by reciprocal rank, then reranked. Without Elastic, an in-app keyword search over the same recalls stands in. Photo matching is not search: it is a perceptual hash compared in code.
- Channel3
Finds a safe replacement product.
How it works and where it lives
POST /v1/search for in-stock products in the same category and price range; each result is checked against active recalls before an owner sees it.
- Bryntum
The corrective-action plan and the review schedule.
How it works and where it lives
Bryntum Gantt 7.3 (trial) holds the recall's plan: the announcement, notice waves, monthly reports, payout batches and follow-ups, with real dependencies. A payout still waiting to be accepted adds a re-notice task. The light or dark theme is loaded to match the site.
gantt/bryntum.tsbryntum/[file]/route.tsscripts/vendor-bryntum.mjs
- AG Grid
The firm's claims queue.
How it works and where it lives
AG Grid 36 for the firm's claims queue, with a photo column, the six checks on each row, quick views, a CSV export and bulk approve and pay.
- APIMatic
Generated the PayPal Server SDK that carries every Orders and Payments call.
How it works and where it lives
@paypal/paypal-server-sdk, generated by APIMatic, creates, reads and captures the sample shop's orders and replacement orders, reads captures, and refunds them to the original purchase, each as a direct call on the SDK's own controllers (ordersController.createOrder, getOrder and captureOrder; paymentsController.getCapturedPayment, refundCapturedPayment and getRefund) with one PayPal-Request-Id per attempt. Payouts, Transaction Search and Disputes are outside the SDK and use PayPal's REST API.
- Render
Hosting and Postgres.
How it works and where it lives
One Blueprint, render.yaml: the web service, a background worker that takes photo checks and payouts off the request path, a daily cron job that pulls each day's new CPSC recalls, and a managed Postgres database with the reviewed schema applied before each release.
Every PayPal API Remedy calls
9 PayPal APIs, each with one job. All run against the PayPal sandbox. Going live sets PAYPAL_ENV=live, which moves every PayPal address (the REST API, the Server SDK, the JavaScript SDK and PayPal's MCP server) to PayPal's live ones, and swaps in a live app's client ID, secret and webhook ID.
PayPal’s MCP server, read in the sandbox on November 8, 2026: get_order answered in 1,190 ms, and check C6 read the order through it (content/public/paypal-mcp-read.json, written by scripts/payments/mcp-probe.ts).
All 9 PayPal APIs, with the call and the job for each
| PayPal | Call | What it does here |
|---|---|---|
| OAuth 2.0 | POST /v1/oauth2/token | One cached access token for every call below. |
| Payouts | POST /v1/payments/payouts | Pays a verified refund to an email, a phone number or Venmo. |
| Payments v2: refund | POST /v2/payments/captures/{id}/refund | Sends the refund back to how the owner paid, inside 180 days. |
| Orders v2 | POST /v2/checkout/orders | The sample shop's purchase, and a safe replacement order. |
| JavaScript SDK v6 | web-sdk/v6/core | The PayPal button in the sample shop. |
| Transaction Search | GET /v1/reporting/transactions | Finds buyers who paid the firm with PayPal, so they can be told about the recall. |
| Disputes | GET /v1/customer/disputes | Checks that a purchase has no open dispute before it is refunded. |
| PayPal MCP server | get_order (read only) | Check C6 reads the purchase's captures and refunds from PayPal's own MCP server; the Orders API is the fallback. Only read tools can be called. |
| Webhooks | POST /v1/notifications/verify-webhook-signature | Checks PayPal's signature on every payout and refund event before it updates a payment. |
How firms connect their PayPal
A firm connects its own PayPal REST app in its console: the client ID and secret are checked with PayPal (an OAuth token request), sealed with AES-256-GCM and never shown again, and its refunds and payouts then run on that app. The sample firm pays from the platform's sandbox account. PayPal's Partner Referrals API needs an app PayPal has approved as a partner, and this sandbox app received 403 NOT_AUTHORIZED when it was tried on November 7, 2026, so firms connect their own app today.
A production rollout onboards each firm through PayPal's Partner Referrals API instead: the firm signs in on PayPal's own page and grants Remedy permission, and Remedy keeps only the firm's merchant ID. Each call for that firm then carries Remedy's own partner token with a PayPal-Auth-Assertion header naming the firm, so the money still moves on the firm's own account and no secret of the firm's is ever held.
What changes in the code
- paypal/firm-account.ts connectAccount stores the merchant ID from PayPal's onboarding return in place of a sealed client ID and secret; restForFirm builds each call with the partner token and a PayPal-Auth-Assertion header for that merchant.
- db/schema.sql The firm row's two sealed credential columns give way to one merchant ID column, as a reviewed migration.
- payments/router.ts No change: the router, the six checks and the ledger already pay through whatever account restForFirm returns.