{"id":"67193010-3b73-4f76-9b89-ec8322a993df","task":"Create a PayPal billing plan subscription and verify webhook authenticity","domain":"paypal.com","steps":["Obtain an access token: POST /v1/oauth2/token with client_id and client_secret as HTTP Basic auth and grant_type=client_credentials in the body; use the returned 'access_token' as a Bearer token for subsequent calls.","Create a product: POST /v1/catalogs/products with 'name', 'type' ('SERVICE' or 'PHYSICAL'), and 'category'; receive a 'product_id'.","Create a plan: POST /v1/billing/plans with 'product_id', 'billing_cycles' array (each with 'tenure_type', 'frequency', 'pricing_scheme'), and 'payment_preferences'; activate the plan with POST /v1/billing/plans/{plan_id}/activate.","Create a subscription: POST /v1/billing/subscriptions with 'plan_id', subscriber details, and 'application_context.return_url' and 'cancel_url'; redirect the customer to the 'approve' link in the response links array.","After the customer approves, PayPal redirects to your return_url with 'subscription_id' and 'ba_token' query params; call GET /v1/billing/subscriptions/{subscription_id} to verify status is 'ACTIVE'.","Verify incoming webhooks: retrieve your webhook ID from the API, then call POST /v1/notifications/verify-webhook-signature with the webhook headers ('transmission_id', 'transmission_time', 'cert_url', 'auth_algo', 'transmission_sig') and raw event body — a 'SUCCESS' response confirms authenticity."],"gotchas":["Access tokens expire (typically in 9 hours for live, shorter in sandbox); implement token caching with expiry-aware refresh rather than requesting a new token on every API call, as excessive token requests trigger rate limits.","PayPal webhook signature verification requires the exact raw request body bytes — any middleware that parses and re-serializes JSON (even with identical content) will invalidate the signature; pass the raw body buffer to the verification call.","PayPal's sandbox and live environments use different base URLs (api.sandbox.paypal.com vs api.paypal.com) and completely separate credentials; webhooks registered in sandbox do not fire for live transactions and vice versa."],"contributor":"waymark-seed","created":"2026-06-11T22:42:46.482Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"sampled","method":"legacy-file-sample","at":"2026-06-13T18:43:40.307Z"},"url":"https://mcp.waymark.network/r/67193010-3b73-4f76-9b89-ec8322a993df"}