Skip to content

Add paypal-invoices extension#27225

Merged
raycastbot merged 17 commits into
raycast:mainfrom
ethananderstandable:ext/paypal-invoices
May 20, 2026
Merged

Add paypal-invoices extension#27225
raycastbot merged 17 commits into
raycast:mainfrom
ethananderstandable:ext/paypal-invoices

Conversation

@ethananderstandable
Copy link
Copy Markdown
Contributor

@ethananderstandable ethananderstandable commented Apr 16, 2026

Description

Adds two commands to create and manage PayPal invoices without leaving Raycast.

Create Invoice: fill in customer name (email optional), line items with descriptions, tax name and rate, due date, note to customer, and payment options (tip, partial payment). The default action creates the invoice and copies a shareable payment link to your clipboard. If an email is provided, PayPal also notifies the client directly.

Invoice List: lists all invoices created on this machine, grouped and sorted by your preference (status, recipient, currency, or month). Live status is synced from PayPal on open. Actions per invoice include copying the link, sending to client, editing line items and tax, setting a due date, reviewing in browser, and removing from the local list.

Requires a PayPal REST API Client ID and Secret from developer.paypal.com. A sandbox mode toggle is available in preferences for testing.

Screencast

paypal-invoices-2 paypal-invoices-1

Checklist

- Add metadata screenshots, remove old media files
- Fix token cache invalidation, updateDueDate body, and payer-view URL guard
@raycastbot
Copy link
Copy Markdown
Collaborator

Congratulations on your new Raycast extension! 🚀

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

Once the PR is approved and merged, the extension will be available on our Store.

@ethananderstandable ethananderstandable marked this pull request as ready for review April 16, 2026 10:05
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 16, 2026

Greptile Summary

This PR adds a new paypal-invoices extension with two commands — Create Invoice and My Invoices — that let users draft, send, and manage PayPal invoices via the REST API without leaving Raycast.

  • Create Invoice builds a form-driven workflow for line items, tax, due date, and payment options, then creates a draft on PayPal, optionally sends it to a recipient, and copies the shareable payment link to the clipboard.
  • My Invoices lists locally-stored invoices with grouping, filtering, and sorting preferences; it syncs live status from PayPal on open, pre-fetches full invoice data for instant editing, and guards custom local statuses (UNPAID, OVERDUE) from being overwritten by PayPal's SENT response.

Confidence Score: 3/5

The extension has a validation gap in line-item quantity fields that will cause PayPal API calls to fail with no field-level feedback when the field is cleared or set to non-numeric input.

The validate() function in both Create Invoice and Edit Invoice checks name and price but never validates quantity. Submitting an empty or non-numeric quantity sends a malformed body to PayPal, which rejects it; the user only sees a generic toast error with no indication that quantity is the problem. All other previously raised issues appear to have been addressed in this revision.

extensions/paypal-invoices/src/create-invoice.tsx and extensions/paypal-invoices/src/my-invoices.tsx — both validate() functions need a quantity check added alongside the existing name/price checks.

Important Files Changed

Filename Overview
extensions/paypal-invoices/src/create-invoice.tsx Form for creating PayPal invoices; quantity field lacks validation, causing silent PayPal API failures if the field is cleared or set to a non-numeric value.
extensions/paypal-invoices/src/my-invoices.tsx Invoice list and edit forms with grouping, filtering, status sync, and prefetch cache; EditInvoiceForm's validate() also skips quantity validation.
extensions/paypal-invoices/src/paypal.ts PayPal REST API client with token caching, invoice CRUD, and status helpers; previous guard/error-handling issues appear resolved in this revision.
extensions/paypal-invoices/src/storage.ts LocalStorage layer for invoices and list preferences; saveInvoiceDetail is exported but never imported, making it dead code.
extensions/paypal-invoices/package.json Extension manifest with correct $schema, Finance category, macOS/Windows platforms, and minimal dependency on @raycast/api only.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
extensions/paypal-invoices/src/create-invoice.tsx:244-258
**Quantity field is never validated**

`validate()` checks `name` and `price` but not `quantity`. An empty or non-numeric quantity (e.g. the user clears the field) passes client-side validation, but `buildInvoiceBody` forwards the raw string `quantity: item.quantity` to PayPal. PayPal will reject the request with a 400/422, surfaced only as a generic "Failed to create invoice" toast with no field-level highlight to guide the user. The same gap exists in `EditInvoiceForm.validate()` in `my-invoices.tsx`.

### Issue 2 of 2
extensions/paypal-invoices/src/storage.ts:135-139
**`saveInvoiceDetail` is exported but never imported or called**

The function is defined and exported, but neither `create-invoice.tsx` nor `my-invoices.tsx` imports it. The codebase uses `saveAllInvoiceDetails` for bulk writes and `deleteInvoiceDetail` for cleanup instead. This is dead code that adds confusion about the intended write pattern for invoice details.

Reviews (12): Last reviewed commit: "Update CHANGELOG.md and optimise images" | Re-trigger Greptile

