@nordsym/apiclaw 1.5.9 → 1.5.11

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.
Files changed (109) hide show
  1. package/APILAYER_STATUS_2026-03-24.md +38 -0
  2. package/CHANGELOG-WHITELIST-V2.md +269 -0
  3. package/HIVR-INTEGRATION.md +281 -0
  4. package/HIVR-WHITELIST-STATUS.md +205 -0
  5. package/HIVR-WHITELIST.md +148 -0
  6. package/TERMINOLOGY-AUDIT.md +99 -0
  7. package/TERMINOLOGY-FIXED.md +74 -0
  8. package/VIDEO-DEMO-GUIDE.md +82 -0
  9. package/WHITELIST-ARCHITECTURE.md +379 -0
  10. package/api/discover.ts +71 -0
  11. package/api/health.ts +20 -0
  12. package/convex/http.d.ts.map +1 -1
  13. package/convex/http.js +8 -0
  14. package/convex/http.js.map +1 -1
  15. package/convex/http.ts +8 -0
  16. package/direct-test.mjs +51 -0
  17. package/dist/access-control.d.ts +45 -0
  18. package/dist/access-control.d.ts.map +1 -0
  19. package/dist/access-control.js +142 -0
  20. package/dist/access-control.js.map +1 -0
  21. package/dist/analytics.d.ts +4 -0
  22. package/dist/analytics.d.ts.map +1 -1
  23. package/dist/analytics.js +1 -0
  24. package/dist/analytics.js.map +1 -1
  25. package/dist/cli/commands/mcp-install.d.ts.map +1 -1
  26. package/dist/cli/commands/mcp-install.js +55 -40
  27. package/dist/cli/commands/mcp-install.js.map +1 -1
  28. package/dist/credentials.d.ts.map +1 -1
  29. package/dist/credentials.js +148 -0
  30. package/dist/credentials.js.map +1 -1
  31. package/dist/discovery.d.ts.map +1 -1
  32. package/dist/discovery.js +191 -82
  33. package/dist/discovery.js.map +1 -1
  34. package/dist/execute.d.ts.map +1 -1
  35. package/dist/execute.js +274 -0
  36. package/dist/execute.js.map +1 -1
  37. package/dist/hivr-whitelist.d.ts +18 -0
  38. package/dist/hivr-whitelist.d.ts.map +1 -0
  39. package/dist/hivr-whitelist.js +95 -0
  40. package/dist/hivr-whitelist.js.map +1 -0
  41. package/dist/http-api.d.ts.map +1 -1
  42. package/dist/http-api.js +17 -33
  43. package/dist/http-api.js.map +1 -1
  44. package/dist/http-server-minimal.d.ts +7 -0
  45. package/dist/http-server-minimal.d.ts.map +1 -0
  46. package/dist/http-server-minimal.js +126 -0
  47. package/dist/http-server-minimal.js.map +1 -0
  48. package/dist/product-whitelist.d.ts +37 -0
  49. package/dist/product-whitelist.d.ts.map +1 -0
  50. package/dist/product-whitelist.js +203 -0
  51. package/dist/product-whitelist.js.map +1 -0
  52. package/dist/proxy.d.ts.map +1 -1
  53. package/dist/proxy.js +1 -1
  54. package/dist/proxy.js.map +1 -1
  55. package/email-templates/README.md +104 -0
  56. package/email-templates/partnership-template.html +116 -0
  57. package/landing/next-env.d.ts +1 -0
  58. package/landing/pages/api/discover.ts +43 -0
  59. package/landing/pages/api/health.ts +20 -0
  60. package/landing/src/app/api/auth/magic-link/route.ts +1 -1
  61. package/landing/src/app/auth/verify/page.tsx +6 -0
  62. package/landing/src/app/dashboard/verify/page.tsx +6 -0
  63. package/landing/src/app/join/page.tsx +6 -0
  64. package/landing/src/app/layout.tsx +2 -2
  65. package/landing/src/app/login/page.tsx +1 -1
  66. package/landing/src/app/mou/[partnerId]/page.tsx +6 -0
  67. package/landing/src/app/page.tsx +39 -18
  68. package/landing/src/app/providers/dashboard/[apiId]/actions/[actionId]/edit/page.tsx +6 -0
  69. package/landing/src/app/providers/dashboard/[apiId]/actions/new/page.tsx +5 -0
  70. package/landing/src/app/providers/dashboard/[apiId]/actions/page.tsx +5 -0
  71. package/landing/src/app/providers/dashboard/[apiId]/direct-call/page.tsx +6 -1
  72. package/landing/src/app/providers/dashboard/[apiId]/page.tsx +5 -0
  73. package/landing/src/app/providers/dashboard/[apiId]/test/page.tsx +5 -0
  74. package/landing/src/app/providers/dashboard/layout.tsx +6 -6
  75. package/landing/src/app/providers/dashboard/login/page.tsx +1 -1
  76. package/landing/src/app/providers/dashboard/page.tsx +1 -1
  77. package/landing/src/app/providers/dashboard/verify/page.tsx +6 -0
  78. package/landing/src/app/providers/layout.tsx +1 -1
  79. package/landing/src/app/upgrade/page.tsx +6 -0
  80. package/landing/src/app/workspace/page.tsx +6 -0
  81. package/landing/src/components/HeroTabs.tsx +2 -2
  82. package/landing/src/components/VideoDemo.tsx +94 -0
  83. package/landing/src/components/{ProviderDashboard.tsx → Workspace.tsx} +2 -2
  84. package/landing/src/lib/mock-data.ts +1 -1
  85. package/landing/src/lib/stats.json +1 -1
  86. package/package.json +4 -2
  87. package/scripts/test-whitelist-v2.sh +128 -0
  88. package/src/access-control.ts +174 -0
  89. package/src/analytics.ts +5 -0
  90. package/src/cli/commands/mcp-install.ts +14 -4
  91. package/src/credentials.ts +156 -0
  92. package/src/discovery.ts +191 -82
  93. package/src/execute.ts +274 -0
  94. package/src/hivr-whitelist.ts +110 -0
  95. package/src/http-api.ts +18 -34
  96. package/src/http-server-minimal.ts +154 -0
  97. package/src/product-whitelist.ts +246 -0
  98. package/src/proxy.ts +1 -1
  99. package/test-actual-handlers.ts +92 -0
  100. package/test-apilayer-all-14.ts +249 -0
  101. package/test-apilayer-fixed.ts +248 -0
  102. package/test-direct-endpoints.ts +174 -0
  103. package/test-exact-endpoints.ts +144 -0
  104. package/test-final.ts +83 -0
  105. package/test-full-routing.ts +100 -0
  106. package/test-handlers-correct.ts +217 -0
  107. package/test-numverify-key.ts +41 -0
  108. package/test-via-handlers.ts +92 -0
  109. package/test-worldnews.mjs +26 -0
