CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/paypal-sandbox

Wraps PayPal Sandbox testing patterns: sandbox account creation (Business + Personal accounts in developer.paypal.com), the Orders v2 API (create / capture / refund), webhook event simulator (developer.paypal.com webhook simulator), sandbox-account-specific test cards, and the OAuth2 client-credentials flow for sandbox. Use when testing PayPal-integrated code.

73

Quality

92%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.md

name:
paypal-sandbox
description:
Wraps PayPal Sandbox testing patterns: sandbox account creation (Business + Personal accounts in developer.paypal.com), the Orders v2 API (create / capture / refund), webhook event simulator (developer.paypal.com webhook simulator), sandbox-account-specific test cards, and the OAuth2 client-credentials flow for sandbox. Use when testing PayPal-integrated code.

paypal-sandbox

Overview

PayPal Sandbox is a parallel environment that mirrors the prod PayPal API. Per developer.paypal.com/tools/sandbox, sandbox accounts (Business + Personal) are created in the developer dashboard; tests use sandbox client credentials.

The current canonical API is Orders v2 (developer.paypal.com/docs/api/orders/v2); older Payments API (v1) is deprecated.

When to use

  • Tests for code using PayPal Checkout (PayPal button, etc.).
  • Webhook handling.
  • OAuth-based sandbox flows.

Authoring

Setup

  1. Create developer account at developer.paypal.com.
  2. Create Business + Personal sandbox accounts (one Business for merchant; one or more Personal for buyers).
  3. Get sandbox client ID + secret.

Install

npm install @paypal/checkout-server-sdk
pip install paypalserversdk

OAuth2 client credentials

import paypal from '@paypal/checkout-server-sdk';

const env = new paypal.core.SandboxEnvironment(
  process.env.PAYPAL_SANDBOX_CLIENT_ID!,
  process.env.PAYPAL_SANDBOX_SECRET!,
);
const client = new paypal.core.PayPalHttpClient(env);

Create order

const request = new paypal.orders.OrdersCreateRequest();
request.requestBody({
  intent: 'CAPTURE',
  purchase_units: [{ amount: { currency_code: 'USD', value: '10.00' } }],
});

const order = await client.execute(request);
expect(order.result.status).toBe('CREATED');
expect(order.result.id).toBeTruthy();

Capture order (after buyer approval)

const captureRequest = new paypal.orders.OrdersCaptureRequest(order.result.id);
captureRequest.requestBody({});

const capture = await client.execute(captureRequest);
expect(capture.result.status).toBe('COMPLETED');

In test code, you need a sandbox buyer to approve the order via the PayPal checkout UI - for fully-automated tests, this requires Playwright + a sandbox Personal account login.

Sandbox test cards

Per developer.paypal.com/tools/sandbox/card-testing:

CardBehaviour
4111 1111 1111 1111Visa Sandbox success
5555 5555 5555 4444Mastercard success
4032 0359 8001 0008Decline

PayPal Sandbox is more PayPal-balance-oriented than card- oriented; sandbox buyers also have fake "PayPal balance."

Webhook simulator

Per developer.paypal.com/api/rest/webhooks/event-names: the developer dashboard exposes a Webhook Simulator that sends any event type to your registered URL.

For automated tests, use the simulator's API:

curl -X POST 'https://api-m.sandbox.paypal.com/v1/notifications/simulate-event' \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -d '{
    "url": "https://example.com/webhook",
    "event_type": "PAYMENT.CAPTURE.COMPLETED",
    ...
  }'

Webhook signature verification

Per developer.paypal.com/api/rest/webhooks/rest: PayPal webhooks include PAYPAL-TRANSMISSION-SIG and related headers; verify via PayPal's verification endpoint or local SDK helper.

import { verifyWebhookSignature } from '@paypal/checkout-server-sdk';

const isValid = await verifyWebhookSignature({
  authAlgo: headers['paypal-auth-algo'],
  certUrl: headers['paypal-cert-url'],
  transmissionId: headers['paypal-transmission-id'],
  transmissionSig: headers['paypal-transmission-sig'],
  transmissionTime: headers['paypal-transmission-time'],
  webhookId: process.env.PAYPAL_WEBHOOK_ID!,
  webhookEvent: notificationPayload,
});
expect(isValid).toBe(true);

Running

npm test

CI integration

jobs:
  paypal-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
      - run: npm ci && npm test
        env:
          PAYPAL_SANDBOX_CLIENT_ID: ${{ secrets.PAYPAL_SANDBOX_CLIENT_ID }}
          PAYPAL_SANDBOX_SECRET: ${{ secrets.PAYPAL_SANDBOX_SECRET }}

Anti-patterns

Anti-patternWhy it failsFix
Use live PayPal credentials in testsReal moneySandbox-only
Test with manual buyer approvalSlow; not CI-suitablePlaywright + sandbox buyer login
Skip webhook signature verificationSpoofableAlways verify
Hardcode sandbox account IDsFragile to account changesPer-env IDs
Test only the API pathReal flow requires checkout UIPlaywright e2e
Legacy Payments v1 APIDeprecatedMigrate to Orders v2
Treat CREATED as finalOrder needs captureTest the full lifecycle
One-shot test for refundsRefunds are asyncWait for webhook

Limitations

  • Sandbox UI is slower than prod. Playwright e2e against sandbox is flaky-prone.
  • Sandbox accounts can be rate-limited. CI parallelism may conflict.
  • Card sandbox testing less first-class than balance-based testing; PayPal expects wallet flows.
  • Webhook delivery in sandbox sometimes delayed; tests need timeouts.
  • Legacy Payments v1 still works but is deprecated; new code should use Orders v2.

References

SKILL.md

tile.json