@nordsym/apiclaw 1.0.0 → 1.1.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.
Files changed (154) hide show
  1. package/AGENTS.md +74 -0
  2. package/HEARTBEAT.md +4 -0
  3. package/IDENTITY.md +22 -0
  4. package/README.md +197 -202
  5. package/SOUL.md +36 -0
  6. package/STATUS.md +237 -0
  7. package/TOOLS.md +36 -0
  8. package/USER.md +17 -0
  9. package/{backend/convex → convex}/_generated/api.d.ts +6 -6
  10. package/convex/credits.ts +211 -0
  11. package/convex/http.ts +490 -0
  12. package/convex/providers.ts +516 -0
  13. package/convex/purchases.ts +183 -0
  14. package/convex/schema.ts +180 -0
  15. package/convex.json +3 -0
  16. package/dist/credentials.d.ts +19 -0
  17. package/dist/credentials.d.ts.map +1 -0
  18. package/dist/credentials.js +158 -0
  19. package/dist/credentials.js.map +1 -0
  20. package/dist/credits.d.ts +14 -11
  21. package/dist/credits.d.ts.map +1 -1
  22. package/dist/credits.js +151 -99
  23. package/dist/credits.js.map +1 -1
  24. package/dist/discovery.d.ts +7 -16
  25. package/dist/discovery.d.ts.map +1 -1
  26. package/dist/discovery.js +33 -40
  27. package/dist/discovery.js.map +1 -1
  28. package/dist/execute.d.ts +19 -0
  29. package/dist/execute.d.ts.map +1 -0
  30. package/dist/execute.js +285 -0
  31. package/dist/execute.js.map +1 -0
  32. package/dist/index.js +106 -30
  33. package/dist/index.js.map +1 -1
  34. package/dist/proxy.d.ts +6 -0
  35. package/dist/proxy.d.ts.map +1 -0
  36. package/dist/proxy.js +19 -0
  37. package/dist/proxy.js.map +1 -0
  38. package/dist/registry/apis.json +95362 -202
  39. package/dist/registry/apis_expanded.json +100853 -0
  40. package/dist/stripe.d.ts +68 -0
  41. package/dist/stripe.d.ts.map +1 -0
  42. package/dist/stripe.js +196 -0
  43. package/dist/stripe.js.map +1 -0
  44. package/dist/test.d.ts +3 -2
  45. package/dist/test.d.ts.map +1 -1
  46. package/dist/test.js +105 -75
  47. package/dist/test.js.map +1 -1
  48. package/dist/types.d.ts +0 -28
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/webhook.d.ts +2 -0
  51. package/dist/webhook.d.ts.map +1 -0
  52. package/dist/webhook.js +90 -0
  53. package/dist/webhook.js.map +1 -0
  54. package/landing/DESIGN.md +343 -0
  55. package/landing/package-lock.json +1190 -40
  56. package/landing/package.json +5 -2
  57. package/landing/public/android-chrome-192x192.png +0 -0
  58. package/landing/public/android-chrome-512x512.png +0 -0
  59. package/landing/public/apple-touch-icon.png +0 -0
  60. package/landing/public/demo.gif +0 -0
  61. package/landing/public/demo.mp4 +0 -0
  62. package/landing/public/favicon-16x16.png +0 -0
  63. package/landing/public/favicon-32x32.png +0 -0
  64. package/landing/public/favicon.ico +0 -0
  65. package/landing/public/favicon.svg +3 -0
  66. package/landing/public/icon.svg +47 -0
  67. package/landing/public/logo-mono.svg +37 -0
  68. package/landing/public/logo-simple.svg +45 -0
  69. package/landing/public/logo.svg +84 -0
  70. package/landing/public/og-image.png +0 -0
  71. package/landing/public/og-template.html +184 -0
  72. package/landing/public/site.webmanifest +31 -0
  73. package/landing/scripts/generate-assets.js +284 -0
  74. package/landing/scripts/generate-pngs.js +48 -0
  75. package/landing/scripts/generate-stats.js +42 -0
  76. package/landing/src/app/admin/page.tsx +348 -0
  77. package/landing/src/app/api/auth/magic-link/route.ts +73 -0
  78. package/landing/src/app/api/auth/session/route.ts +38 -0
  79. package/landing/src/app/api/auth/verify/route.ts +43 -0
  80. package/landing/src/app/api/og/route.tsx +74 -0
  81. package/landing/src/app/globals.css +439 -100
  82. package/landing/src/app/layout.tsx +37 -9
  83. package/landing/src/app/page.tsx +640 -552
  84. package/landing/src/app/providers/dashboard/login/page.tsx +176 -0
  85. package/landing/src/app/providers/dashboard/page.tsx +589 -0
  86. package/landing/src/app/providers/dashboard/verify/page.tsx +106 -0
  87. package/landing/src/app/providers/layout.tsx +14 -0
  88. package/landing/src/app/providers/page.tsx +402 -0
  89. package/landing/src/app/providers/register/page.tsx +670 -0
  90. package/landing/src/components/ProviderDashboard.tsx +794 -0
  91. package/landing/src/hooks/useDashboardData.ts +99 -0
  92. package/landing/src/lib/apis.json +116054 -0
  93. package/landing/src/lib/convex-client.ts +106 -0
  94. package/landing/src/lib/mock-data.ts +285 -0
  95. package/landing/src/lib/stats.json +6 -0
  96. package/landing/tailwind.config.ts +12 -11
  97. package/landing/tsconfig.tsbuildinfo +1 -0
  98. package/package.json +21 -20
  99. package/scripts/SYMBOT-FIX.md +238 -0
  100. package/scripts/demo-simulation.py +177 -0
  101. package/scripts/expand-more.py +502 -0
  102. package/scripts/expand-registry.py +434 -0
  103. package/scripts/history-sanitizer.ts +272 -0
  104. package/scripts/mass-scrape.py +1308 -0
  105. package/scripts/sync-and-deploy.sh +36 -0
  106. package/src/credentials.ts +177 -0
  107. package/src/credits.ts +190 -122
  108. package/src/discovery.ts +45 -58
  109. package/src/execute.ts +350 -0
  110. package/src/index.ts +113 -31
  111. package/src/proxy.ts +24 -0
  112. package/src/registry/apis.json +95362 -202
  113. package/src/registry/apis_expanded.json +100853 -0
  114. package/src/stripe.ts +243 -0
  115. package/src/test.ts +127 -89
  116. package/src/types.ts +0 -34
  117. package/src/webhook.ts +107 -0
  118. package/.github/ISSUE_TEMPLATE/add-api.yml +0 -123
  119. package/BRIEFING.md +0 -30
  120. package/backend/convex/apiKeys.ts +0 -75
  121. package/backend/convex/purchases.ts +0 -74
  122. package/backend/convex/schema.ts +0 -45
  123. package/backend/convex/transactions.ts +0 -57
  124. package/backend/convex/users.ts +0 -94
  125. package/backend/package-lock.json +0 -521
  126. package/backend/package.json +0 -15
  127. package/dist/registry/parse_apis.py +0 -146
  128. package/dist/revenuecat.d.ts +0 -61
  129. package/dist/revenuecat.d.ts.map +0 -1
  130. package/dist/revenuecat.js +0 -166
  131. package/dist/revenuecat.js.map +0 -1
  132. package/dist/webhooks/revenuecat.d.ts +0 -48
  133. package/dist/webhooks/revenuecat.d.ts.map +0 -1
  134. package/dist/webhooks/revenuecat.js +0 -119
  135. package/dist/webhooks/revenuecat.js.map +0 -1
  136. package/docs/revenuecat-setup.md +0 -89
  137. package/landing/src/app/api/keys/route.ts +0 -71
  138. package/landing/src/app/api/log/route.ts +0 -37
  139. package/landing/src/app/api/stats/route.ts +0 -37
  140. package/landing/src/app/page.tsx.bak +0 -567
  141. package/landing/src/components/AddKeyModal.tsx +0 -159
  142. package/newsletter-template.html +0 -71
  143. package/outreach/OUTREACH-SYSTEM.md +0 -211
  144. package/outreach/email-template.html +0 -179
  145. package/outreach/targets.md +0 -133
  146. package/src/registry/parse_apis.py +0 -146
  147. package/src/revenuecat.ts +0 -239
  148. package/src/webhooks/revenuecat.ts +0 -187
  149. /package/{backend/convex → convex}/README.md +0 -0
  150. /package/{backend/convex → convex}/_generated/api.js +0 -0
  151. /package/{backend/convex → convex}/_generated/dataModel.d.ts +0 -0
  152. /package/{backend/convex → convex}/_generated/server.d.ts +0 -0
  153. /package/{backend/convex → convex}/_generated/server.js +0 -0
  154. /package/{backend/convex → convex}/tsconfig.json +0 -0
@@ -1,123 +0,0 @@
1
- name: "🦞 Add Your API"
2
- description: Submit your API to the APIClaw marketplace
3
- title: "[API] "
4
- labels: ["api-submission", "triage"]
5
- body:
6
- - type: markdown
7
- attributes:
8
- value: |
9
- Thanks for submitting your API to APIClaw! 🦞
10
-
11
- We'll review your submission and get back to you within a few days.
12
-
13
- - type: input
14
- id: api_name
15
- attributes:
16
- label: API Name
17
- description: The name of your API
18
- placeholder: "e.g., Acme Email API"
19
- validations:
20
- required: true
21
-
22
- - type: input
23
- id: api_url
24
- attributes:
25
- label: API URL
26
- description: Link to your API documentation or homepage
27
- placeholder: "https://api.example.com"
28
- validations:
29
- required: true
30
-
31
- - type: textarea
32
- id: description
33
- attributes:
34
- label: Description
35
- description: What does your API do? (2-3 sentences)
36
- placeholder: "Our API enables developers to..."
37
- validations:
38
- required: true
39
-
40
- - type: dropdown
41
- id: category
42
- attributes:
43
- label: Category
44
- description: Primary category for your API
45
- options:
46
- - SMS/Messaging
47
- - Email
48
- - Search
49
- - LLM/AI
50
- - TTS/Voice
51
- - Payments
52
- - Storage
53
- - Auth/Identity
54
- - Analytics
55
- - Other
56
- validations:
57
- required: true
58
-
59
- - type: dropdown
60
- id: auth_type
61
- attributes:
62
- label: Authentication Type
63
- description: How do users authenticate?
64
- options:
65
- - API Key
66
- - OAuth 2.0
67
- - Bearer Token
68
- - Basic Auth
69
- - No Auth
70
- - Other
71
- validations:
72
- required: true
73
-
74
- - type: dropdown
75
- id: pricing
76
- attributes:
77
- label: Pricing Model
78
- description: How is your API priced?
79
- options:
80
- - Free
81
- - Freemium
82
- - Pay-as-you-go
83
- - Subscription
84
- - Enterprise only
85
- validations:
86
- required: true
87
-
88
- - type: input
89
- id: regions
90
- attributes:
91
- label: Supported Regions
92
- description: Where is your API available?
93
- placeholder: "Global, EU, US, etc."
94
- validations:
95
- required: false
96
-
97
- - type: textarea
98
- id: additional
99
- attributes:
100
- label: Additional Information
101
- description: Anything else we should know?
102
- placeholder: "Rate limits, compliance certifications, special features..."
103
- validations:
104
- required: false
105
-
106
- - type: input
107
- id: contact
108
- attributes:
109
- label: Contact Email
110
- description: Email for follow-up questions
111
- placeholder: "api-team@example.com"
112
- validations:
113
- required: true
114
-
115
- - type: checkboxes
116
- id: terms
117
- attributes:
118
- label: Confirmation
119
- options:
120
- - label: I confirm this API has public documentation
121
- required: true
122
- - label: I am authorized to submit this API on behalf of the provider
123
- required: true
package/BRIEFING.md DELETED
@@ -1,30 +0,0 @@
1
- # APIClaw — Symbot Briefing
2
-
3
- **Vad det är:** Agent-native API discovery & purchasing via MCP
4
- **Status:** AKTIVT BYGGE — feedback välkommet
5
-
6
- ## Länkar
7
- - **Landing:** https://landing-peach-delta.vercel.app
8
- - **GitHub:** https://github.com/nordsym/apiclaw
9
- - **Stripe Pro ($99/mo):** https://buy.stripe.com/fZu3cx3W48uC0mo1CMcMM0g
10
- - **Convex Backend:** https://blessed-chicken-640.convex.cloud
11
-
12
- ## Vad det gör
13
- 1. Agenter frågar "I need SMS API"
14
- 2. APIClaw returnerar rankade alternativ med pricing
15
- 3. Agent köper access → får credentials direkt
16
- 4. Ingen dashboard, ingen signup
17
-
18
- ## Stats
19
- - 1,400+ APIs i registret
20
- - 51 kategorier
21
- - Free (5% fee) / Pro $99/mo (2% fee)
22
- - USDC on Base (Coinbase Agent Wallet)
23
-
24
- ## Om någon frågar
25
- - Välkomna feedback!
26
- - Logga deras intresse/frågor
27
- - Erbjud att visa demo eller förklara mer
28
- - Om de vill lista sin API → github.com/nordsym/apiclaw/issues/new?template=add-api.yml
29
-
30
- ## Del av OpenClaw-universumet 🦞
@@ -1,75 +0,0 @@
1
- import { v } from "convex/values";
2
- import { mutation, query } from "./_generated/server";
3
-
4
- // Add a new API key
5
- export const add = mutation({
6
- args: {
7
- userEmail: v.string(),
8
- apiId: v.string(),
9
- apiName: v.string(),
10
- keyName: v.string(),
11
- keyValue: v.string(),
12
- },
13
- handler: async (ctx, args) => {
14
- const id = await ctx.db.insert("apiKeys", {
15
- userEmail: args.userEmail,
16
- apiId: args.apiId,
17
- apiName: args.apiName,
18
- keyName: args.keyName,
19
- keyValue: args.keyValue,
20
- createdAt: Date.now(),
21
- });
22
- return id;
23
- },
24
- });
25
-
26
- // Get all keys for a user
27
- export const listByEmail = query({
28
- args: { userEmail: v.string() },
29
- handler: async (ctx, args) => {
30
- const keys = await ctx.db
31
- .query("apiKeys")
32
- .withIndex("by_email", (q) => q.eq("userEmail", args.userEmail))
33
- .collect();
34
- // Return without exposing full key values
35
- return keys.map((k) => ({
36
- ...k,
37
- keyValue: k.keyValue.slice(0, 4) + "..." + k.keyValue.slice(-4),
38
- _fullKey: undefined, // never expose
39
- }));
40
- },
41
- });
42
-
43
- // Get a specific key (for agent use - requires auth in prod)
44
- export const get = query({
45
- args: {
46
- userEmail: v.string(),
47
- apiId: v.string(),
48
- },
49
- handler: async (ctx, args) => {
50
- const keys = await ctx.db
51
- .query("apiKeys")
52
- .withIndex("by_email_and_api", (q) =>
53
- q.eq("userEmail", args.userEmail).eq("apiId", args.apiId)
54
- )
55
- .collect();
56
- return keys;
57
- },
58
- });
59
-
60
- // Delete a key
61
- export const remove = mutation({
62
- args: { id: v.id("apiKeys") },
63
- handler: async (ctx, args) => {
64
- await ctx.db.delete(args.id);
65
- return { success: true };
66
- },
67
- });
68
-
69
- // Update last used timestamp
70
- export const markUsed = mutation({
71
- args: { id: v.id("apiKeys") },
72
- handler: async (ctx, args) => {
73
- await ctx.db.patch(args.id, { lastUsed: Date.now() });
74
- },
75
- });
@@ -1,74 +0,0 @@
1
- import { query, mutation } from "./_generated/server";
2
- import { v } from "convex/values";
3
-
4
- // Create new API purchase
5
- export const create = mutation({
6
- args: {
7
- userId: v.id("users"),
8
- apiId: v.string(),
9
- credentials: v.any(),
10
- expiresAt: v.optional(v.number()),
11
- },
12
- handler: async (ctx, args) => {
13
- const purchaseId = await ctx.db.insert("purchases", {
14
- userId: args.userId,
15
- apiId: args.apiId,
16
- credentials: args.credentials,
17
- status: "active",
18
- purchasedAt: Date.now(),
19
- expiresAt: args.expiresAt,
20
- });
21
-
22
- return purchaseId;
23
- },
24
- });
25
-
26
- // List user's active purchases
27
- export const listByUser = query({
28
- args: {
29
- userId: v.id("users"),
30
- },
31
- handler: async (ctx, args) => {
32
- const purchases = await ctx.db
33
- .query("purchases")
34
- .withIndex("by_user", (q) => q.eq("userId", args.userId))
35
- .collect();
36
-
37
- // Filter active only
38
- return purchases.filter((p) => p.status === "active");
39
- },
40
- });
41
-
42
- // Get purchase by user and API
43
- export const getByUserAndApi = query({
44
- args: {
45
- userId: v.id("users"),
46
- apiId: v.string(),
47
- },
48
- handler: async (ctx, args) => {
49
- return await ctx.db
50
- .query("purchases")
51
- .withIndex("by_user_and_api", (q) =>
52
- q.eq("userId", args.userId).eq("apiId", args.apiId)
53
- )
54
- .first();
55
- },
56
- });
57
-
58
- // Update purchase status
59
- export const updateStatus = mutation({
60
- args: {
61
- purchaseId: v.id("purchases"),
62
- status: v.string(),
63
- },
64
- handler: async (ctx, args) => {
65
- await ctx.db.patch(args.purchaseId, { status: args.status });
66
- },
67
- });
68
-
69
- // Get all purchases (for admin)
70
- export const listAll = query({
71
- handler: async (ctx) => {
72
- return await ctx.db.query("purchases").collect();
73
- },
74
- });
@@ -1,45 +0,0 @@
1
- import { defineSchema, defineTable } from "convex/server";
2
- import { v } from "convex/values";
3
-
4
- export default defineSchema({
5
- // Users
6
- users: defineTable({
7
- clerkId: v.optional(v.string()),
8
- email: v.string(),
9
- credits: v.number(), // in cents
10
- createdAt: v.number(),
11
- }).index("by_email", ["email"])
12
- .index("by_clerkId", ["clerkId"]),
13
-
14
- // API Purchases
15
- purchases: defineTable({
16
- userId: v.id("users"),
17
- apiId: v.string(), // "46elks", "resend", etc
18
- credentials: v.any(), // encrypted or reference
19
- status: v.string(), // "active", "expired"
20
- purchasedAt: v.number(),
21
- expiresAt: v.optional(v.number()),
22
- }).index("by_user", ["userId"])
23
- .index("by_user_and_api", ["userId", "apiId"]),
24
-
25
- // Transactions
26
- transactions: defineTable({
27
- userId: v.id("users"),
28
- type: v.string(), // "credit_add", "api_purchase"
29
- amount: v.number(),
30
- description: v.string(),
31
- createdAt: v.number(),
32
- }).index("by_user", ["userId"]),
33
-
34
- // BYOK - Bring Your Own Keys
35
- apiKeys: defineTable({
36
- userEmail: v.string(),
37
- apiId: v.string(),
38
- apiName: v.string(),
39
- keyName: v.string(), // "API Key", "Secret Key", etc
40
- keyValue: v.string(), // the actual key (encrypted in prod)
41
- createdAt: v.number(),
42
- lastUsed: v.optional(v.number()),
43
- }).index("by_email", ["userEmail"])
44
- .index("by_email_and_api", ["userEmail", "apiId"]),
45
- });
@@ -1,57 +0,0 @@
1
- import { query, mutation } from "./_generated/server";
2
- import { v } from "convex/values";
3
-
4
- // Log a transaction
5
- export const log = mutation({
6
- args: {
7
- userId: v.id("users"),
8
- type: v.string(), // "credit_add", "api_purchase", "refund"
9
- amount: v.number(),
10
- description: v.string(),
11
- },
12
- handler: async (ctx, args) => {
13
- const transactionId = await ctx.db.insert("transactions", {
14
- userId: args.userId,
15
- type: args.type,
16
- amount: args.amount,
17
- description: args.description,
18
- createdAt: Date.now(),
19
- });
20
-
21
- return transactionId;
22
- },
23
- });
24
-
25
- // Get transaction history for user
26
- export const listByUser = query({
27
- args: {
28
- userId: v.id("users"),
29
- limit: v.optional(v.number()),
30
- },
31
- handler: async (ctx, args) => {
32
- const query = ctx.db
33
- .query("transactions")
34
- .withIndex("by_user", (q) => q.eq("userId", args.userId))
35
- .order("desc");
36
-
37
- if (args.limit) {
38
- return await query.take(args.limit);
39
- }
40
- return await query.collect();
41
- },
42
- });
43
-
44
- // Get all transactions (for admin)
45
- export const listAll = query({
46
- args: {
47
- limit: v.optional(v.number()),
48
- },
49
- handler: async (ctx, args) => {
50
- const query = ctx.db.query("transactions").order("desc");
51
-
52
- if (args.limit) {
53
- return await query.take(args.limit);
54
- }
55
- return await query.collect();
56
- },
57
- });
@@ -1,94 +0,0 @@
1
- import { query, mutation } from "./_generated/server";
2
- import { v } from "convex/values";
3
-
4
- // Get user by email, create if not exists
5
- export const getOrCreate = mutation({
6
- args: {
7
- email: v.string(),
8
- clerkId: v.optional(v.string()),
9
- },
10
- handler: async (ctx, args) => {
11
- // Try to find existing user
12
- const existing = await ctx.db
13
- .query("users")
14
- .withIndex("by_email", (q) => q.eq("email", args.email))
15
- .first();
16
-
17
- if (existing) {
18
- // Update clerkId if provided and not set
19
- if (args.clerkId && !existing.clerkId) {
20
- await ctx.db.patch(existing._id, { clerkId: args.clerkId });
21
- }
22
- return existing._id;
23
- }
24
-
25
- // Create new user
26
- const userId = await ctx.db.insert("users", {
27
- email: args.email,
28
- clerkId: args.clerkId,
29
- credits: 0,
30
- createdAt: Date.now(),
31
- });
32
-
33
- return userId;
34
- },
35
- });
36
-
37
- // Add credits to user
38
- export const addCredits = mutation({
39
- args: {
40
- userId: v.id("users"),
41
- amount: v.number(), // in cents, positive or negative
42
- },
43
- handler: async (ctx, args) => {
44
- const user = await ctx.db.get(args.userId);
45
- if (!user) {
46
- throw new Error("User not found");
47
- }
48
-
49
- const newBalance = user.credits + args.amount;
50
- if (newBalance < 0) {
51
- throw new Error("Insufficient credits");
52
- }
53
-
54
- await ctx.db.patch(args.userId, { credits: newBalance });
55
- return newBalance;
56
- },
57
- });
58
-
59
- // Get current balance
60
- export const getBalance = query({
61
- args: {
62
- userId: v.id("users"),
63
- },
64
- handler: async (ctx, args) => {
65
- const user = await ctx.db.get(args.userId);
66
- if (!user) {
67
- throw new Error("User not found");
68
- }
69
- return user.credits;
70
- },
71
- });
72
-
73
- // Get user by ID
74
- export const get = query({
75
- args: {
76
- userId: v.id("users"),
77
- },
78
- handler: async (ctx, args) => {
79
- return await ctx.db.get(args.userId);
80
- },
81
- });
82
-
83
- // Get user by email
84
- export const getByEmail = query({
85
- args: {
86
- email: v.string(),
87
- },
88
- handler: async (ctx, args) => {
89
- return await ctx.db
90
- .query("users")
91
- .withIndex("by_email", (q) => q.eq("email", args.email))
92
- .first();
93
- },
94
- });