package/dist/proxy.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,GAAG,0DAA0D,CAAC;AAE9E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAW;IAC3D,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;IAExC,2CAA2C;IAC3C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,EAAE,WAAW,IAAI,QAAQ,WAAW,EAAE,CAAC;IAEjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,sBAAsB,EAAE,UAAU;YAClC,oBAAoB,EAAE,QAAQ;YAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM;SAC5C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAuB,CAAC;QAC/G,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,gBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,GAAG,0DAA0D,CAAC;AAE9E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAW;IAC3D,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;IAExC,2CAA2C;IAC3C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,EAAE,WAAW,IAAI,QAAQ,WAAW,EAAE,CAAC;IAEjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,sBAAsB,EAAE,UAAU;YAClC,oBAAoB,EAAE,QAAQ;YAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM;SAC5C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAuB,CAAC;QAC/G,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,gBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC"}
@@ -0,0 +1,104 @@
1
+ # APIClaw Email Templates
2
+
3
+ Official HTML email templates for APIClaw communications.
4
+
5
+ ## Design System
6
+
7
+ **Brand Colors:**
8
+ - Primary Red: `#ef4444`
9
+ - Background: `#fafafa`
10
+ - Card Background: `#ffffff`
11
+ - Text Primary: `#1a1a1a`
12
+ - Text Secondary: `#4b5563`
13
+ - Text Muted: `#6b7280`
14
+ - Border: `#e5e7eb`
15
+ - Highlight Background: `#fef2f2`
16
+
17
+ **Typography:**
18
+ - System font stack: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`
19
+ - Headers: Bold, red (`#ef4444`)
20
+ - Body: Regular, dark gray (`#4b5563`)
21
+ - Code blocks: Monospace, gray background (`#f9fafb`)
22
+
23
+ **Layout:**
24
+ - Max width: 600px
25
+ - Card style with rounded corners (16px)
26
+ - Subtle shadow and border
27
+ - Responsive padding
28
+ - Center-aligned container
29
+
30
+ ## Templates
31
+
32
+ ### `partnership-template.html`
33
+ **Use for:** Partnership outreach, integration proposals, technical follow-ups
34
+
35
+ **Variables to replace:**
36
+ - `{{EMAIL_TITLE}}` - Main heading (e.g., "APIClaw × Apideck")
37
+ - `{{EMAIL_SUBTITLE}}` - Subtitle (e.g., "Partnership Follow-up")
38
+ - `{{GREETING}}` - Opening (e.g., "Hi Pratham,")
39
+ - `{{INTRO_TEXT}}` - First paragraph
40
+ - `{{SECTION_X_TITLE}}` - Section headings
41
+ - `{{SECTION_X_CONTENT}}` - Section content (can include HTML lists, paragraphs)
42
+ - `{{HIGHLIGHT_TITLE}}` - Callout box title
43
+ - `{{HIGHLIGHT_TEXT}}` - Callout box content
44
+ - `{{CODE_BLOCK}}` - Technical/code content (optional)
45
+ - `{{CTA_LINK}}` - Button URL
46
+ - `{{CTA_TEXT}}` - Button text
47
+ - `{{CLOSING_TEXT}}` - Closing paragraph
48
+ - `{{FOOTER_TEXT}}` - Footer context (e.g., "APIClaw × Apideck • March 2026")
49
+
50
+ **Structure:**
51
+ 1. Header with logo + title
52
+ 2. Greeting + intro
53
+ 3. Multiple sections with red headings
54
+ 4. Optional highlight box
55
+ 5. Optional code block
56
+ 6. CTA button
57
+ 7. Closing + signature
58
+ 8. Footer
59
+
60
+ ## Usage
61
+
62
+ Send via n8n workflow:
63
+
64
+ ```bash
65
+ curl -s -X POST "https://nordsym.app.n8n.cloud/webhook/symbot-gmail" \
66
+ -H "Content-Type: application/json" \
67
+ -d '{
68
+ "action": "send",
69
+ "to": "recipient@example.com",
70
+ "subject": "Subject line",
71
+ "message": "'"$(cat partnership-template.html | sed 's/{{VAR}}/value/g')"'"
72
+ }'
73
+ ```
74
+
75
+ Or use `action: "smtp"` for sending from `Symbot@nordsym.com`.
76
+
77
+ ## Design Principles
78
+
79
+ ✅ **DO:**
80
+ - Use light mode (professional, readable)
81
+ - Keep sections scannable
82
+ - Use red for emphasis sparingly
83
+ - Include clear CTA
84
+ - Test in both light and dark mode (email clients auto-convert)
85
+ - Maintain 600px max width for readability
86
+
87
+ ❌ **DON'T:**
88
+ - Use dark mode as default
89
+ - Overuse red color
90
+ - Create walls of text
91
+ - Skip the highlight box for key points
92
+ - Forget mobile responsiveness
93
+
94
+ ## Created
95
+
96
+ **Date:** 2026-03-24
97
+ **Design:** Light APIClaw theme matching MoU pages
98
+ **First use:** Pratham/Apideck partnership follow-up (draft)
99
+
100
+ ## Notes
101
+
102
+ Design is production-ready. Copy/content templates can be improved iteratively.
103
+
104
+ Each email should feel like it came from the same visual system as apiclaw.nordsym.com.
@@ -0,0 +1,116 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>APIClaw Email Template</title>
7
+ </head>
8
+ <body style="margin: 0; padding: 0; background-color: #fafafa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;">
9
+ <table width="100%" cellpadding="0" cellspacing="0" style="background-color: #fafafa; padding: 40px 20px;">
10
+ <tr>
11
+ <td align="center">
12
+ <!-- Main container -->
13
+ <table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 16px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); overflow: hidden; border: 1px solid #e5e7eb;">
14
+
15
+ <!-- Header -->
16
+ <tr>
17
+ <td style="background-color: #ffffff; border-bottom: 1px solid #e5e7eb; padding: 32px; text-align: center;">
18
+ <div style="font-size: 28px; font-weight: bold; color: #ef4444; margin-bottom: 16px;">🦞 APIClaw</div>
19
+ <h1 style="margin: 0; font-size: 24px; font-weight: bold; color: #1a1a1a;">{{EMAIL_TITLE}}</h1>
20
+ <p style="margin: 4px 0 0 0; color: #6b7280; font-size: 14px;">{{EMAIL_SUBTITLE}}</p>
21
+ <div style="height: 4px; width: 80px; background-color: #ef4444; margin: 16px auto 0; border-radius: 2px;"></div>
22
+ </td>
23
+ </tr>
24
+
25
+ <!-- Content -->
26
+ <tr>
27
+ <td style="padding: 32px;">
28
+ <!-- Greeting -->
29
+ <p style="margin: 0 0 20px 0; color: #1a1a1a; font-size: 16px; line-height: 1.6;">
30
+ {{GREETING}}
31
+ </p>
32
+
33
+ <!-- Intro paragraph -->
34
+ <p style="margin: 0 0 20px 0; color: #4b5563; font-size: 16px; line-height: 1.6;">
35
+ {{INTRO_TEXT}}
36
+ </p>
37
+
38
+ <!-- Section 1 -->
39
+ <div style="margin: 24px 0;">
40
+ <h2 style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: #ef4444; border-bottom: 2px solid #f3f4f6; padding-bottom: 8px;">
41
+ {{SECTION_1_TITLE}}
42
+ </h2>
43
+ {{SECTION_1_CONTENT}}
44
+ </div>
45
+
46
+ <!-- Highlight Box (optional) -->
47
+ <div style="margin: 24px 0; background-color: #fef2f2; border-left: 4px solid #ef4444; padding: 16px; border-radius: 8px;">
48
+ <h3 style="margin: 0 0 8px 0; font-size: 16px; font-weight: 600; color: #ef4444;">
49
+ {{HIGHLIGHT_TITLE}}
50
+ </h3>
51
+ <p style="margin: 0; color: #4b5563; font-size: 14px; line-height: 1.6;">
52
+ {{HIGHLIGHT_TEXT}}
53
+ </p>
54
+ </div>
55
+
56
+ <!-- Section 2 -->
57
+ <div style="margin: 24px 0;">
58
+ <h2 style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: #ef4444; border-bottom: 2px solid #f3f4f6; padding-bottom: 8px;">
59
+ {{SECTION_2_TITLE}}
60
+ </h2>
61
+ {{SECTION_2_CONTENT}}
62
+ </div>
63
+
64
+ <!-- Code/Technical Block (optional) -->
65
+ <div style="background-color: #f9fafb; padding: 16px; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 13px; color: #374151; line-height: 1.6;">
66
+ {{CODE_BLOCK}}
67
+ </div>
68
+
69
+ <!-- CTA Button -->
70
+ <div style="text-align: center; margin: 32px 0;">
71
+ <a href="{{CTA_LINK}}" style="display: inline-block; background-color: #ef4444; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px; box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2);">
72
+ {{CTA_TEXT}}
73
+ </a>
74
+ </div>
75
+
76
+ <!-- Closing -->
77
+ <p style="margin: 24px 0 0 0; color: #4b5563; font-size: 16px; line-height: 1.6;">
78
+ {{CLOSING_TEXT}}
79
+ </p>
80
+
81
+ <!-- Signature -->
82
+ <p style="margin: 20px 0 0 0; color: #4b5563; font-size: 16px; line-height: 1.6;">
83
+ Best,<br>
84
+ <strong style="color: #1a1a1a;">Gustav Hemmingsson</strong><br>
85
+ <span style="color: #6b7280; font-size: 14px;">CEO, NordSym AB</span>
86
+ </p>
87
+ </td>
88
+ </tr>
89
+
90
+ <!-- Footer -->
91
+ <tr>
92
+ <td style="background-color: #f9fafb; border-top: 1px solid #e5e7eb; padding: 24px; text-align: center;">
93
+ <p style="margin: 0 0 8px 0; color: #6b7280; font-size: 13px;">
94
+ {{FOOTER_TEXT}}
95
+ </p>
96
+ <p style="margin: 0; color: #9ca3af; font-size: 12px;">
97
+ Questions? Contact <a href="mailto:gustav@nordsym.com" style="color: #ef4444; text-decoration: none;">gustav@nordsym.com</a>
98
+ </p>
99
+ </td>
100
+ </tr>
101
+
102
+ </table>
103
+
104
+ <!-- Signature -->
105
+ <div style="margin-top: 32px; text-align: center; color: #9ca3af; font-size: 12px;">
106
+ <p style="margin: 0;">NordSym AB (559535-5768) • Sweden</p>
107
+ <p style="margin: 4px 0 0 0;">
108
+ <a href="https://apiclaw.nordsym.com" style="color: #ef4444; text-decoration: none;">apiclaw.nordsym.com</a> •
109
+ <a href="https://github.com/nordsym/apiclaw" style="color: #ef4444; text-decoration: none;">GitHub</a>
110
+ </p>
111
+ </div>
112
+ </td>
113
+ </tr>
114
+ </table>
115
+ </body>
116
+ </html>
@@ -1,5 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
+ /// <reference types="next/navigation-types/compat/navigation" />
3
4
 
