paypal-checkout
Skill0 starsChanged 49 days agoMITView on GitHub
Accept PayPal and card payments in Laravel with PayPal Orders v2 and Smart Buttons, where the server creates and captures every order so the amount can't be tampered with. Use when adding PayPal, PayPal buttons, card checkout through PayPal, donations, or when fixing PayPal capture, amount mismatch, duplicate order or sandbox/live issues.
- Reads credentials
In this repository11 other files it gives its agents.
- bot-proof-formsSkill
- image-uploadsSkill
- inertia-admin-tablesSkill
- json-ld-structured-dataSkill
- mpesa-stk-pushSkill
- pre-push-checksSkill
- secrets-scannerSkill
- seo-crawlabilitySkill
- shared-network-rate-limitsSkill
- social-share-previewsSkill
- wordpress-migrationSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 30
Add require __DIR__.'/paypal.php'.
- Very specific: line 31
Add these keys with empty values to .env.example.
- Very specific: line 48
Don't read, print or copy the contents of .env.
- Very specific: line 52
The client secret stays on the server: Only the client ID goes in the page.
- Distinctive: line 61
Create a live app in the PayPal dashboard.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
PayPal checkout (Orders v2, server-side capture)
PayPal's Smart Buttons run in the browser, but here the server creates and captures every order. The browser can't change the amount, and a payment only counts when PayPal confirms the full amount in the right currency.
What you get
Copy each file in stubs/ to the same path in the app, dropping the .stub suffix.
| File | Purpose |
config/paypal.php | Mode, client ID and secret, currency, amount limits |
app/Support/Payments/PayPal.php | OAuth token caching, create order, capture (idempotent), paidInFull() check |
app/Http/Controllers/PayPalCheckoutController.php | Create, capture and cancel endpoints for the buttons |
routes/paypal.php | The three routes. require it from routes/web.php |
app/Models/Payment.php, app/Enums/PaymentStatus.php, migration, factory | The shared payments table (identical to the mpesa-stk-push skill's) |
resources/js/paypal-checkout.js | renderPayPalButtons(), wired to the endpoints |
tests/Feature/PayPalCheckoutTest.php | 12 Pest tests with Http::fake() |
Steps
- Copy the stubs. If
app/Models/Payment.phpalready exists frommpesa-stk-push, keep it. - Add
require __DIR__.'/paypal.php';toroutes/web.php, then runphp artisan migrate. - Add these keys with empty values to
.env.example. The owner fills in their own.env:
The owner creates the app at developer.paypal.com → Apps & Credentials. Sandbox and live have different credentials.PAYPAL_MODE=sandbox PAYPAL_CLIENT_ID= PAYPAL_CLIENT_SECRET= PAYPAL_CURRENCY=USD - Load the SDK on the checkout page with only the client ID:
https://www.paypal.com/sdk/js?client-id=...¤cy=USD&intent=capture&components=buttons - Call
renderPayPalButtons('#paypal-buttons', () => ({ amount }), onResult). - Run
php artisan test --filter=PayPal.
Agent safety
- This skill writes integration code and tests. Never start a real payment or call the live API yourself: the tests use
Http::fake(), and real charges only happen when a customer pays in the running app, in sandbox until the owner switches to live. - Never ask the user to paste keys into the chat, and never write key values into any file. Add the variable names with empty values to
.env.example; the owner sets the real values in their own.envor the host's environment settings. - Don't read, print or copy the contents of
.env.
Rules that matter
- The client secret stays on the server. Only the client ID goes in the page. Never put the secret in a
VITE_variable: Vite compiles those into public JavaScript. - Verify the capture, not the button callback.
onApproveonly means the customer clicked.PayPal::paidInFull()checks that the capturestatusisCOMPLETED, that the currency matches, and that the amount equals the payment's. APENDINGcapture (under review) is not paid. - Idempotency: the
PayPal-Request-Idheader (the payment's UUID) stops retries from creating duplicate orders. Capturing an already-captured order returnsORDER_ALREADY_CAPTURED, and the client then fetches the order instead of failing. - Never trust the browser for prices. The stub takes
amountfrom the request (donations). For orders, compute the amount server-side and link the payment throughpayable. - Cancel isn't failure. Closing the pop-up marks the payment
abandoned. If PayPal later confirms it anyway,markCompleted()still records it. shipping_preference: NO_SHIPPINGhides the address step for donations and digital goods. Remove it if you ship things.
Going live
- Create a live app in the PayPal dashboard. It needs a verified business account.
- Set
PAYPAL_MODE=livewith the live client ID and secret. The client picksapi-m.paypal.comautomatically. - The owner makes one small real payment themselves and refunds it from the PayPal dashboard.
- The owner rotates the credentials if they were ever pasted into chat, email or a commit. The
secrets-scannerskill catches committed ones.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

