@adityanair98/api-oracle 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +74 -0
- package/dist/dashboard/public/app.js +1004 -0
- package/dist/dashboard/public/index.html +142 -0
- package/dist/dashboard/public/public/app.js +1004 -0
- package/dist/dashboard/public/public/index.html +142 -0
- package/dist/dashboard/public/public/styles.css +1464 -0
- package/dist/dashboard/public/styles.css +1464 -0
- package/dist/dashboard/routes/api.d.ts +7 -0
- package/dist/dashboard/routes/api.js +245 -0
- package/dist/dashboard/server.d.ts +9 -0
- package/dist/dashboard/server.js +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +23 -0
- package/dist/knowledge/db.d.ts +22 -0
- package/dist/knowledge/db.js +182 -0
- package/dist/knowledge/schema.d.ts +275 -0
- package/dist/knowledge/schema.js +135 -0
- package/dist/knowledge/scorer.d.ts +63 -0
- package/dist/knowledge/scorer.js +314 -0
- package/dist/knowledge/search.d.ts +37 -0
- package/dist/knowledge/search.js +111 -0
- package/dist/knowledge/synonyms.d.ts +36 -0
- package/dist/knowledge/synonyms.js +523 -0
- package/dist/knowledge/tfidf.d.ts +42 -0
- package/dist/knowledge/tfidf.js +138 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +40 -0
- package/dist/tools/check-freshness.d.ts +9 -0
- package/dist/tools/check-freshness.js +95 -0
- package/dist/tools/compare-apis.d.ts +8 -0
- package/dist/tools/compare-apis.js +149 -0
- package/dist/tools/find-api.d.ts +9 -0
- package/dist/tools/find-api.js +120 -0
- package/dist/tools/get-setup-guide.d.ts +8 -0
- package/dist/tools/get-setup-guide.js +127 -0
- package/dist/updater/linter.d.ts +31 -0
- package/dist/updater/linter.js +219 -0
- package/dist/updater/report.d.ts +29 -0
- package/dist/updater/report.js +96 -0
- package/dist/updater/staleness.d.ts +39 -0
- package/dist/updater/staleness.js +66 -0
- package/dist/updater/version-tracker.d.ts +28 -0
- package/dist/updater/version-tracker.js +50 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +13 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.js +32 -0
- package/package.json +56 -0
- package/src/entries/ai/anthropic.json +95 -0
- package/src/entries/ai/eleven-labs.json +90 -0
- package/src/entries/ai/openai.json +95 -0
- package/src/entries/ai/replicate.json +87 -0
- package/src/entries/ai/resemble-ai.json +88 -0
- package/src/entries/ai/stability-ai.json +89 -0
- package/src/entries/analytics/posthog.json +88 -0
- package/src/entries/analytics/sentry.json +84 -0
- package/src/entries/auth/auth0.json +90 -0
- package/src/entries/auth/clerk.json +95 -0
- package/src/entries/cms/contentful.json +92 -0
- package/src/entries/cms/sanity.json +92 -0
- package/src/entries/cms/strapi.json +93 -0
- package/src/entries/commerce/medusa.json +91 -0
- package/src/entries/commerce/shopify-api.json +91 -0
- package/src/entries/communication/sendbird.json +85 -0
- package/src/entries/communication/stream-chat.json +94 -0
- package/src/entries/database/firebase.json +88 -0
- package/src/entries/database/neon.json +94 -0
- package/src/entries/database/planetscale.json +95 -0
- package/src/entries/database/supabase.json +94 -0
- package/src/entries/database/upstash.json +94 -0
- package/src/entries/devops/fly-io.json +90 -0
- package/src/entries/devops/netlify.json +90 -0
- package/src/entries/devops/railway.json +90 -0
- package/src/entries/devops/vercel.json +90 -0
- package/src/entries/email/mailgun.json +91 -0
- package/src/entries/email/postmark.json +91 -0
- package/src/entries/email/resend.json +89 -0
- package/src/entries/email/sendgrid.json +90 -0
- package/src/entries/forms/formspark.json +85 -0
- package/src/entries/forms/typeform.json +98 -0
- package/src/entries/infrastructure/aws-s3.json +104 -0
- package/src/entries/infrastructure/cloudflare-r2.json +92 -0
- package/src/entries/infrastructure/cloudflare-workers.json +92 -0
- package/src/entries/infrastructure/digital-ocean-spaces.json +87 -0
- package/src/entries/integration/nango.json +90 -0
- package/src/entries/integration/zapier.json +92 -0
- package/src/entries/maps/google-maps.json +89 -0
- package/src/entries/maps/mapbox.json +87 -0
- package/src/entries/media/deepgram.json +84 -0
- package/src/entries/media/imgix.json +84 -0
- package/src/entries/media/mux.json +94 -0
- package/src/entries/messaging/ably.json +94 -0
- package/src/entries/messaging/pusher.json +94 -0
- package/src/entries/messaging/twilio.json +94 -0
- package/src/entries/messaging/vonage.json +89 -0
- package/src/entries/notifications/knock.json +84 -0
- package/src/entries/notifications/novu.json +84 -0
- package/src/entries/notifications/onesignal.json +84 -0
- package/src/entries/payments/lemonsqueezy.json +91 -0
- package/src/entries/payments/paddle.json +90 -0
- package/src/entries/payments/paypal.json +91 -0
- package/src/entries/payments/razorpay.json +85 -0
- package/src/entries/payments/square.json +91 -0
- package/src/entries/payments/stripe.json +96 -0
- package/src/entries/scheduling/cal-com.json +90 -0
- package/src/entries/scheduling/calendly.json +90 -0
- package/src/entries/search/algolia.json +96 -0
- package/src/entries/security/arcjet.json +89 -0
- package/src/entries/security/snyk.json +90 -0
- package/src/entries/storage/cloudinary.json +93 -0
- package/src/entries/storage/uploadthing.json +90 -0
- package/src/entries/testing/browserstack.json +86 -0
- package/src/entries/testing/checkly.json +89 -0
- package/src/entries/workflow/inngest.json +88 -0
- package/src/entries/workflow/temporal.json +90 -0
- package/src/entries/workflow/trigger-dev.json +89 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "PayPal",
|
|
3
|
+
"slug": "paypal",
|
|
4
|
+
"category": "payments",
|
|
5
|
+
"subcategory": "payment-processing",
|
|
6
|
+
"website": "https://developer.paypal.com",
|
|
7
|
+
"description": "PayPal is one of the world's most widely recognized payment platforms, supporting 400M+ active accounts. While not the best developer experience compared to Stripe, PayPal's ubiquity means many customers — especially in B2C markets — prefer or require it. Supports credit/debit cards, PayPal balance, PayPal Credit, Venmo (US), and Buy Now Pay Later via its REST API.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Accept PayPal payments from customers who prefer PayPal over credit cards",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Offer Buy Now Pay Later (BNPL) as a checkout option",
|
|
15
|
+
"fit": "good"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Accept international payments in 100+ currencies",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Process payments on a marketplace with seller payouts",
|
|
23
|
+
"fit": "partial"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "oauth2",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a PayPal Developer account at developer.paypal.com",
|
|
30
|
+
"Go to My Apps & Credentials and create a new app",
|
|
31
|
+
"Copy your Client ID and Client Secret from the app details page",
|
|
32
|
+
"Use the Sandbox credentials for development and testing",
|
|
33
|
+
"Authenticate by POSTing to /v1/oauth2/token with client_credentials grant to receive a Bearer token",
|
|
34
|
+
"Swap to Live credentials in production by updating PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "PAYPAL_CLIENT_ID",
|
|
37
|
+
"codeSnippet": "import { Client, Environment } from '@paypal/paypal-server-sdk';\n\nconst client = new Client({\n clientCredentialsAuthCredentials: {\n oAuthClientId: process.env.PAYPAL_CLIENT_ID!,\n oAuthClientSecret: process.env.PAYPAL_CLIENT_SECRET!,\n },\n environment: Environment.Sandbox, // Use Environment.Production for live\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "usage_based",
|
|
41
|
+
"freeTier": null,
|
|
42
|
+
"startingPrice": "2.99% per transaction (PayPal Commerce Platform)",
|
|
43
|
+
"costPer": "2.99% domestic card transactions; 3.49% + $0.49 for PayPal digital payments; additional 1.5% for international transactions",
|
|
44
|
+
"pricingUrl": "https://www.paypal.com/us/webapps/mpp/merchant-fees"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "standard",
|
|
48
|
+
"limit": "Not publicly documented — throttling occurs under heavy load",
|
|
49
|
+
"notes": "PayPal's API reliability is inconsistent. Implement generous timeouts (10-30s) and retry logic. The Orders API v2 is more reliable than older NVP/SOAP APIs.",
|
|
50
|
+
"retryStrategy": "Use idempotency-request-id header on POST requests. Retry on 429 and 5xx with exponential backoff (start at 1s, max 32s)."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact @paypal/paypal-server-sdk",
|
|
55
|
+
"importStatement": "import { Client, OrdersController } from '@paypal/paypal-server-sdk';",
|
|
56
|
+
"otherLanguages": ["python", "java", "php", "ruby"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Create a PayPal order",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "import { Client, Environment, OrdersController, CheckoutPaymentIntent } from '@paypal/paypal-server-sdk';\n\nconst client = new Client({\n clientCredentialsAuthCredentials: {\n oAuthClientId: process.env.PAYPAL_CLIENT_ID!,\n oAuthClientSecret: process.env.PAYPAL_CLIENT_SECRET!,\n },\n environment: Environment.Sandbox,\n});\n\nconst ordersController = new OrdersController(client);\n\n// Create an order and get the approval URL\nconst { body: order } = await ordersController.ordersCreate({\n body: {\n intent: CheckoutPaymentIntent.Capture,\n purchaseUnits: [\n {\n amount: {\n currencyCode: 'USD',\n value: '20.00',\n },\n description: 'Pro Plan Subscription',\n referenceId: 'order_123',\n },\n ],\n applicationContext: {\n returnUrl: 'https://yourapp.com/checkout/success',\n cancelUrl: 'https://yourapp.com/checkout/cancel',\n brandName: 'Your App',\n userAction: 'PAY_NOW',\n },\n },\n prefer: 'return=representation',\n});\n\n// Find the approval URL to redirect the customer\nconst approvalLink = order.links?.find((link) => link.rel === 'approve');\nconsole.log('Redirect customer to:', approvalLink?.href);\nconsole.log('Order ID:', order.id);",
|
|
63
|
+
"notes": "Redirect the customer to the approval URL returned in order.links where rel === 'approve'. After the customer approves, PayPal redirects them to your returnUrl with the token and PayerID query params. Use the order.id to capture the payment in the next step."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"title": "Capture payment after customer approval",
|
|
67
|
+
"language": "typescript",
|
|
68
|
+
"code": "import { Client, Environment, OrdersController } from '@paypal/paypal-server-sdk';\n\nconst client = new Client({\n clientCredentialsAuthCredentials: {\n oAuthClientId: process.env.PAYPAL_CLIENT_ID!,\n oAuthClientSecret: process.env.PAYPAL_CLIENT_SECRET!,\n },\n environment: Environment.Sandbox,\n});\n\nconst ordersController = new OrdersController(client);\n\n// orderId comes from query param ?token= on your returnUrl\nasync function capturePayPalOrder(orderId: string): Promise<void> {\n const idempotencyKey = `capture-${orderId}-${Date.now()}`;\n\n const { body: captureResult, statusCode } = await ordersController.ordersCapture({\n id: orderId,\n prefer: 'return=representation',\n paypalRequestId: idempotencyKey, // Idempotency key for safe retries\n });\n\n if (statusCode !== 201) {\n console.error('Capture failed with status:', statusCode);\n throw new Error(`PayPal capture failed: ${statusCode}`);\n }\n\n const captureStatus = captureResult.status;\n const captureId = captureResult.purchaseUnits?.[0]?.payments?.captures?.[0]?.id;\n\n if (captureStatus === 'COMPLETED') {\n console.log('Payment captured successfully. Capture ID:', captureId);\n // Fulfill the order — provision access, send confirmation email, etc.\n await fulfillOrder(orderId, captureId!);\n } else {\n console.warn('Unexpected capture status:', captureStatus);\n }\n}\n\nasync function fulfillOrder(orderId: string, captureId: string) {\n // Your order fulfillment logic here\n}",
|
|
69
|
+
"notes": "Always use a stable idempotency key (paypalRequestId) on capture requests so that network retries do not result in double captures. The capture ID in purchaseUnits[0].payments.captures[0].id is the PayPal transaction reference you should store for refunds and disputes."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"gotchas": [
|
|
73
|
+
"PayPal's developer documentation is notoriously fragmented — there are 4+ different API versions (NVP, SOAP, v1, v2) and multiple SDKs. Always use the Orders API v2 and the @paypal/paypal-server-sdk. Ignore any tutorial using nvp, soap, or the deprecated REST SDK (@paypal/checkout-server-sdk).",
|
|
74
|
+
"PayPal accounts get frozen without warning for 'suspicious activity', often during legitimate high-volume periods. If PayPal is your only payment processor, this can stop your business. Always offer an alternative like Stripe.",
|
|
75
|
+
"PayPal's sandbox and production environments are completely separate tenants. Sandbox buyer accounts must be created manually in the Developer Dashboard — you cannot use real PayPal accounts for testing. Sandbox behavior sometimes differs from production.",
|
|
76
|
+
"The PayPal checkout button opens a popup window. Many ad blockers and privacy browsers (Brave, Firefox with strict mode) block popups by default, which breaks the checkout flow entirely for those users."
|
|
77
|
+
],
|
|
78
|
+
"reliability": {
|
|
79
|
+
"uptimeGuarantee": "99.9% uptime SLA for Commerce Platform",
|
|
80
|
+
"statusPageUrl": "https://www.paypal-status.com",
|
|
81
|
+
"notes": "Globally distributed with 400M+ users. API reliability is less consistent than Stripe — implement generous timeouts and retry logic. Historical outages have impacted checkout flows."
|
|
82
|
+
},
|
|
83
|
+
"qualityScore": 6,
|
|
84
|
+
"qualityJustification": "PayPal's ubiquity (400M+ accounts) makes it a necessary evil for many businesses — some customers won't buy without it. However, developer experience is poor (fragmented docs, inconsistent APIs), account freezes are a real risk, and the fee structure is complex. Use as a supplementary payment method alongside Stripe, not as a replacement.",
|
|
85
|
+
"alternatives": ["stripe", "razorpay", "square"],
|
|
86
|
+
"complementary": ["stripe", "resend"],
|
|
87
|
+
"bestFor": "Offering PayPal as a supplementary checkout option for customers who prefer PayPal over credit cards — not recommended as a primary payment processor",
|
|
88
|
+
"lastVerified": "2026-02-25",
|
|
89
|
+
"entryVersion": 1,
|
|
90
|
+
"addedBy": "claude-code-session-4"
|
|
91
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Razorpay",
|
|
3
|
+
"slug": "razorpay",
|
|
4
|
+
"category": "payments",
|
|
5
|
+
"subcategory": "payment-processing",
|
|
6
|
+
"website": "https://razorpay.com",
|
|
7
|
+
"description": "Razorpay is India's leading payment gateway, providing a complete payment suite that supports UPI, Netbanking, credit/debit cards, wallets, and EMI — the full spectrum of Indian payment methods. It is the go-to choice for businesses targeting Indian consumers.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Accept payments in India with UPI, Netbanking, and cards",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Process Indian payments including UPI and local wallets",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Build subscription billing for Indian customers",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Accept international credit card payments globally",
|
|
23
|
+
"fit": "partial"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "basic_auth",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Sign up at razorpay.com with a valid Indian business",
|
|
30
|
+
"Complete KYC verification (PAN card, bank account details)",
|
|
31
|
+
"Go to Settings > API Keys",
|
|
32
|
+
"Generate your Key ID and Key Secret",
|
|
33
|
+
"Set RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET environment variables",
|
|
34
|
+
"Use test mode keys (rzp_test_*) for development"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "RAZORPAY_KEY_SECRET",
|
|
37
|
+
"codeSnippet": "import Razorpay from 'razorpay';\nconst razorpay = new Razorpay({\n key_id: process.env.RAZORPAY_KEY_ID!,\n key_secret: process.env.RAZORPAY_KEY_SECRET!,\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "usage_based",
|
|
41
|
+
"freeTier": "No monthly fee — transaction fees only",
|
|
42
|
+
"startingPrice": "2% per transaction (domestic Indian payments)",
|
|
43
|
+
"costPer": "2% for domestic cards/UPI/Netbanking; 3% for international cards; GST additional",
|
|
44
|
+
"pricingUrl": "https://razorpay.com/pricing"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "all tiers",
|
|
48
|
+
"limit": "No published hard API rate limit; practical limit varies by plan",
|
|
49
|
+
"notes": "Razorpay enforces limits per account tier. High-volume merchants should contact Razorpay for custom limits.",
|
|
50
|
+
"retryStrategy": "Use idempotency keys for order creation; retry failed requests with exponential backoff"
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact razorpay",
|
|
55
|
+
"importStatement": "import Razorpay from 'razorpay';",
|
|
56
|
+
"otherLanguages": ["python", "java", "php", "ruby", "go"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Create an order and accept payment",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "import Razorpay from 'razorpay';\nimport crypto from 'crypto';\n\nconst razorpay = new Razorpay({\n key_id: process.env.RAZORPAY_KEY_ID!,\n key_secret: process.env.RAZORPAY_KEY_SECRET!,\n});\n\n// Step 1: Create order (server-side)\nconst order = await razorpay.orders.create({\n amount: 50000, // Amount in paise (₹500.00)\n currency: 'INR',\n receipt: 'order_receipt_123',\n});\n\n// Step 2: Verify payment signature (after frontend completes payment)\nfunction verifyPayment(orderId: string, paymentId: string, signature: string): boolean {\n const body = `${orderId}|${paymentId}`;\n const expectedSignature = crypto\n .createHmac('sha256', process.env.RAZORPAY_KEY_SECRET!)\n .update(body)\n .digest('hex');\n return expectedSignature === signature;\n}\n\nconsole.log('Order created:', order.id);",
|
|
63
|
+
"notes": "Amount is in paise (smallest INR unit). ₹500 = 50000 paise. Always verify the payment signature server-side before fulfilling orders."
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"gotchas": [
|
|
67
|
+
"Amount is in paise, not rupees — ₹100 = 10000 paise. This is a common source of 100x pricing errors in production.",
|
|
68
|
+
"KYC verification is mandatory and can take 2-5 business days. Plan for this in your launch timeline — you cannot accept live payments without completing KYC.",
|
|
69
|
+
"Always verify the payment signature (HMAC-SHA256) server-side after the frontend receives razorpay_payment_id. Skipping this step allows anyone to fake a successful payment.",
|
|
70
|
+
"Razorpay is primarily built for Indian businesses with Indian bank accounts. International businesses face significant friction during onboarding and may be rejected."
|
|
71
|
+
],
|
|
72
|
+
"reliability": {
|
|
73
|
+
"uptimeGuarantee": "99.9% uptime SLA",
|
|
74
|
+
"statusPageUrl": "https://status.razorpay.com",
|
|
75
|
+
"notes": "Razorpay processes a significant percentage of India's digital payments. Infrastructure is robust but primarily India-focused."
|
|
76
|
+
},
|
|
77
|
+
"qualityScore": 8,
|
|
78
|
+
"qualityJustification": "The best and most comprehensive solution for Indian payments with excellent UPI support. TypeScript SDK is solid. Primary limitation is geographic scope — this is an India-first solution. The KYC requirement adds onboarding time.",
|
|
79
|
+
"alternatives": ["stripe", "paypal", "square"],
|
|
80
|
+
"complementary": ["resend", "clerk"],
|
|
81
|
+
"bestFor": "Payments for Indian consumers — UPI, Netbanking, wallets, and local cards all in one API",
|
|
82
|
+
"lastVerified": "2026-02-25",
|
|
83
|
+
"entryVersion": 1,
|
|
84
|
+
"addedBy": "claude-code-session-1"
|
|
85
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Square",
|
|
3
|
+
"slug": "square",
|
|
4
|
+
"category": "payments",
|
|
5
|
+
"subcategory": "payment-processing",
|
|
6
|
+
"website": "https://developer.squareup.com",
|
|
7
|
+
"description": "Square provides unified payment processing for both in-person (POS hardware) and online payments through a single API. Particularly strong for retail and restaurant businesses that need both physical terminals and an online store. The Developer API allows custom POS integrations, online checkout, and appointment booking.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Accept in-person payments with a POS integration",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Build a unified online + in-person payment system",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Process online payments for a retail or restaurant business",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Integrate appointment booking with payment collection",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "oauth2",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Square Developer account at developer.squareup.com",
|
|
30
|
+
"Create a new Application in the Developer Dashboard",
|
|
31
|
+
"For single-merchant use, copy your personal access token from the Credentials tab",
|
|
32
|
+
"For multi-merchant marketplace apps, implement the full OAuth 2.0 authorization code flow",
|
|
33
|
+
"Use Sandbox credentials and the Sandbox base URL for development",
|
|
34
|
+
"Switch to Production credentials when ready to go live"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "SQUARE_ACCESS_TOKEN",
|
|
37
|
+
"codeSnippet": "import { Client, Environment } from 'square';\n\nconst client = new Client({\n accessToken: process.env.SQUARE_ACCESS_TOKEN!,\n environment: Environment.Sandbox, // Use Environment.Production for live\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "freemium",
|
|
41
|
+
"freeTier": "Free developer account with sandbox; in-person: 2.6% + $0.10/tap, dip, swipe; online: 2.9% + $0.30",
|
|
42
|
+
"startingPrice": "No monthly fee — pay per transaction only",
|
|
43
|
+
"costPer": "In-person: 2.6% + $0.10; Online: 2.9% + $0.30; Manually keyed: 3.5% + $0.15; Keyed-in card-not-present: 3.5% + $0.15",
|
|
44
|
+
"pricingUrl": "https://squareup.com/us/en/payments/our-rates"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "standard",
|
|
48
|
+
"limit": "15 requests/second per application, 100 calls/minute for some endpoints",
|
|
49
|
+
"notes": "Rate limits vary by endpoint. Catalog and inventory endpoints have tighter limits. Use batch endpoints for bulk operations.",
|
|
50
|
+
"retryStrategy": "Respect Retry-After headers on 429 responses. Use batch endpoints (BatchUpsertCatalogObjects) to reduce API calls."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact square",
|
|
55
|
+
"importStatement": "import { Client, Environment } from 'square';",
|
|
56
|
+
"otherLanguages": ["python", "java", "php", "ruby"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Create a payment link for online checkout",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "import { Client, Environment } from 'square';\nimport { randomUUID } from 'crypto';\n\nconst client = new Client({\n accessToken: process.env.SQUARE_ACCESS_TOKEN!,\n environment: Environment.Sandbox,\n});\n\nconst { checkoutApi } = client;\n\n// Create a payment link for a quick sale\nconst { result, statusCode } = await checkoutApi.createPaymentLink({\n idempotencyKey: randomUUID(),\n quickPay: {\n name: 'Pro Plan Subscription',\n priceMoney: {\n amount: BigInt(2000), // Amount in cents — must be BigInt in the Square SDK\n currency: 'USD',\n },\n locationId: process.env.SQUARE_LOCATION_ID!,\n },\n checkoutOptions: {\n redirectUrl: 'https://yourapp.com/checkout/success',\n askForShippingAddress: false,\n },\n prePopulatedData: {\n buyerEmail: 'customer@example.com',\n },\n});\n\nif (result.errors && result.errors.length > 0) {\n console.error('Square API errors:', result.errors);\n throw new Error(result.errors.map((e) => e.detail).join(', '));\n}\n\nconst paymentLink = result.paymentLink;\nconsole.log('Payment link URL:', paymentLink?.url);\nconsole.log('Payment link ID:', paymentLink?.id);\n// Redirect the customer to paymentLink.url",
|
|
63
|
+
"notes": "Note that monetary amounts are BigInt in the Square TypeScript SDK, not number. Use BigInt(2000) for $20.00. JSON.stringify() will throw on BigInt — use String(amount) or a custom replacer when serializing. Always check result.errors before accessing result.paymentLink."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"title": "Create a catalog item with pricing",
|
|
67
|
+
"language": "typescript",
|
|
68
|
+
"code": "import { Client, Environment, CatalogObjectType } from 'square';\nimport { randomUUID } from 'crypto';\n\nconst client = new Client({\n accessToken: process.env.SQUARE_ACCESS_TOKEN!,\n environment: Environment.Sandbox,\n});\n\nconst { catalogApi } = client;\n\n// Create a catalog item (e.g., a menu item) with a price variation\nconst itemId = `#item-${randomUUID()}`;\nconst variationId = `#variation-${randomUUID()}`;\n\nconst { result, statusCode } = await catalogApi.upsertCatalogObject({\n idempotencyKey: randomUUID(),\n object: {\n type: CatalogObjectType.Item,\n id: itemId,\n itemData: {\n name: 'Espresso',\n description: 'Double shot espresso',\n variations: [\n {\n type: CatalogObjectType.ItemVariation,\n id: variationId,\n itemVariationData: {\n itemId: itemId,\n name: 'Regular',\n pricingType: 'FIXED_PRICING',\n priceMoney: {\n amount: BigInt(350), // $3.50 — must be BigInt\n currency: 'USD',\n },\n trackInventory: false,\n },\n },\n ],\n },\n },\n});\n\nif (result.errors && result.errors.length > 0) {\n console.error('Failed to create catalog item:', result.errors);\n throw new Error(result.errors.map((e) => e.detail).join(', '));\n}\n\nconst createdItem = result.catalogObject;\nconsole.log('Created catalog item ID:', createdItem?.id);\nconsole.log('Variation ID:', createdItem?.itemData?.variations?.[0]?.id);",
|
|
69
|
+
"notes": "Catalog item IDs starting with # are client-assigned temporary IDs for batch operations — Square replaces them with server-assigned IDs in the response. Store the server-assigned IDs for future API calls. All price amounts are BigInt. The Square SDK does not throw on API errors — always inspect result.errors explicitly."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"gotchas": [
|
|
73
|
+
"Square's availability is limited to US, Canada, UK, Australia, and Japan. If your business or customers are in other countries (EU, Asia outside Japan, Latin America), Square will not work. Use Stripe or Adyen instead.",
|
|
74
|
+
"Square uses BigInt for monetary amounts — all prices are in the smallest currency unit (cents) as a BigInt in the TypeScript SDK, not a number. JSON.stringify() does not serialize BigInt by default, causing runtime errors. Use String(amount) or a custom replacer.",
|
|
75
|
+
"The Square SDK uses a non-standard async pattern with response objects — it does not throw errors on API failures by default. Always check result.result and result.statusCode. Errors are in result.errors, not in a thrown exception.",
|
|
76
|
+
"Square's OAuth flow is designed for marketplace apps where you access multiple merchants' accounts. For single-merchant apps (your own Square account), use a personal access token — much simpler than implementing the full OAuth flow."
|
|
77
|
+
],
|
|
78
|
+
"reliability": {
|
|
79
|
+
"uptimeGuarantee": "99.9% uptime",
|
|
80
|
+
"statusPageUrl": "https://issquareup.com",
|
|
81
|
+
"notes": "US-headquartered with global card processing infrastructure. In-person payment processing is handled locally on Square hardware, providing resilience even during partial API outages."
|
|
82
|
+
},
|
|
83
|
+
"qualityScore": 7,
|
|
84
|
+
"qualityJustification": "Best choice for businesses that need unified in-person and online payment processing under a single API and settlement. The hardware ecosystem (Terminal, Register) is polished. However, geographic limitations (US/CA/UK/AU/JP only) and the BigInt SDK quirks reduce its appeal for pure online-only businesses.",
|
|
85
|
+
"alternatives": ["stripe", "razorpay", "paypal"],
|
|
86
|
+
"complementary": ["resend", "supabase"],
|
|
87
|
+
"bestFor": "Businesses needing unified in-person and online payment processing — retail, restaurants, and appointment-based services in the US, Canada, UK, Australia, and Japan",
|
|
88
|
+
"lastVerified": "2026-02-25",
|
|
89
|
+
"entryVersion": 1,
|
|
90
|
+
"addedBy": "claude-code-session-4"
|
|
91
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Stripe",
|
|
3
|
+
"slug": "stripe",
|
|
4
|
+
"category": "payments",
|
|
5
|
+
"subcategory": "payment-processing",
|
|
6
|
+
"website": "https://stripe.com",
|
|
7
|
+
"description": "Stripe is the global standard for online payment processing, offering a comprehensive suite of APIs for accepting payments, managing subscriptions, handling payouts, and building financial products. Its developer-first design and extensive documentation make it the default choice for SaaS, e-commerce, and marketplace applications.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Accept credit card and debit card payments online",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Build subscription billing with recurring payments",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Create a marketplace with split payments and payouts",
|
|
19
|
+
"fit": "perfect"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Handle one-time payments with a checkout page",
|
|
23
|
+
"fit": "perfect"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"task": "Process payments in emerging markets like India",
|
|
27
|
+
"fit": "partial"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"auth": {
|
|
31
|
+
"method": "api_key",
|
|
32
|
+
"setupSteps": [
|
|
33
|
+
"Sign up at stripe.com",
|
|
34
|
+
"In the Dashboard, go to Developers > API Keys",
|
|
35
|
+
"Copy your Publishable key and Secret key",
|
|
36
|
+
"Use test keys (starting with pk_test_ and sk_test_) for development",
|
|
37
|
+
"Set STRIPE_SECRET_KEY and STRIPE_PUBLISHABLE_KEY environment variables",
|
|
38
|
+
"Enable live mode and add bank account details before going to production"
|
|
39
|
+
],
|
|
40
|
+
"envVarName": "STRIPE_SECRET_KEY",
|
|
41
|
+
"codeSnippet": "import Stripe from 'stripe';\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);"
|
|
42
|
+
},
|
|
43
|
+
"pricing": {
|
|
44
|
+
"model": "usage_based",
|
|
45
|
+
"freeTier": "No monthly fee — pay per transaction only",
|
|
46
|
+
"startingPrice": "2.9% + $0.30 per successful card charge (US)",
|
|
47
|
+
"costPer": "2.9% + $0.30 per transaction; additional fees for international cards, currency conversion",
|
|
48
|
+
"pricingUrl": "https://stripe.com/pricing"
|
|
49
|
+
},
|
|
50
|
+
"rateLimits": {
|
|
51
|
+
"tier": "all tiers",
|
|
52
|
+
"limit": "100 read requests/second, 100 write requests/second per secret key",
|
|
53
|
+
"notes": "Rate limits are per API key. Live mode has higher limits than test mode. Rate limit headers (Stripe-RateLimit-*) are included in responses.",
|
|
54
|
+
"retryStrategy": "Stripe recommends idempotency keys for write operations to safely retry on network failures; use exponential backoff for 429 responses"
|
|
55
|
+
},
|
|
56
|
+
"sdk": {
|
|
57
|
+
"primaryLanguage": "typescript",
|
|
58
|
+
"installCommand": "npm install --save-exact stripe",
|
|
59
|
+
"importStatement": "import Stripe from 'stripe';",
|
|
60
|
+
"otherLanguages": ["python", "ruby", "java", "go", "php", "dotnet"]
|
|
61
|
+
},
|
|
62
|
+
"codeExamples": [
|
|
63
|
+
{
|
|
64
|
+
"title": "Create a payment intent (server-side)",
|
|
65
|
+
"language": "typescript",
|
|
66
|
+
"code": "import Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n// Create a PaymentIntent on your server\nconst paymentIntent = await stripe.paymentIntents.create({\n amount: 2000, // Amount in cents ($20.00)\n currency: 'usd',\n automatic_payment_methods: { enabled: true },\n metadata: { orderId: 'order_123' },\n});\n\n// Return client_secret to the frontend\nconsole.log('Client secret:', paymentIntent.client_secret);",
|
|
67
|
+
"notes": "Always create PaymentIntents server-side. Never expose your secret key to the client. Use the client_secret to confirm payment client-side with Stripe.js."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"title": "Create a Checkout Session (no-code payment page)",
|
|
71
|
+
"language": "typescript",
|
|
72
|
+
"code": "import Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\nconst session = await stripe.checkout.sessions.create({\n payment_method_types: ['card'],\n line_items: [{\n price_data: {\n currency: 'usd',\n product_data: { name: 'Pro Plan' },\n unit_amount: 2000,\n recurring: { interval: 'month' },\n },\n quantity: 1,\n }],\n mode: 'subscription',\n success_url: 'https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}',\n cancel_url: 'https://yourapp.com/cancel',\n});\n\nconsole.log('Checkout URL:', session.url);",
|
|
73
|
+
"notes": "Checkout Sessions handle the entire payment UI. Redirect users to session.url. Stripe handles PCI compliance automatically."
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"gotchas": [
|
|
77
|
+
"Always use idempotency keys for write requests (charge, PaymentIntent creation) to safely retry on network failures without double-charging. Pass `idempotencyKey` in the request options.",
|
|
78
|
+
"Stripe's test mode and live mode use completely separate API keys and data — test customers, cards, and charges do not carry over to live mode.",
|
|
79
|
+
"Webhook signature verification is mandatory for security. Never trust webhook payloads without verifying the Stripe-Signature header using stripe.webhooks.constructEvent().",
|
|
80
|
+
"Amount is always in the smallest currency unit (cents for USD, pence for GBP). $20.00 = 2000, not 20.",
|
|
81
|
+
"Stripe is not available in all countries. For India-specific payments with UPI and local cards, Razorpay is often a better choice."
|
|
82
|
+
],
|
|
83
|
+
"reliability": {
|
|
84
|
+
"uptimeGuarantee": "99.99% uptime SLA for core payment APIs",
|
|
85
|
+
"statusPageUrl": "https://status.stripe.com",
|
|
86
|
+
"notes": "Stripe's infrastructure is battle-tested at global scale. Automatic retries, redundant infrastructure, and SOC 2 Type II certified."
|
|
87
|
+
},
|
|
88
|
+
"qualityScore": 10,
|
|
89
|
+
"qualityJustification": "The gold standard for payment APIs. Unmatched documentation, TypeScript support that is genuinely excellent, comprehensive feature set (subscriptions, marketplaces, Connect, billing), and a test mode that mirrors production perfectly. The only reason to use something else is geographic availability.",
|
|
90
|
+
"alternatives": ["razorpay", "lemonsqueezy", "paddle", "paypal", "square"],
|
|
91
|
+
"complementary": ["resend", "clerk", "auth0"],
|
|
92
|
+
"bestFor": "Online payment processing for SaaS subscriptions, e-commerce, and marketplaces in the US, EU, and most global markets",
|
|
93
|
+
"lastVerified": "2026-02-25",
|
|
94
|
+
"entryVersion": 1,
|
|
95
|
+
"addedBy": "claude-code-session-1"
|
|
96
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Cal.com",
|
|
3
|
+
"slug": "cal-com",
|
|
4
|
+
"category": "scheduling",
|
|
5
|
+
"subcategory": "appointment-scheduling",
|
|
6
|
+
"website": "https://cal.com",
|
|
7
|
+
"description": "Cal.com is an open source scheduling platform and Calendly alternative with a developer API. Self-host for free or use Cal.com Cloud. The API allows creating event types, managing bookings, and embedding scheduling widgets. Deeply customizable with a strong focus on developer control and white-labeling.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Embed a scheduling widget for booking appointments or meetings",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Manage and query bookings programmatically via API",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Build a white-labeled scheduling product on top of Cal.com",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Set up automated scheduling workflows (create events, cancel, reschedule)",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Cal.com account at cal.com (or self-host the open source version)",
|
|
30
|
+
"Go to Settings in the top-right menu",
|
|
31
|
+
"Navigate to Developer → API Keys",
|
|
32
|
+
"Click 'Add' to create a new API key, optionally set an expiry date",
|
|
33
|
+
"Copy the generated API key and set the CAL_API_KEY environment variable"
|
|
34
|
+
],
|
|
35
|
+
"envVarName": "CAL_API_KEY",
|
|
36
|
+
"codeSnippet": "const response = await fetch('https://api.cal.com/v2/me', {\n headers: {\n Authorization: `Bearer ${process.env.CAL_API_KEY}`,\n 'cal-api-version': '2024-08-13',\n },\n});\nconst data = await response.json();\nconsole.log('Cal.com user:', data);"
|
|
37
|
+
},
|
|
38
|
+
"pricing": {
|
|
39
|
+
"model": "freemium",
|
|
40
|
+
"freeTier": "Free: Cal.com Cloud individual plan with unlimited scheduling. Open source self-hosted: free forever.",
|
|
41
|
+
"startingPrice": "$12/user/month (Teams) for team scheduling, routing, and admin features",
|
|
42
|
+
"costPer": null,
|
|
43
|
+
"pricingUrl": "https://cal.com/pricing"
|
|
44
|
+
},
|
|
45
|
+
"rateLimits": {
|
|
46
|
+
"tier": "free tier",
|
|
47
|
+
"limit": "REST API: rate limits not published; Cloud free tier: 1,000 API calls/month (estimated)",
|
|
48
|
+
"notes": "Webhooks are available on all plans. Cal.com Cloud and self-hosted have different feature sets. The v2 API (api.cal.com/v2) is the current version — use it over deprecated v1.",
|
|
49
|
+
"retryStrategy": "Implement retry with exponential backoff. Handle webhook signature verification using X-Cal-Signature-256 header on delivery."
|
|
50
|
+
},
|
|
51
|
+
"sdk": {
|
|
52
|
+
"primaryLanguage": "typescript",
|
|
53
|
+
"installCommand": "npm install --save-exact @calcom/atoms",
|
|
54
|
+
"importStatement": "import { Cal, getCalApi } from '@calcom/atoms';",
|
|
55
|
+
"otherLanguages": ["javascript"]
|
|
56
|
+
},
|
|
57
|
+
"codeExamples": [
|
|
58
|
+
{
|
|
59
|
+
"title": "Embed Cal.com booking widget",
|
|
60
|
+
"language": "typescript",
|
|
61
|
+
"code": "'use client';\n\nimport { useEffect } from 'react';\nimport { getCalApi } from '@calcom/atoms';\n\ninterface CalBookingWidgetProps {\n calLink: string; // e.g. 'your-username/30min'\n onBookingSuccess?: (data: { uid: string }) => void;\n}\n\nexport function CalBookingWidget({\n calLink,\n onBookingSuccess,\n}: CalBookingWidgetProps): JSX.Element {\n useEffect(() => {\n (async function initCal() {\n const cal = await getCalApi({\n namespace: 'booking-widget',\n });\n\n cal('ui', {\n styles: { branding: { brandColor: '#000000' } },\n hideEventTypeDetails: false,\n layout: 'month_view',\n });\n\n if (onBookingSuccess) {\n cal('on', {\n action: 'bookingSuccessful',\n callback: (e: CustomEvent) => {\n const { uid } = e.detail.data as { uid: string };\n onBookingSuccess({ uid });\n },\n });\n }\n })();\n }, [onBookingSuccess]);\n\n return (\n <div\n data-cal-namespace=\"booking-widget\"\n data-cal-link={calLink}\n data-cal-config='{\"layout\":\"month_view\"}'\n style={{\n width: '100%',\n height: '700px',\n overflow: 'scroll',\n }}\n />\n );\n}\n\n// Usage:\n// <CalBookingWidget\n// calLink=\"jane/30min\"\n// onBookingSuccess={({ uid }) => console.log('Booked:', uid)}\n// />",
|
|
62
|
+
"notes": "The @calcom/atoms package handles the embed lifecycle. Call getCalApi() inside useEffect to avoid SSR issues. Use the `namespace` parameter when embedding multiple Cal widgets on the same page. Set brandColor to match your app's design system."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"title": "List bookings via Cal.com API",
|
|
66
|
+
"language": "typescript",
|
|
67
|
+
"code": "const CAL_API_BASE = 'https://api.cal.com/v2';\nconst CAL_API_VERSION = '2024-08-13';\n\ninterface CalBooking {\n id: number;\n uid: string;\n title: string;\n status: 'accepted' | 'pending' | 'cancelled' | 'rejected';\n startTime: string;\n endTime: string;\n attendees: Array<{\n name: string;\n email: string;\n timeZone: string;\n }>;\n eventType: {\n id: number;\n title: string;\n slug: string;\n };\n}\n\ninterface CalBookingsResponse {\n status: string;\n data: CalBooking[];\n error?: { message: string };\n}\n\nasync function listBookings(options?: {\n status?: 'upcoming' | 'past' | 'cancelled';\n take?: number;\n skip?: number;\n}): Promise<CalBooking[]> {\n const params = new URLSearchParams();\n if (options?.status) params.set('status', options.status);\n if (options?.take) params.set('take', String(options.take));\n if (options?.skip) params.set('skip', String(options.skip));\n\n const url = `${CAL_API_BASE}/bookings${params.size > 0 ? `?${params}` : ''}`;\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${process.env.CAL_API_KEY}`,\n 'cal-api-version': CAL_API_VERSION,\n },\n });\n\n if (!response.ok) {\n const error = await response.json() as CalBookingsResponse;\n throw new Error(`Cal.com API error: ${error.error?.message ?? response.statusText}`);\n }\n\n const result = await response.json() as CalBookingsResponse;\n return result.data;\n}\n\n// Example: fetch upcoming bookings\nconst upcomingBookings = await listBookings({ status: 'upcoming', take: 20 });\n\nfor (const booking of upcomingBookings) {\n console.log(`[${booking.status.toUpperCase()}] ${booking.title}`);\n console.log(` Start: ${new Date(booking.startTime).toLocaleString()}`);\n console.log(` End: ${new Date(booking.endTime).toLocaleString()}`);\n for (const attendee of booking.attendees) {\n console.log(` Attendee: ${attendee.name} <${attendee.email}>`);\n }\n}",
|
|
68
|
+
"notes": "The v2 API requires the `cal-api-version` header (use `2024-08-13` or later). The `status` filter accepts `upcoming`, `past`, or `cancelled`. Use `take` and `skip` for pagination. All datetimes are returned in ISO 8601 UTC format."
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"gotchas": [
|
|
72
|
+
"Cal.com's v1 and v2 APIs have different authentication and response formats. The v2 API (api.cal.com/v2) requires API keys with `Bearer` prefix and returns different field names. Check which version tutorials are using before copying code.",
|
|
73
|
+
"The Cal.com Atoms library (@calcom/atoms) is the UI embed component library. It ships with its own styles that may conflict with your existing CSS. Wrap it in an isolated container or use CSS layers to prevent style bleeding.",
|
|
74
|
+
"Cal.com's self-hosted version requires PostgreSQL, Redis, and a properly configured SMTP server. The Docker Compose setup works well for development, but production self-hosting needs careful configuration of email, OAuth apps, and storage.",
|
|
75
|
+
"Webhooks from Cal.com include booking lifecycle events (BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, MEETING_ENDED). You must verify the webhook signature using the HMAC-SHA256 secret to prevent spoofed events."
|
|
76
|
+
],
|
|
77
|
+
"reliability": {
|
|
78
|
+
"uptimeGuarantee": "99.9% uptime on Cal.com Cloud (paid plans)",
|
|
79
|
+
"statusPageUrl": "https://status.cal.com",
|
|
80
|
+
"notes": "Globally distributed cloud infrastructure. Self-hosted reliability depends entirely on your own infrastructure. Cal.com Cloud paid plans include SLA commitments."
|
|
81
|
+
},
|
|
82
|
+
"qualityScore": 8,
|
|
83
|
+
"qualityJustification": "Best open source scheduling API — excellent developer control, white-labeling support, and a genuinely generous free tier. The Atoms embed components work well in React apps. The main friction is that the API documentation can be inconsistent between v1 and v2, and self-hosting requires meaningful ops work.",
|
|
84
|
+
"alternatives": ["calendly"],
|
|
85
|
+
"complementary": ["resend", "stripe", "vercel", "novu"],
|
|
86
|
+
"bestFor": "Embedding customizable appointment scheduling into applications — open source with self-hosting option, strong API, and white-label support",
|
|
87
|
+
"lastVerified": "2026-02-25",
|
|
88
|
+
"entryVersion": 1,
|
|
89
|
+
"addedBy": "claude-code-session-4"
|
|
90
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Calendly",
|
|
3
|
+
"slug": "calendly",
|
|
4
|
+
"category": "scheduling",
|
|
5
|
+
"subcategory": "appointment-scheduling",
|
|
6
|
+
"website": "https://developer.calendly.com",
|
|
7
|
+
"description": "Calendly is the market-leading scheduling platform with a developer API for fetching scheduled events, managing invitees, and embedding scheduling pages. The Calendly API v2 uses OAuth2 with personal tokens for single-user apps. Widely recognized by end users — sharing a Calendly link has become a standard professional practice.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Embed a Calendly scheduling widget into a web app or website",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Retrieve scheduled meetings and invitee data via API",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Trigger actions on event scheduling via webhook",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Sync Calendly bookings to a custom database or CRM",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "oauth2",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Calendly account at calendly.com",
|
|
30
|
+
"Go to Integrations in the top-right menu",
|
|
31
|
+
"Navigate to API & Webhooks",
|
|
32
|
+
"Click 'Generate New Token' under Personal Access Tokens",
|
|
33
|
+
"Copy the token and set the CALENDLY_API_TOKEN environment variable"
|
|
34
|
+
],
|
|
35
|
+
"envVarName": "CALENDLY_API_TOKEN",
|
|
36
|
+
"codeSnippet": "const response = await fetch('https://api.calendly.com/users/me', {\n headers: {\n Authorization: `Bearer ${process.env.CALENDLY_API_TOKEN}`,\n 'Content-Type': 'application/json',\n },\n});\nconst data = await response.json();\nconsole.log('Calendly user URI:', data.resource.uri);"
|
|
37
|
+
},
|
|
38
|
+
"pricing": {
|
|
39
|
+
"model": "freemium",
|
|
40
|
+
"freeTier": "Free: 1 event type, unlimited scheduling, basic integrations, Calendly branding",
|
|
41
|
+
"startingPrice": "$10/user/month (Standard) for unlimited event types, group events, workflows",
|
|
42
|
+
"costPer": null,
|
|
43
|
+
"pricingUrl": "https://calendly.com/pricing"
|
|
44
|
+
},
|
|
45
|
+
"rateLimits": {
|
|
46
|
+
"tier": "standard",
|
|
47
|
+
"limit": "1,100 requests/hour per user token; webhooks retry for 7 days on failure",
|
|
48
|
+
"notes": "API rate limits are per access token, not per organization. Webhooks deliver real-time event notifications (invitee.created, invitee.canceled). Each webhook has a signing key for verification.",
|
|
49
|
+
"retryStrategy": "Check X-RateLimit-Remaining and Retry-After headers. Webhooks auto-retry with exponential backoff — return 200 immediately and process async."
|
|
50
|
+
},
|
|
51
|
+
"sdk": {
|
|
52
|
+
"primaryLanguage": "typescript",
|
|
53
|
+
"installCommand": "npm install --save-exact calendly-api-v2",
|
|
54
|
+
"importStatement": "// No official SDK — use fetch or axios with the REST API",
|
|
55
|
+
"otherLanguages": ["javascript", "python", "ruby"]
|
|
56
|
+
},
|
|
57
|
+
"codeExamples": [
|
|
58
|
+
{
|
|
59
|
+
"title": "Embed Calendly scheduling widget",
|
|
60
|
+
"language": "typescript",
|
|
61
|
+
"code": "'use client';\n\nimport { useEffect } from 'react';\n\ndeclare global {\n interface Window {\n Calendly?: {\n initInlineWidget: (options: {\n url: string;\n parentElement: HTMLElement;\n prefill?: {\n name?: string;\n email?: string;\n customAnswers?: Record<string, string>;\n };\n utm?: Record<string, string>;\n }) => void;\n };\n }\n}\n\ninterface CalendlyWidgetProps {\n url: string; // e.g. 'https://calendly.com/your-name/30min'\n prefill?: {\n name?: string;\n email?: string;\n };\n}\n\nexport function CalendlyWidget({ url, prefill }: CalendlyWidgetProps): JSX.Element {\n useEffect(() => {\n // Dynamically load the Calendly embed script\n const script = document.createElement('script');\n script.src = 'https://assets.calendly.com/assets/external/widget.js';\n script.async = true;\n document.head.appendChild(script);\n\n script.onload = () => {\n const container = document.getElementById('calendly-embed-container');\n if (container && window.Calendly) {\n window.Calendly.initInlineWidget({\n url,\n parentElement: container,\n prefill: prefill ?? {},\n });\n }\n };\n\n return () => {\n // Clean up script on unmount\n document.head.removeChild(script);\n };\n }, [url, prefill]);\n\n return (\n <div\n id=\"calendly-embed-container\"\n style={{ minWidth: '320px', height: '700px' }}\n />\n );\n}\n\n// Usage:\n// <CalendlyWidget\n// url=\"https://calendly.com/jane-doe/30min\"\n// prefill={{ name: 'John Smith', email: 'john@example.com' }}\n// />",
|
|
62
|
+
"notes": "Always load the Calendly widget script dynamically inside useEffect to avoid SSR hydration errors in Next.js. The widget does not support server-side rendering. Use the `prefill` option to pre-populate invitee name and email from your app's authenticated session."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"title": "Fetch scheduled events via API",
|
|
66
|
+
"language": "typescript",
|
|
67
|
+
"code": "const CALENDLY_API_BASE = 'https://api.calendly.com';\n\ninterface CalendlyUser {\n uri: string;\n name: string;\n email: string;\n}\n\ninterface CalendlyEvent {\n uri: string;\n name: string;\n status: 'active' | 'canceled';\n start_time: string;\n end_time: string;\n event_type: string;\n invitees_counter: {\n total: number;\n active: number;\n limit: number;\n };\n}\n\ninterface CalendlyEventsResponse {\n collection: CalendlyEvent[];\n pagination: {\n count: number;\n next_page: string | null;\n next_page_token: string | null;\n };\n}\n\nasync function calendlyFetch<T>(path: string): Promise<T> {\n const response = await fetch(`${CALENDLY_API_BASE}${path}`, {\n headers: {\n Authorization: `Bearer ${process.env.CALENDLY_API_TOKEN}`,\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n throw new Error(`Calendly API error ${response.status}: ${response.statusText}`);\n }\n\n return response.json() as Promise<T>;\n}\n\nasync function getScheduledEvents(): Promise<void> {\n // Step 1: Get the current user's URI (required for scoped queries)\n const me = await calendlyFetch<{ resource: CalendlyUser }>('/users/me');\n const userUri = me.resource.uri;\n\n console.log(`Fetching events for: ${me.resource.name} (${me.resource.email})`);\n\n // Step 2: Fetch upcoming active events\n const now = new Date().toISOString();\n const params = new URLSearchParams({\n user: userUri,\n status: 'active',\n min_start_time: now,\n count: '20',\n sort: 'start_time:asc',\n });\n\n const events = await calendlyFetch<CalendlyEventsResponse>(\n `/scheduled_events?${params}`\n );\n\n console.log(`Found ${events.collection.length} upcoming event(s)`);\n\n for (const event of events.collection) {\n // Extract UUID from the resource URI\n const eventId = event.uri.split('/').pop()!;\n console.log(`\\nEvent ID: ${eventId}`);\n console.log(` Name: ${event.name}`);\n console.log(` Start: ${new Date(event.start_time).toLocaleString()}`);\n console.log(` End: ${new Date(event.end_time).toLocaleString()}`);\n console.log(` Invitees: ${event.invitees_counter.active}/${event.invitees_counter.limit}`);\n }\n\n // Handle pagination\n if (events.pagination.next_page_token) {\n console.log(`\\nMore events available. Next page token: ${events.pagination.next_page_token}`);\n }\n}\n\ngetScheduledEvents().catch(console.error);",
|
|
68
|
+
"notes": "You must first call /users/me to get your user URI — all event queries require scoping to a user or organization URI. Calendly returns full URIs (not plain IDs) in all resource references. Extract the UUID from the URI tail with split('/').pop(). Use next_page_token for cursor-based pagination."
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"gotchas": [
|
|
72
|
+
"Calendly has no official TypeScript/JavaScript SDK. The `calendly-api-v2` npm package is community-maintained and may lag behind API changes. For production use, call the REST API directly with typed interfaces.",
|
|
73
|
+
"The Calendly widget is loaded from Calendly's CDN (~200KB JS). It does NOT support SSR (server-side rendering) — always use dynamic imports or useEffect to load it client-side in Next.js/React apps to avoid hydration mismatches.",
|
|
74
|
+
"Calendly's free plan shows Calendly branding on all scheduling pages and in emails. Removing branding requires the Essentials plan ($8/month). This matters for professional or white-labeled products.",
|
|
75
|
+
"The Calendly API returns resource URIs (like https://api.calendly.com/event_types/UUID) rather than plain IDs. Extract the UUID from the URI tail using split('/').pop() — don't try to use the full URI as a database key."
|
|
76
|
+
],
|
|
77
|
+
"reliability": {
|
|
78
|
+
"uptimeGuarantee": "99.9% uptime SLA (Teams+)",
|
|
79
|
+
"statusPageUrl": "https://status.calendly.com",
|
|
80
|
+
"notes": "AWS-hosted globally. Webhook delivery retries automatically for up to 7 days on failure. Suitable for production scheduling workflows with proper async event handling."
|
|
81
|
+
},
|
|
82
|
+
"qualityScore": 7,
|
|
83
|
+
"qualityJustification": "Market-leading scheduling platform with high brand recognition — users trust and know the Calendly name. Good API for syncing data. Main friction: no official SDK, free plan is heavily branded, and the widget is not SSR-compatible. Cal.com is a better choice for developers who want more control.",
|
|
84
|
+
"alternatives": ["cal-com"],
|
|
85
|
+
"complementary": ["resend", "stripe", "novu"],
|
|
86
|
+
"bestFor": "Adding scheduling to apps where Calendly's brand recognition and user familiarity are assets — and for teams that need a polished out-of-the-box scheduling solution",
|
|
87
|
+
"lastVerified": "2026-02-25",
|
|
88
|
+
"entryVersion": 1,
|
|
89
|
+
"addedBy": "claude-code-session-4"
|
|
90
|
+
}
|