4
5
  // NOTE: This file should not be edited
5
6
  // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * APIClaw Discovery API - Next.js API Route
3
+ * GET /api/discover?query=...&agentId=...
4
+ */
5
+
6
+ import type { NextApiRequest, NextApiResponse } from 'next';
7
+
8
+ // Import from built dist (since we can't easily import TS from parent)
9
+ // For now, return a simple response - we'll implement full logic after verifying deployment
10
+
11
+ export default async function handler(
12
+ req: NextApiRequest,
13
+ res: NextApiResponse
14
+ ) {
15
+ // CORS
16
+ res.setHeader('Access-Control-Allow-Origin', '*');
17
+ res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
18
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Agent-Id');
19
+
20
+ if (req.method === 'OPTIONS') {
21
+ return res.status(200).end();
22
+ }
23
+
24
+ if (req.method !== 'GET') {
25
+ return res.status(405).json({ error: 'Method not allowed' });
26
+ }
27
+
28
+ const { query, agentId, category, maxResults } = req.query;
29
+
30
+ if (!query || typeof query !== 'string') {
31
+ return res.status(400).json({ error: 'Missing query parameter' });
32
+ }
33
+
34
+ // TODO: Import actual whitelist + discovery logic
35
+ // For now, simple passthrough
36
+ return res.status(200).json({
37
+ success: true,
38
+ query,
39
+ agentId: typeof agentId === 'string' ? agentId : undefined,
40
+ message: 'APIClaw Discovery API - implementation pending',
41
+ timestamp: new Date().toISOString(),
42
+ });
43
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * APIClaw Health Check - Next.js API Route
3
+ * GET /api/health
4
+ */
5
+
6
+ import type { NextApiRequest, NextApiResponse } from 'next';
7
+
8
+ export default async function handler(
9
+ req: NextApiRequest,
10
+ res: NextApiResponse
11
+ ) {
12
+ res.setHeader('Access-Control-Allow-Origin', '*');
13
+
14
+ return res.status(200).json({
15
+ status: 'ok',
16
+ service: 'apiclaw-http-api',
17
+ version: '2.0.0',
18
+ timestamp: new Date().toISOString(),
19
+ });
20
+ }
@@ -51,7 +51,7 @@ export async function POST(req: NextRequest) {
51
51
  </div>
52
52
 
53
53
  <p style="color: #525252; font-size: 16px; line-height: 1.6; text-align: center;">
54
- Click the button below to sign in to your provider dashboard.
54
+ Click the button below to sign in to your workspace.
55
55
  </p>
56
56
 
57
57
  <div style="text-align: center; margin: 32px 0;">
@@ -22,6 +22,12 @@ interface VerifyResult {
22
22
 
23
23
  function VerifyContent() {
24
24
  const searchParams = useSearchParams();
25
+
26
+ // Handle null searchParams (shouldn't happen in client component, but TypeScript requires it)
27
+ if (!searchParams) {
28
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
29
+ }
30
+
25
31
  const token = searchParams.get("token");
26
32
  const referralCode = searchParams.get("ref"); // Referral code from signup URL
27
33
 
@@ -8,6 +8,12 @@ import Link from "next/link";
8
8
  function VerifyContent() {
9
9
  const router = useRouter();
10
10
  const searchParams = useSearchParams();
11
+
12
+ // Handle null searchParams
13
+ if (!searchParams) {
14
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
15
+ }
16
+
11
17
  const token = searchParams.get("token");
12
18
 
13
19
  const [status, setStatus] = useState<"verifying" | "success" | "error">("verifying");
@@ -7,6 +7,12 @@ import { Suspense } from "react";
7
7
  function JoinContent() {
8
8
  const searchParams = useSearchParams();
9
9
  const router = useRouter();
10
+
11
+ // Handle null searchParams
12
+ if (!searchParams) {
13
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
14
+ }
15
+
10
16
  const refCode = searchParams.get("ref");
11
17
 
12
18
  useEffect(() => {
@@ -51,7 +51,7 @@ const schemaOrg = {
51
51
  "@type": "WebSite",
52
52
  "name": "APIClaw",
53
53
  "url": "https://apiclaw.nordsym.com",
54
- "description": "Your agent's API encyclopedia. Search by capability, call instantly. 22,392 APIs indexed • 1,636 Open APIs • 18 Direct Call • MCP native"
54
+ "description": "Your agent's API encyclopedia. Search by capability, call instantly. 22,392 APIs indexed • 1,636 Open APIs • 19 Direct Call • MCP native"
55
55
  },
56
56
  {
57
57
  "@type": "Organization",
@@ -63,7 +63,7 @@ const schemaOrg = {
63
63
  "name": "APIClaw",
64
64
  "applicationCategory": "DeveloperApplication",
65
65
  "operatingSystem": "Web",
66
- "description": "The API layer for AI agents. 22,392 APIs indexed, 1,636 Open APIs, 18 Direct Call providers. MCP native.",
66
+ "description": "The API layer for AI agents. 22,392 APIs indexed, 1,636 Open APIs, 19 Direct Call providers. MCP native.",
67
67
  "offers": {
68
68
  "@type": "Offer",
69
69
  "price": "0",
@@ -199,7 +199,7 @@ export default function LoginPage() {
199
199
  <p className="text-sm text-[var(--text-muted)]">
200
200
  Are you an API provider?{" "}
201
201
  <Link href="/providers/dashboard/login" className="text-accent hover:underline">
202
- Provider Dashboard
202
+ Workspace
203
203
  </Link>
204
204
  </p>
205
205
  </div>
@@ -126,6 +126,12 @@ const mouContent: Record<string, MOUPartner> = {
126
126
 
127
127
  export default function MOUPage() {
128
128
  const params = useParams();
129
+
130
+ // Handle null params
131
+ if (!params || !params.partnerId) {
132
+ return <div className="min-h-screen flex items-center justify-center">Invalid partner ID</div>;
133
+ }
134
+
129
135
  const partnerId = params.partnerId as string;
130
136
  const canvasRef = useRef<HTMLCanvasElement>(null);
131
137
  const [isDrawing, setIsDrawing] = useState(false);
@@ -12,11 +12,12 @@ import { useState, useEffect, useRef } from "react";
12
12
  import { HeroTabs } from "@/components/HeroTabs";
13
13
  import { PhoneDemo } from "@/components/demo";
14
14
  import { AITestimonials } from "@/components/AITestimonials";
15
+ import { VideoDemo } from "@/components/VideoDemo";
15
16
 
16
17
  const stats = [
17
18
  { number: statsData.apiCount.toLocaleString(), label: "APIs Indexed", live: true },
18
19
  { number: statsData.openApiCount.toLocaleString(), label: "Open APIs", live: true },
19
- { number: statsData.directCallCount?.toString() || "19", label: "Direct Call", live: false },
20
+ { number: "19", label: "Direct Call", live: false },
20
21
  { number: (statsData.npmDownloads || 4232).toLocaleString(), label: "Installs", live: false },
21
22
  { number: statsData.categoryCount.toString(), label: "Categories", live: false },
22
23
  ];
@@ -146,6 +147,7 @@ const terminalLines = [
146
147
  const directCallProviders = [
147
148
  { name: "Replicate", desc: "1000+ ML models" },
148
149
  { name: "OpenRouter", desc: "100+ LLMs" },
150
+ { name: "APILayer", desc: "14 APIs" },
149
151
  { name: "Firecrawl", desc: "Web scraping" },
150
152
  { name: "E2B", desc: "Code sandbox" },
151
153
  { name: "GitHub", desc: "Repos & Issues" },
@@ -170,22 +172,23 @@ export default function Home() {
170
172
  const [waitlistEmail, setWaitlistEmail] = useState("");
171
173
  const [waitlistStatus, setWaitlistStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
172
174
 
173
- const directCallProviders = [
174
- // Original 10
175
- { name: "Replicate", desc: "Whisper, Stable Diffusion, 1000+ ML models", category: "AI & LLM" },
176
- { name: "OpenRouter", desc: "GPT-4, Claude, Llama, 100+ LLMs", category: "AI & LLM" },
175
+ const directCallProviders: Array<{ name: string; desc: string; category: string; featured?: boolean; apis?: number }> = [
176
+ // Multi-API providers (top)
177
+ { name: "APILayer", desc: "Exchange rates, stocks, aviation, PDF, screenshots, email/phone verification, VAT, news, scraping", category: "Multi-API", apis: 14 },
178
+ { name: "Replicate", desc: "Whisper, Stable Diffusion, Flux, Luma, 1000+ ML models", category: "Multi-API", apis: 1000 },
179
+ { name: "OpenRouter", desc: "GPT-4, Claude, Llama, Gemini, 100+ LLMs", category: "Multi-API", apis: 100 },
180
+ // Single-purpose
177
181
  { name: "ElevenLabs", desc: "Text-to-speech in 29 languages", category: "Voice & TTS" },
178
- { name: "46elks", desc: "SMS in Sweden and globally", category: "SMS & Messaging" },
179
- { name: "Twilio", desc: "Enterprise SMS and voice", category: "SMS & Messaging" },
180
- { name: "Resend", desc: "Modern email API for developers", category: "Email" },
181
- { name: "Brave Search", desc: "Privacy-focused web search", category: "Search" },
182
- { name: "Firecrawl", desc: "Web scraping to LLM-ready markdown", category: "Search" },
183
- { name: "E2B", desc: "Secure cloud sandboxes for code execution", category: "Code Execution" },
184
- { name: "GitHub", desc: "Repos, issues, PRs, and more", category: "Developer Tools" },
185
- // New 8
186
182
  { name: "Groq", desc: "Ultra-fast LLM inference", category: "AI & LLM" },
187
183
  { name: "Deepgram", desc: "Speech-to-text transcription", category: "Voice & TTS" },
184
+ { name: "Firecrawl", desc: "Web scraping to LLM-ready markdown", category: "Search" },
185
+ { name: "Brave Search", desc: "Privacy-focused web search", category: "Search" },
188
186
  { name: "Serper", desc: "Google search API for AI", category: "Search" },
187
+ { name: "E2B", desc: "Secure cloud sandboxes for code execution", category: "Code Execution" },
188
+ { name: "GitHub", desc: "Repos, issues, PRs, and more", category: "Developer Tools" },
189
+ { name: "Resend", desc: "Modern email API for developers", category: "Email" },
190
+ { name: "46elks", desc: "SMS in Sweden and globally", category: "SMS & Messaging" },
191
+ { name: "Twilio", desc: "Enterprise SMS and voice", category: "SMS & Messaging" },
189
192
  { name: "Mistral", desc: "Open-weight LLMs from Mistral AI", category: "AI & LLM" },
190
193
  { name: "Cohere", desc: "Enterprise NLP and embeddings", category: "AI & LLM" },
191
194
  { name: "Together AI", desc: "Open-source model inference", category: "AI & LLM" },
@@ -217,6 +220,7 @@ Voice: ElevenLabs, Deepgram, AssemblyAI
217
220
  Search: Brave Search, Serper, Firecrawl
218
221
  Code: E2B, GitHub
219
222
  Utility: Resend (email), 46elks & Twilio (SMS)
223
+ Multi-API: APILayer (exchange rates, stocks, aviation, PDF, screenshots, verification, VAT, news, scraping — 14 APIs)
220
224
 
221
225
  Your Tools:
222
226
  • call_api(provider, action, params) – Execute immediately (leave auth fields empty – APIClaw handles it)
@@ -587,12 +591,26 @@ Docs: https://apiclaw.nordsym.com/docs`;
587
591
  <p className="text-text-muted mb-4">These APIs work through APIClaw's proxy. Your agent calls them without needing API keys.</p>
588
592
  <div className="space-y-3">
589
593
  {directCallProviders.map((provider, i) => (
590
- <div key={i} className="flex items-center justify-between p-3 rounded-xl bg-surface border border-border">
594
+ <div key={i} className={`flex items-center justify-between p-3 rounded-xl border transition-all ${
595
+ provider.featured
596
+ ? 'bg-gradient-to-r from-accent/5 to-purple-500/5 border-accent/30 hover:border-accent/50 hover:shadow-[0_0_20px_rgba(0,212,255,0.08)]'
597
+ : provider.apis
598
+ ? 'bg-surface border-border/80'
599
+ : 'bg-surface border-border'
600
+ }`}>
591
601
  <div>
592
- <div className="font-medium">{provider.name}</div>
602
+ <div className="flex items-center gap-2">
603
+ <span className="font-medium">{provider.name}</span>
604
+ {provider.featured && (
605
+ <span className="text-[10px] font-bold uppercase tracking-wider px-1.5 py-0.5 rounded bg-accent/20 text-accent">Partner</span>
606
+ )}
607
+ {provider.apis && (
608
+ <span className="text-[10px] font-medium px-1.5 py-0.5 rounded bg-purple-500/20 text-purple-400">{provider.apis >= 1000 ? `${Math.floor(provider.apis/1000)}k+` : `${provider.apis}`} APIs</span>
609
+ )}
610
+ </div>
593
611
  <div className="text-sm text-text-muted">{provider.desc}</div>
594
612
  </div>
595
- <span className="text-xs px-2 py-1 rounded-full bg-accent/20 text-accent">{provider.category}</span>
613
+ <span className="text-xs px-2 py-1 rounded-full bg-accent/20 text-accent flex-shrink-0 ml-3">{provider.category}</span>
596
614
  </div>
597
615
  ))}
598
616
  </div>
@@ -1029,7 +1047,7 @@ Docs: https://apiclaw.nordsym.com/docs`;
1029
1047
  </li>
1030
1048
  <li className="flex items-start gap-3 text-text-secondary text-sm">
1031
1049
  <Check className="w-5 h-5 text-accent flex-shrink-0 mt-0.5" />
1032
- 18 Direct Call providers
1050
+ 19 Direct Call providers
1033
1051
  </li>
1034
1052
  <li className="flex items-start gap-3 text-text-secondary text-sm">
1035
1053
  <Check className="w-5 h-5 text-accent flex-shrink-0 mt-0.5" />
@@ -1144,7 +1162,7 @@ Docs: https://apiclaw.nordsym.com/docs`;
1144
1162
  },
1145
1163
  {
1146
1164
  q: "How do I add my API?",
1147
- a: "Go to the Provider Dashboard, sign up with your email, and follow the self-service onboarding. Your API will be discoverable by AI agents immediately. Want to become a Direct Call partner? Set that up in the dashboard too."
1165
+ a: "Go to your Workspace, sign up with your email, and follow the self-service onboarding. Your API will be discoverable by AI agents immediately. Want to become a Direct Call partner? Set that up in your Workspace too."
1148
1166
  },
1149
1167
  {
1150
1168
  q: "What's MCP?",
@@ -1327,6 +1345,9 @@ Docs: https://apiclaw.nordsym.com/docs`;
1327
1345
  </div>
1328
1346
  </div>
1329
1347
  )}
1348
+
1349
+ {/* Video Demo Bubble - Always visible */}
1350
+ <VideoDemo />
1330
1351
  </main>
1331
1352
  );
1332
1353
  }
@@ -47,6 +47,12 @@ const PARAM_LOCATIONS = ["body", "query", "path"] as const;
47
47
  export default function EditActionPage() {
48
48
  const params = useParams();
49
49
  const router = useRouter();
50
+
51
+ // Handle null params
52
+ if (!params || !params.apiId || !params.actionId) {
53
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
54
+ }
55
+
50
56
  const apiId = params.apiId as string;
51
57
  const actionId = params.actionId as string;
52
58
 
@@ -45,6 +45,11 @@ const PARAM_LOCATIONS = ["body", "query", "path"] as const;
45
45
 
46
46
  export default function NewActionPage() {
47
47
  const params = useParams();
48
+
49
+ // Handle null params
50
+ if (!params || !params.apiId) {
51
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
52
+ }
48
53
  const router = useRouter();
49
54
  const apiId = params.apiId as string;
50
55
 
@@ -41,6 +41,11 @@ const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || 'https://brilliant-puff
41
41
 
42
42
  export default function ActionsPage() {
43
43
  const params = useParams();
44
+
45
+ // Handle null params
46
+ if (!params || !params.apiId) {
47
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
48
+ }
44
49
  const router = useRouter();
45
50
  const apiId = params.apiId as string;
46
51
 
@@ -50,6 +50,11 @@ const authTypes = [
50
50
 
51
51
  export default function DirectCallSetupPage() {
52
52
  const params = useParams();
53
+
54
+ // Handle null params
55
+ if (!params || !params.apiId) {
56
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
57
+ }
53
58
  const router = useRouter();
54
59
  const apiId = params.apiId as string;
55
60
 
@@ -440,7 +445,7 @@ export default function DirectCallSetupPage() {
440
445
  <label className="block text-sm font-medium mb-2">Service Account Key</label>
441
446
  <p className="text-xs text-text-muted mb-3">
442
447
  The API key APIClaw uses to make requests on behalf of your users.
443
- This is typically a privileged key from your provider dashboard.
448
+ This is typically a privileged key from your workspace.
444
449
  </p>
445
450
  <div className="relative">
446
451
  <Key className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-text-muted" />
@@ -32,6 +32,11 @@ interface DirectCallConfig {
32
32
 
33
33
  export default function ApiOverviewPage() {
34
34
  const params = useParams();
35
+
36
+ // Handle null params
37
+ if (!params || !params.apiId) {
38
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
39
+ }
35
40
  const router = useRouter();
36
41
  const apiId = params.apiId as string;
37
42
 
@@ -61,6 +61,11 @@ const methodColors: Record<string, string> = {
61
61
 
62
62
  export default function TestConsolePage() {
63
63
  const params = useParams();
64
+
65
+ // Handle null params
66
+ if (!params || !params.apiId) {
67
+ return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
68
+ }
64
69
  const router = useRouter();
65
70
  const apiId = params.apiId as string;
66
71