- Preserve UNPAID status, guard empty invoiceId, check detailResponse.ok
- Preserve UNPAID status, guard empty invoiceId, check detailResponse.ok
@ethananderstandable ethananderstandable marked this pull request as draft April 16, 2026 10:16
@ethananderstandable ethananderstandable marked this pull request as ready for review April 16, 2026 10:23
Comment thread extensions/paypal-invoices/src/create-invoice.tsx
@ethananderstandable ethananderstandable marked this pull request as draft April 16, 2026 10:29
@ethananderstandable ethananderstandable marked this pull request as ready for review April 16, 2026 10:36
Comment thread extensions/paypal-invoices/src/create-invoice.tsx
Comment thread extensions/paypal-invoices/src/my-invoices.tsx Outdated
@raycastbot
Copy link
Copy Markdown
Collaborator

This pull request has been automatically marked as stale because it did not have any recent activity.

It will be closed if no further activity occurs in the next 7 days to keep our backlog clean 😊

@raycastbot raycastbot added the status: stalled Stalled due inactivity label May 1, 2026
@ethananderstandable ethananderstandable marked this pull request as draft May 1, 2026 17:17
@ethananderstandable ethananderstandable marked this pull request as ready for review May 1, 2026 17:18
Comment thread extensions/paypal-invoices/src/my-invoices.tsx
@raycastbot raycastbot removed the status: stalled Stalled due inactivity label May 1, 2026
Comment thread extensions/paypal-invoices/src/my-invoices.tsx
Comment thread extensions/paypal-invoices/src/my-invoices.tsx
@ethananderstandable
Copy link
Copy Markdown
Contributor Author

I'm not sure if this is the right place to ask, but I wanted to check in on the status of this PR. All 10 automated checks are passing and the extension is ready for review on my end. I noticed ⁠raycastbot added a ⁠status: stalled label last week.

Is there anything I need to do from my side to move this forward, or is it simply waiting in the review queue? I want to make sure I'm not missing any steps. Thanks.

- Ignore .DS_Store
- Fix lint: remove unused imports, apply Prettier formatting
- Prefill edit form with existing invoice data, fix loading flash, optimize with local cache
Comment thread extensions/paypal-invoices/src/my-invoices.tsx
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: metadata image style

The current screenshot has local extension icon in the bottom bar

Also, you can use mock data for metadata screenshots

Could you make sure that the metadata images use the same background/appearance as the rest to maintain the same visual expression?

Reference:

Comment thread extensions/paypal-invoices/metadata/my-invoices-1.jpeg Outdated
Copy link
Copy Markdown
Contributor

@0xdhrv 0xdhrv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ethananderstandable 👋

I have added a few comments for you to address.

I'm looking forward to testing this extension again 🔥

Feel free to contact me here or at Slack if you have any questions.


I converted this PR into a draft until it's ready for the review, please press the button Ready for review when it's ready and we'll have a look 😊

@0xdhrv 0xdhrv marked this pull request as draft May 13, 2026 13:10
@0xdhrv 0xdhrv assigned 0xdhrv and unassigned 0xdhrv May 13, 2026
- Replace metadata screenshots with clean Window Capture versions
- Add development and publishing workflow to README
@ethananderstandable ethananderstandable marked this pull request as ready for review May 18, 2026 10:48
- Remove .eslintrc.js configuration file
- Update .gitignore to include additional files and directories
- Upgrade dependencies in package.json and package-lock.json
- Modify TypeScript configuration for improved module resolution
- Enhance README with clearer instructions and formatting
- Update invoice action conditions in my-invoices.tsx for better user experience
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 20, 2026

Want your agent to iterate on Greptile's feedback? Try greploops.

Copy link
Copy Markdown
Contributor

@0xdhrv 0xdhrv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, approved ✅

@raycastbot raycastbot merged commit 38af49e into raycast:main May 20, 2026
3 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

Published to the Raycast Store:
https://raycast.com/ethananderstandable/paypal-invoices

@raycastbot
Copy link
Copy Markdown
Collaborator

🎉 🎉 🎉

We've rewarded your Raycast account with some credits. You will soon be able to exchange them for some swag.

Comment on lines +244 to +258
}

async function handleCreateDraftOnly() {
if (!validate()) return;
setIsSubmitting(true);

try {
await showToast({ style: Toast.Style.Animated, title: "Saving draft…" });

const subtotal = calcSubtotal(items);
const taxAmount = taxPercent
? subtotal * (parseFloat(taxPercent) / 100)
: 0;
const total = subtotal + taxAmount;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Quantity field is never validated

validate() checks name and price but not quantity. An empty or non-numeric quantity (e.g. the user clears the field) passes client-side validation, but buildInvoiceBody forwards the raw string quantity: item.quantity to PayPal. PayPal will reject the request with a 400/422, surfaced only as a generic "Failed to create invoice" toast with no field-level highlight to guide the user. The same gap exists in EditInvoiceForm.validate() in my-invoices.tsx.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/paypal-invoices/src/create-invoice.tsx
Line: 244-258

Comment:
**Quantity field is never validated**

`validate()` checks `name` and `price` but not `quantity`. An empty or non-numeric quantity (e.g. the user clears the field) passes client-side validation, but `buildInvoiceBody` forwards the raw string `quantity: item.quantity` to PayPal. PayPal will reject the request with a 400/422, surfaced only as a generic "Failed to create invoice" toast with no field-level highlight to guide the user. The same gap exists in `EditInvoiceForm.validate()` in `my-invoices.tsx`.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants