@nordsym/apiclaw 1.2.2 → 1.2.3
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/AGENTS.md +50 -33
- package/README.md +22 -12
- package/SOUL.md +60 -19
- package/STATUS.md +91 -169
- package/convex/_generated/api.d.ts +6 -0
- package/convex/directCall.ts +598 -0
- package/convex/providers.ts +341 -26
- package/convex/schema.ts +87 -0
- package/convex/usage.ts +260 -0
- package/convex/waitlist.ts +55 -0
- package/data/combined-02-26.json +22102 -0
- package/data/night-expansion-02-26-06-batch2.json +1898 -0
- package/data/night-expansion-02-26-06-batch3.json +1410 -0
- package/data/night-expansion-02-26-06.json +3146 -0
- package/data/night-expansion-02-26-full.json +9726 -0
- package/data/night-expansion-02-26-v2.json +330 -0
- package/data/night-expansion-02-26.json +171 -0
- package/dist/crypto.d.ts +7 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +67 -0
- package/dist/crypto.js.map +1 -0
- package/dist/execute-dynamic.d.ts +116 -0
- package/dist/execute-dynamic.d.ts.map +1 -0
- package/dist/execute-dynamic.js +456 -0
- package/dist/execute-dynamic.js.map +1 -0
- package/dist/execute.d.ts +2 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +35 -5
- package/dist/execute.js.map +1 -1
- package/dist/index.js +33 -4
- package/dist/index.js.map +1 -1
- package/dist/registry/apis.json +2081 -3
- package/docs/PRD-customer-key-passthrough.md +184 -0
- package/landing/public/badges/available-on-apiclaw.svg +14 -0
- package/landing/scripts/generate-stats.js +75 -4
- package/landing/src/app/admin/page.tsx +1 -1
- package/landing/src/app/api/auth/magic-link/route.ts +1 -1
- package/landing/src/app/api/auth/session/route.ts +1 -1
- package/landing/src/app/api/auth/verify/route.ts +1 -1
- package/landing/src/app/api/og/route.tsx +5 -3
- package/landing/src/app/docs/page.tsx +5 -4
- package/landing/src/app/earn/page.tsx +14 -11
- package/landing/src/app/globals.css +16 -15
- package/landing/src/app/layout.tsx +2 -2
- package/landing/src/app/page.tsx +425 -254
- package/landing/src/app/providers/dashboard/[apiId]/actions/[actionId]/edit/page.tsx +600 -0
- package/landing/src/app/providers/dashboard/[apiId]/actions/new/page.tsx +583 -0
- package/landing/src/app/providers/dashboard/[apiId]/actions/page.tsx +301 -0
- package/landing/src/app/providers/dashboard/[apiId]/direct-call/page.tsx +659 -0
- package/landing/src/app/providers/dashboard/[apiId]/page.tsx +381 -0
- package/landing/src/app/providers/dashboard/[apiId]/test/page.tsx +418 -0
- package/landing/src/app/providers/dashboard/layout.tsx +292 -0
- package/landing/src/app/providers/dashboard/page.tsx +353 -290
- package/landing/src/app/providers/register/page.tsx +87 -10
- package/landing/src/components/AiClientDropdown.tsx +85 -0
- package/landing/src/components/ConfigHelperModal.tsx +113 -0
- package/landing/src/components/HeroTabs.tsx +187 -0
- package/landing/src/components/ShareIntegrationModal.tsx +198 -0
- package/landing/src/hooks/useDashboardData.ts +53 -1
- package/landing/src/lib/apis.json +46554 -174
- package/landing/src/lib/convex-client.ts +22 -3
- package/landing/src/lib/stats.json +4 -4
- package/landing/tsconfig.tsbuildinfo +1 -1
- package/night-expansion-02-26-06-batch2.py +368 -0
- package/night-expansion-02-26-06-batch3.py +299 -0
- package/night-expansion-02-26-06.py +756 -0
- package/package.json +1 -1
- package/scripts/bulk-add-public-apis-v2.py +418 -0
- package/scripts/night-expansion-02-26-v2.py +296 -0
- package/scripts/night-expansion-02-26.py +890 -0
- package/scripts/seed-complete-api.js +181 -0
- package/scripts/seed-demo-api.sh +44 -0
- package/src/crypto.ts +75 -0
- package/src/execute-dynamic.ts +589 -0
- package/src/execute.ts +41 -5
- package/src/index.ts +38 -4
- package/src/registry/apis.json +2081 -3
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# PRD: Customer Key Passthrough
|
|
2
|
+
|
|
3
|
+
**Status:** DRAFT — väntar på Gustavs attestering
|
|
4
|
+
**Datum:** 2026-02-26
|
|
5
|
+
**Författare:** Symbot
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
CoAccept (och liknande SaaS-providers) vill att deras slutkunder (t.ex. hyresvärdar) ska kunna styra CoAccept via AI-agent. Men:
|
|
12
|
+
|
|
13
|
+
1. Varje slutkund har egen CoAccept API-nyckel
|
|
14
|
+
2. APIClaw sparar idag EN master key per provider
|
|
15
|
+
3. Ingen mekanism för "denna request kommer från Kund X"
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Mål
|
|
20
|
+
|
|
21
|
+
Möjliggöra att agent users skickar med sin egen provider-nyckel vid Direct Call — **utan sign-up friction**.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Constraints (KRITISKA)
|
|
26
|
+
|
|
27
|
+
| Constraint | Varför |
|
|
28
|
+
|------------|--------|
|
|
29
|
+
| **Ingen sign-up för agent user** | Friktion = death. Free credits + search ska vara friktionsfritt. |
|
|
30
|
+
| **Search alltid gratis** | Hela databasen (19k APIs) sökbar utan login |
|
|
31
|
+
| **Open APIs gratis** | Discovery + open API calls = $0 |
|
|
32
|
+
| **Direct Call med free credits** | Agent user kan testa Direct Call utan betalning |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Lösningsförslag
|
|
37
|
+
|
|
38
|
+
### Option A: `customer_key` parameter (Rekommenderad)
|
|
39
|
+
|
|
40
|
+
Agent skickar med sin egen nyckel i anropet:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
api_direct_call({
|
|
44
|
+
provider: "coaccept",
|
|
45
|
+
action: "send_reminder",
|
|
46
|
+
params: { tenant_id: "123" },
|
|
47
|
+
customer_key: "hyresvärdens-coaccept-api-key" // <-- NY
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Flow:**
|
|
52
|
+
1. Agent anropar med `customer_key`
|
|
53
|
+
2. APIClaw använder `customer_key` istället för master key
|
|
54
|
+
3. CoAccept ser anropet som vanlig API-request från sin kund
|
|
55
|
+
4. APIClaw loggar usage (för analytics, ej billing på kundens nyckel)
|
|
56
|
+
|
|
57
|
+
**Fördelar:**
|
|
58
|
+
- Ingen sign-up behövs
|
|
59
|
+
- Agent user kontrollerar sin egen nyckel
|
|
60
|
+
- Provider (CoAccept) ser sin vanliga kund
|
|
61
|
+
- Bakåtkompatibelt (utan `customer_key` = master key används)
|
|
62
|
+
|
|
63
|
+
**Nackdelar:**
|
|
64
|
+
- Nyckel skickas i varje request (måste vara över HTTPS)
|
|
65
|
+
- Agent user måste ha/få sin nyckel från providern
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Option B: Registered customer keys (mer enterprise)
|
|
70
|
+
|
|
71
|
+
Agent user registrerar sin nyckel en gång i APIClaw dashboard, får tillbaka ett `customer_id`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
api_direct_call({
|
|
75
|
+
provider: "coaccept",
|
|
76
|
+
action: "send_reminder",
|
|
77
|
+
params: { tenant_id: "123" },
|
|
78
|
+
customer_id: "cust_abc123" // Referens till sparad nyckel
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Fördelar:**
|
|
83
|
+
- Nyckel skickas inte i varje request
|
|
84
|
+
- Kan bygga usage tracking per customer
|
|
85
|
+
- Möjliggör billing per customer senare
|
|
86
|
+
|
|
87
|
+
**Nackdelar:**
|
|
88
|
+
- Kräver sign-up/registration (BRYTER CONSTRAINT)
|
|
89
|
+
- Mer komplext
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Rekommendation
|
|
94
|
+
|
|
95
|
+
**Option A först.**
|
|
96
|
+
|
|
97
|
+
Enklast, friktionsfritt, löser CoAccept-caset direkt. Option B kan byggas senare som "enterprise mode" för de som vill.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Implementation (Option A)
|
|
102
|
+
|
|
103
|
+
### 1. MCP Tool Update
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// Befintlig
|
|
107
|
+
api_direct_call(provider, action, params)
|
|
108
|
+
|
|
109
|
+
// Ny
|
|
110
|
+
api_direct_call(provider, action, params, customer_key?)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 2. execute-dynamic.ts
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// I executeAction():
|
|
117
|
+
const apiKey = args.customer_key || config.encryptedMasterKey;
|
|
118
|
+
// Använd apiKey för auth header
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Provider Config (optional flag)
|
|
122
|
+
|
|
123
|
+
Provider kan välja att:
|
|
124
|
+
- `allow_customer_keys: true` — tillåt passthrough
|
|
125
|
+
- `require_customer_keys: true` — ENDAST customer keys (ingen master)
|
|
126
|
+
|
|
127
|
+
CoAccept skulle sätta `require_customer_keys: true` eftersom varje hyresvärd måste autentisera sig själv.
|
|
128
|
+
|
|
129
|
+
### 4. Logging
|
|
130
|
+
|
|
131
|
+
Logga `customer_key_used: true/false` i usage logs (inte själva nyckeln).
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Vad som INTE ändras
|
|
136
|
+
|
|
137
|
+
- ✅ Search — fortfarande gratis, ingen login
|
|
138
|
+
- ✅ Open APIs — fortfarande gratis
|
|
139
|
+
- ✅ Free credits — fortfarande tillgängliga
|
|
140
|
+
- ✅ Master key Direct Call — funkar som innan (default)
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Scope för V1
|
|
145
|
+
|
|
146
|
+
| Ingår | Ingår ej |
|
|
147
|
+
|-------|----------|
|
|
148
|
+
| `customer_key` parameter i MCP tool | Dashboard för att spara nycklar |
|
|
149
|
+
| execute-dynamic.ts uppdatering | Per-customer billing |
|
|
150
|
+
| Provider flag `allow_customer_keys` | Customer registration flow |
|
|
151
|
+
| Usage logging | |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Effort Estimate
|
|
156
|
+
|
|
157
|
+
| Task | Tid |
|
|
158
|
+
|------|-----|
|
|
159
|
+
| MCP tool schema update | 30 min |
|
|
160
|
+
| execute-dynamic.ts logic | 1h |
|
|
161
|
+
| Provider config flag (Convex + UI) | 1h |
|
|
162
|
+
| Testing | 30 min |
|
|
163
|
+
| **Total** | ~3h |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Öppna frågor
|
|
168
|
+
|
|
169
|
+
1. **Ska vi validera customer_key format?** (Nej — provider's API gör det)
|
|
170
|
+
2. **Rate limits på customer_key?** (V1: Nej. Providern hanterar det.)
|
|
171
|
+
3. **Billing?** (V1: Ingen. Agent user betalar providern direkt.)
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Attestering
|
|
176
|
+
|
|
177
|
+
- [ ] Gustav har läst och godkänt
|
|
178
|
+
- [ ] Scope bekräftat
|
|
179
|
+
- [ ] Constraints respekterade
|
|
180
|
+
- [ ] Klart för implementation
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
*Väntar på din feedback, Gustav.* 🦞
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg width="220" height="44" viewBox="0 0 220 44" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#0a0a0a"/>
|
|
5
|
+
<stop offset="100%" style="stop-color:#1a1a1a"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="220" height="44" rx="8" fill="url(#bgGrad)" stroke="#333" stroke-width="1"/>
|
|
9
|
+
<text x="16" y="28" fill="#ef4444" font-family="system-ui, -apple-system, sans-serif" font-size="18">🦞</text>
|
|
10
|
+
<text x="44" y="27" fill="white" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">Available on</text>
|
|
11
|
+
<text x="44" y="27" fill="white" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">
|
|
12
|
+
<tspan x="130" font-weight="700" fill="#ef4444">APIClaw</tspan>
|
|
13
|
+
</text>
|
|
14
|
+
</svg>
|
|
@@ -2,6 +2,75 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
|
+
// Category mapping (consolidate similar ones)
|
|
6
|
+
const categoryMap = {
|
|
7
|
+
'AI': 'AI & ML',
|
|
8
|
+
'AI & ML': 'AI & ML',
|
|
9
|
+
'AI/ML': 'AI & ML',
|
|
10
|
+
'Machine Learning': 'AI & ML',
|
|
11
|
+
'Authentication': 'Auth & Security',
|
|
12
|
+
'Auth': 'Auth & Security',
|
|
13
|
+
'Security': 'Auth & Security',
|
|
14
|
+
'Payment': 'Payments',
|
|
15
|
+
'Payments': 'Payments',
|
|
16
|
+
'Finance': 'Finance',
|
|
17
|
+
'Cryptocurrency': 'Finance',
|
|
18
|
+
'Currency': 'Finance',
|
|
19
|
+
'Health': 'Health & Fitness',
|
|
20
|
+
'Health & Fitness': 'Health & Fitness',
|
|
21
|
+
'Healthcare': 'Health & Fitness',
|
|
22
|
+
'Fitness': 'Health & Fitness',
|
|
23
|
+
'Social': 'Social & Communication',
|
|
24
|
+
'Social Media': 'Social & Communication',
|
|
25
|
+
'Communication': 'Social & Communication',
|
|
26
|
+
'Messaging': 'Social & Communication',
|
|
27
|
+
'Data': 'Data & Analytics',
|
|
28
|
+
'Data & Analytics': 'Data & Analytics',
|
|
29
|
+
'Analytics': 'Data & Analytics',
|
|
30
|
+
'Big Data': 'Data & Analytics',
|
|
31
|
+
'Cloud': 'Cloud & Infrastructure',
|
|
32
|
+
'Cloud Storage': 'Cloud & Infrastructure',
|
|
33
|
+
'Infrastructure': 'Cloud & Infrastructure',
|
|
34
|
+
'DevOps': 'Development',
|
|
35
|
+
'Development': 'Development',
|
|
36
|
+
'Development Tools': 'Development',
|
|
37
|
+
'Testing': 'Development',
|
|
38
|
+
'E-commerce': 'Commerce',
|
|
39
|
+
'Commerce': 'Commerce',
|
|
40
|
+
'Shopping': 'Commerce',
|
|
41
|
+
'Games': 'Entertainment',
|
|
42
|
+
'Gaming': 'Entertainment',
|
|
43
|
+
'Entertainment': 'Entertainment',
|
|
44
|
+
'Music': 'Entertainment',
|
|
45
|
+
'Video': 'Media',
|
|
46
|
+
'Media': 'Media',
|
|
47
|
+
'Photography': 'Media',
|
|
48
|
+
'News': 'News & Media',
|
|
49
|
+
'News & information': 'News & Media',
|
|
50
|
+
'Geo': 'Location & Maps',
|
|
51
|
+
'Geocoding': 'Location & Maps',
|
|
52
|
+
'Geolocation': 'Location & Maps',
|
|
53
|
+
'Maps': 'Location & Maps',
|
|
54
|
+
'Location': 'Location & Maps',
|
|
55
|
+
'Spatial': 'Location & Maps',
|
|
56
|
+
'Transportation': 'Travel & Transport',
|
|
57
|
+
'Travel': 'Travel & Transport',
|
|
58
|
+
'Logistics': 'Travel & Transport',
|
|
59
|
+
'Delivery-Tracking': 'Travel & Transport',
|
|
60
|
+
'Carsharing': 'Travel & Transport',
|
|
61
|
+
'Document': 'Documents & Files',
|
|
62
|
+
'Documents': 'Documents & Files',
|
|
63
|
+
'File Storage and Manipulation': 'Documents & Files',
|
|
64
|
+
'Web Scraping': 'Search & Scraping',
|
|
65
|
+
'Search': 'Search & Scraping',
|
|
66
|
+
'Text Analysis': 'Language & Text',
|
|
67
|
+
'Language': 'Language & Text',
|
|
68
|
+
'Dictionary': 'Language & Text',
|
|
69
|
+
'Vision Analysis': 'AI & ML',
|
|
70
|
+
'Art & Design': 'Design',
|
|
71
|
+
'Design': 'Design',
|
|
72
|
+
};
|
|
73
|
+
|
|
5
74
|
// Try local copy first (for Vercel), then parent directory (for local dev)
|
|
6
75
|
const localRegistryPath = path.join(__dirname, '../src/lib/apis.json');
|
|
7
76
|
const parentRegistryPath = path.join(__dirname, '../../src/registry/apis.json');
|
|
@@ -11,11 +80,13 @@ const outputPath = path.join(__dirname, '../src/lib/stats.json');
|
|
|
11
80
|
try {
|
|
12
81
|
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
13
82
|
|
|
14
|
-
|
|
83
|
+
// Consolidate categories using the mapping
|
|
84
|
+
const consolidatedCategories = registry.apis.map(api => categoryMap[api.category] || api.category);
|
|
85
|
+
const uniqueCategories = [...new Set(consolidatedCategories)];
|
|
15
86
|
|
|
16
87
|
const stats = {
|
|
17
88
|
apiCount: registry.count,
|
|
18
|
-
categoryCount:
|
|
89
|
+
categoryCount: uniqueCategories.length,
|
|
19
90
|
lastUpdated: registry.lastUpdated || new Date().toISOString().split('T')[0],
|
|
20
91
|
generatedAt: new Date().toISOString()
|
|
21
92
|
};
|
|
@@ -32,8 +103,8 @@ try {
|
|
|
32
103
|
console.error('Failed to generate stats:', err);
|
|
33
104
|
// Write fallback stats
|
|
34
105
|
const fallback = {
|
|
35
|
-
apiCount:
|
|
36
|
-
categoryCount:
|
|
106
|
+
apiCount: 19176,
|
|
107
|
+
categoryCount: 58,
|
|
37
108
|
lastUpdated: new Date().toISOString().split('T')[0],
|
|
38
109
|
generatedAt: new Date().toISOString()
|
|
39
110
|
};
|
|
@@ -4,7 +4,7 @@ import { useState, useEffect } from "react";
|
|
|
4
4
|
import { Shield, Users, Zap, TrendingUp, Check, X, Clock, ExternalLink, RefreshCw, Eye } from "lucide-react";
|
|
5
5
|
import Link from "next/link";
|
|
6
6
|
|
|
7
|
-
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://
|
|
7
|
+
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
|
|
8
8
|
|
|
9
9
|
interface Stats {
|
|
10
10
|
totalProviders: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from "next/server";
|
|
2
2
|
|
|
3
|
-
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://
|
|
3
|
+
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
|
|
4
4
|
|
|
5
5
|
export async function POST(req: NextRequest) {
|
|
6
6
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from "next/server";
|
|
2
2
|
|
|
3
|
-
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://
|
|
3
|
+
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
|
|
4
4
|
|
|
5
5
|
export async function POST(req: NextRequest) {
|
|
6
6
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from "next/server";
|
|
2
2
|
|
|
3
|
-
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://
|
|
3
|
+
const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
|
|
4
4
|
|
|
5
5
|
export async function POST(req: NextRequest) {
|
|
6
6
|
try {
|
|
@@ -52,17 +52,19 @@ export async function GET() {
|
|
|
52
52
|
<div
|
|
53
53
|
style={{
|
|
54
54
|
display: 'flex',
|
|
55
|
-
gap:
|
|
55
|
+
gap: 32,
|
|
56
56
|
marginTop: 40,
|
|
57
57
|
color: '#ef4444',
|
|
58
|
-
fontSize:
|
|
58
|
+
fontSize: 26,
|
|
59
59
|
}}
|
|
60
60
|
>
|
|
61
61
|
<span>{statsData.apiCount.toLocaleString()}+ APIs</span>
|
|
62
62
|
<span>•</span>
|
|
63
|
-
<span>{statsData.categoryCount}
|
|
63
|
+
<span>{statsData.categoryCount} Categories</span>
|
|
64
64
|
<span>•</span>
|
|
65
65
|
<span>MCP Native</span>
|
|
66
|
+
<span>•</span>
|
|
67
|
+
<span>Direct Call</span>
|
|
66
68
|
</div>
|
|
67
69
|
<div
|
|
68
70
|
style={{
|
|
@@ -35,8 +35,9 @@ export default function DocsPage() {
|
|
|
35
35
|
</Link>
|
|
36
36
|
<nav className="flex items-center gap-4 md:gap-6">
|
|
37
37
|
<Link href="/" className="hidden sm:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">Home</Link>
|
|
38
|
-
<
|
|
39
|
-
<Link href="/
|
|
38
|
+
<span className="hidden md:block text-[var(--accent)] font-medium text-sm md:text-base">Docs</span>
|
|
39
|
+
<Link href="/providers/dashboard" className="hidden md:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">Providers</Link>
|
|
40
|
+
<Link href="/earn" className="hidden md:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">Earn</Link>
|
|
40
41
|
<a
|
|
41
42
|
href="https://github.com/nordsym/apiclaw"
|
|
42
43
|
target="_blank"
|
|
@@ -192,7 +193,7 @@ export default function DocsPage() {
|
|
|
192
193
|
{/* discover_apis */}
|
|
193
194
|
<div className="bg-[var(--surface)] border border-[var(--border)] rounded-xl p-6">
|
|
194
195
|
<h3 className="text-lg font-mono text-[var(--accent)] mb-2">discover_apis</h3>
|
|
195
|
-
<p className="text-[var(--text-secondary)] mb-4">Search
|
|
196
|
+
<p className="text-[var(--text-secondary)] mb-4">Search 19,000+ APIs using natural language.</p>
|
|
196
197
|
<pre className="bg-[var(--surface-elevated)] border border-[var(--border)] rounded-lg p-4 overflow-x-auto">
|
|
197
198
|
<code className="text-sm">
|
|
198
199
|
<span className="text-purple-600 dark:text-purple-400">discover_apis</span>({'{\n'}
|
|
@@ -310,7 +311,7 @@ export default function DocsPage() {
|
|
|
310
311
|
</li>
|
|
311
312
|
<li>
|
|
312
313
|
<strong>Email:</strong>{' '}
|
|
313
|
-
<a href="mailto:
|
|
314
|
+
<a href="mailto:symbot@nordsym.com" className="text-[var(--accent)] hover:underline">symbot@nordsym.com</a>
|
|
314
315
|
</li>
|
|
315
316
|
</ul>
|
|
316
317
|
</div>
|
|
@@ -13,9 +13,9 @@ const EARN_CHANNELS = [
|
|
|
13
13
|
credits: 500,
|
|
14
14
|
cta: 'Star Repository',
|
|
15
15
|
href: 'https://github.com/nordsym/apiclaw',
|
|
16
|
-
color: 'from-
|
|
17
|
-
borderColor: 'hover:border-
|
|
18
|
-
iconColor: 'text-
|
|
16
|
+
color: 'from-red-500/20 to-orange-500/10',
|
|
17
|
+
borderColor: 'hover:border-red-500/50',
|
|
18
|
+
iconColor: 'text-red-500',
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
id: 'twitter',
|
|
@@ -25,9 +25,9 @@ const EARN_CHANNELS = [
|
|
|
25
25
|
credits: 250,
|
|
26
26
|
cta: 'Follow Us',
|
|
27
27
|
href: 'https://x.com/NordSym',
|
|
28
|
-
color: 'from-
|
|
29
|
-
borderColor: 'hover:border-
|
|
30
|
-
iconColor: 'text-
|
|
28
|
+
color: 'from-red-400/20 to-rose-500/10',
|
|
29
|
+
borderColor: 'hover:border-red-400/50',
|
|
30
|
+
iconColor: 'text-red-400',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
id: 'newsletter',
|
|
@@ -37,9 +37,9 @@ const EARN_CHANNELS = [
|
|
|
37
37
|
credits: 100,
|
|
38
38
|
cta: 'Subscribe',
|
|
39
39
|
href: '#newsletter',
|
|
40
|
-
color: 'from-
|
|
41
|
-
borderColor: 'hover:border-
|
|
42
|
-
iconColor: 'text-
|
|
40
|
+
color: 'from-rose-500/20 to-red-500/10',
|
|
41
|
+
borderColor: 'hover:border-rose-500/50',
|
|
42
|
+
iconColor: 'text-rose-500',
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
id: 'referral',
|
|
@@ -120,12 +120,15 @@ export default function EarnPage() {
|
|
|
120
120
|
<Link href="/" className="hidden sm:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">
|
|
121
121
|
Home
|
|
122
122
|
</Link>
|
|
123
|
-
<Link href="/docs" className="text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">
|
|
123
|
+
<Link href="/docs" className="hidden md:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">
|
|
124
124
|
Docs
|
|
125
125
|
</Link>
|
|
126
|
-
<Link href="/providers" className="hidden md:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">
|
|
126
|
+
<Link href="/providers/dashboard" className="hidden md:block text-[var(--text-secondary)] hover:text-[var(--accent)] transition-colors text-sm md:text-base">
|
|
127
127
|
Providers
|
|
128
128
|
</Link>
|
|
129
|
+
<span className="text-[var(--accent)] font-medium text-sm md:text-base">
|
|
130
|
+
Earn
|
|
131
|
+
</span>
|
|
129
132
|
<button
|
|
130
133
|
onClick={toggleTheme}
|
|
131
134
|
className="p-2 rounded-lg bg-[var(--surface)] border border-[var(--border)] hover:border-[var(--accent)]/50 transition-colors"
|
|
@@ -471,36 +471,37 @@ input[type="email"]::placeholder {
|
|
|
471
471
|
|
|
472
472
|
/* Code preview */
|
|
473
473
|
.code-preview {
|
|
474
|
-
background: linear-gradient(180deg, #
|
|
475
|
-
border: 1px solid rgba(
|
|
474
|
+
background: linear-gradient(180deg, #0f1419 0%, #080b0e 100%);
|
|
475
|
+
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
476
476
|
border-radius: 14px;
|
|
477
477
|
overflow: hidden;
|
|
478
478
|
font-family: 'JetBrains Mono', monospace;
|
|
479
479
|
font-size: 13px;
|
|
480
480
|
box-shadow:
|
|
481
|
-
0 0 40px rgba(
|
|
482
|
-
0 0 80px rgba(
|
|
481
|
+
0 0 40px rgba(0, 212, 255, 0.15),
|
|
482
|
+
0 0 80px rgba(0, 212, 255, 0.05),
|
|
483
483
|
0 8px 32px rgba(0, 0, 0, 0.5),
|
|
484
484
|
inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
|
485
485
|
transition: all 0.3s ease;
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
.code-preview:hover {
|
|
489
|
-
border-color: rgba(
|
|
490
|
-
transform: translateY(-
|
|
489
|
+
border-color: rgba(0, 212, 255, 0.5);
|
|
490
|
+
transform: translateY(-2px);
|
|
491
491
|
box-shadow:
|
|
492
|
-
0 0 60px rgba(
|
|
493
|
-
0 0 100px rgba(
|
|
492
|
+
0 0 60px rgba(0, 212, 255, 0.25),
|
|
493
|
+
0 0 100px rgba(0, 212, 255, 0.1),
|
|
494
494
|
0 16px 48px rgba(0, 0, 0, 0.6),
|
|
495
495
|
inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
.code-preview-header {
|
|
499
499
|
padding: 10px 16px;
|
|
500
|
-
background:
|
|
501
|
-
border-bottom: 1px solid
|
|
502
|
-
color: #
|
|
500
|
+
background: rgba(0, 212, 255, 0.05);
|
|
501
|
+
border-bottom: 1px solid rgba(0, 212, 255, 0.15);
|
|
502
|
+
color: #00D4FF;
|
|
503
503
|
font-size: 12px;
|
|
504
|
+
font-weight: 500;
|
|
504
505
|
}
|
|
505
506
|
|
|
506
507
|
.code-preview-body {
|
|
@@ -514,10 +515,10 @@ input[type="email"]::placeholder {
|
|
|
514
515
|
}
|
|
515
516
|
|
|
516
517
|
.code-comment { color: #6b7280; }
|
|
517
|
-
.code-string { color: #
|
|
518
|
-
.code-keyword { color: #
|
|
519
|
-
.code-function { color: #
|
|
520
|
-
.code-property { color: #
|
|
518
|
+
.code-string { color: #00D4FF; }
|
|
519
|
+
.code-keyword { color: #9370DB; }
|
|
520
|
+
.code-function { color: #FF8C00; }
|
|
521
|
+
.code-property { color: #00D4FF; }
|
|
521
522
|
|
|
522
523
|
/* Logo animation */
|
|
523
524
|
.logo-float {
|
|
@@ -18,13 +18,13 @@ export const metadata: Metadata = {
|
|
|
18
18
|
},
|
|
19
19
|
openGraph: {
|
|
20
20
|
title: "APIClaw | The API Layer for AI Agents",
|
|
21
|
-
description:
|
|
21
|
+
description: `${statsData.apiCount.toLocaleString()}+ APIs. MCP native. Direct Call: providers self-serve their APIs for AI agents.`,
|
|
22
22
|
type: "website",
|
|
23
23
|
siteName: "APIClaw",
|
|
24
24
|
locale: "en_US",
|
|
25
25
|
images: [
|
|
26
26
|
{
|
|
27
|
-
url: "/api/og",
|
|
27
|
+
url: "/api/og?v=2",
|
|
28
28
|
width: 1200,
|
|
29
29
|
height: 630,
|
|
30
30
|
alt: "APIClaw - The API layer for AI agents",
|