curl -X POST https://www.wiseyield.co/api/api-keys \
-H "Authorization: Bearer {CLERK_SESSION_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0"
}
}'
const response = await fetch(
'https://www.wiseyield.co/api/api-keys',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production API Key',
environment: 'live',
scopes: ['farms:read', 'farms:write', 'crops:read', 'crops:write'],
rateLimit: 5000,
metadata: {
application: 'web-dashboard',
version: '1.0.0'
}
})
}
);
const apiKey = await response.json();
// ⚠️ SAVE THIS KEY - IT WON'T BE SHOWN AGAIN!
console.log('Your API Key:', apiKey.key);
// Store in environment variables
process.env.WISEYIELD_API_KEY = apiKey.key;
async function createAndStoreApiKey(keyData) {
try {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(keyData)
});
if (!response.ok) {
const error = await response.json();
if (response.status === 400) {
if (error.message?.includes('Maximum of 10')) {
toast.error('You have reached the maximum of 10 API keys. Please revoke unused keys.');
} else if (error.details?.invalidScopes) {
toast.error(`Invalid scopes: ${error.details.invalidScopes.join(', ')}`);
} else {
toast.error(error.message || 'Validation failed');
}
return;
}
if (response.status === 401) {
router.push('/sign-in');
return;
}
toast.error('Failed to create API key');
return;
}
const newKey = await response.json();
// ⚠️ CRITICAL: Show key to user for copying
await showApiKeyModal({
key: newKey.key,
name: newKey.name,
message: '⚠️ Save this key now! It will never be shown again.'
});
toast.success('API key created successfully');
return newKey;
} catch (error) {
toast.error('Network error. Please try again.');
}
}
import requests
from datetime import datetime, timedelta
# Create key that expires in 90 days
expires_at = (datetime.utcnow() + timedelta(days=90)).isoformat()
response = requests.post(
'https://www.wiseyield.co/api/api-keys',
headers={
'Authorization': 'Bearer {CLERK_SESSION_TOKEN}',
'Content-Type': 'application/json'
},
json={
'name': 'Production API Key',
'environment': 'live',
'scopes': ['farms:read', 'crops:read', 'analytics:read'],
'rateLimit': 2000,
'expiresAt': expires_at
}
)
result = response.json()
if response.status_code == 201:
# ⚠️ SAVE THIS KEY IMMEDIATELY!
api_key = result['key']
print(f"Your API Key: {api_key}")
print("Save this key securely - it won't be shown again!")
# Store in environment file (example)
with open('.env', 'a') as f:
f.write(f'\nWISEYIELD_API_KEY={api_key}\n')
else:
print(f"Error: {result.get('error')}")
if 'details' in result:
print(f"Details: {result['details']}")
{
"id": "key_abc123xyz789def456",
"key": "wy_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2",
"keyPrefix": "wy_live_a1b2c3d4",
"keyPreview": "wy_live_a1b2c3d4...****",
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"isActive": true,
"usageCount": 0,
"lastUsedAt": null,
"createdAt": "2025-10-30T10:00:00.000Z",
"updatedAt": "2025-10-30T10:00:00.000Z",
"expiresAt": null,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0",
"userAgent": "Mozilla/5.0..."
}
}
{
"error": "Validation failed",
"message": "Name and at least one scope are required"
}
{
"error": "Validation failed",
"message": "Invalid scopes provided",
"details": {
"invalidScopes": ["invalid:scope"],
"validScopes": [
"farms:read", "farms:write",
"crops:read", "crops:write",
"fields:read", "fields:write",
"analytics:read",
"tasks:read", "tasks:write",
"team:read", "team:write",
"webhooks:read", "webhooks:write",
"all"
]
}
}
{
"error": "Limit exceeded",
"message": "Maximum of 10 active API keys per user"
}
{
"error": "Validation failed",
"message": "Environment must be \"live\" or \"test\""
}
{
"error": "Validation failed",
"message": "Rate limit must be between 1 and 100,000"
}
{
"error": "Validation failed",
"message": "Expiry date must be in the future"
}
{
"error": "Unauthorized",
"message": "Authentication required"
}
{
"error": "Forbidden",
"message": "API access requires the Summit tier. Upgrade at /dashboard/billing.",
"code": "TIER_INSUFFICIENT",
"details": { "currentTier": "professional", "requiredTier": "summit" }
}
{
"error": "Internal server error"
}
API Keys
Create API Key
Generate a new API key for programmatic access to the WiseYield API
POST
/
api
/
api-keys
curl -X POST https://www.wiseyield.co/api/api-keys \
-H "Authorization: Bearer {CLERK_SESSION_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0"
}
}'
const response = await fetch(
'https://www.wiseyield.co/api/api-keys',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production API Key',
environment: 'live',
scopes: ['farms:read', 'farms:write', 'crops:read', 'crops:write'],
rateLimit: 5000,
metadata: {
application: 'web-dashboard',
version: '1.0.0'
}
})
}
);
const apiKey = await response.json();
// ⚠️ SAVE THIS KEY - IT WON'T BE SHOWN AGAIN!
console.log('Your API Key:', apiKey.key);
// Store in environment variables
process.env.WISEYIELD_API_KEY = apiKey.key;
async function createAndStoreApiKey(keyData) {
try {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(keyData)
});
if (!response.ok) {
const error = await response.json();
if (response.status === 400) {
if (error.message?.includes('Maximum of 10')) {
toast.error('You have reached the maximum of 10 API keys. Please revoke unused keys.');
} else if (error.details?.invalidScopes) {
toast.error(`Invalid scopes: ${error.details.invalidScopes.join(', ')}`);
} else {
toast.error(error.message || 'Validation failed');
}
return;
}
if (response.status === 401) {
router.push('/sign-in');
return;
}
toast.error('Failed to create API key');
return;
}
const newKey = await response.json();
// ⚠️ CRITICAL: Show key to user for copying
await showApiKeyModal({
key: newKey.key,
name: newKey.name,
message: '⚠️ Save this key now! It will never be shown again.'
});
toast.success('API key created successfully');
return newKey;
} catch (error) {
toast.error('Network error. Please try again.');
}
}
import requests
from datetime import datetime, timedelta
# Create key that expires in 90 days
expires_at = (datetime.utcnow() + timedelta(days=90)).isoformat()
response = requests.post(
'https://www.wiseyield.co/api/api-keys',
headers={
'Authorization': 'Bearer {CLERK_SESSION_TOKEN}',
'Content-Type': 'application/json'
},
json={
'name': 'Production API Key',
'environment': 'live',
'scopes': ['farms:read', 'crops:read', 'analytics:read'],
'rateLimit': 2000,
'expiresAt': expires_at
}
)
result = response.json()
if response.status_code == 201:
# ⚠️ SAVE THIS KEY IMMEDIATELY!
api_key = result['key']
print(f"Your API Key: {api_key}")
print("Save this key securely - it won't be shown again!")
# Store in environment file (example)
with open('.env', 'a') as f:
f.write(f'\nWISEYIELD_API_KEY={api_key}\n')
else:
print(f"Error: {result.get('error')}")
if 'details' in result:
print(f"Details: {result['details']}")
{
"id": "key_abc123xyz789def456",
"key": "wy_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2",
"keyPrefix": "wy_live_a1b2c3d4",
"keyPreview": "wy_live_a1b2c3d4...****",
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"isActive": true,
"usageCount": 0,
"lastUsedAt": null,
"createdAt": "2025-10-30T10:00:00.000Z",
"updatedAt": "2025-10-30T10:00:00.000Z",
"expiresAt": null,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0",
"userAgent": "Mozilla/5.0..."
}
}
{
"error": "Validation failed",
"message": "Name and at least one scope are required"
}
{
"error": "Validation failed",
"message": "Invalid scopes provided",
"details": {
"invalidScopes": ["invalid:scope"],
"validScopes": [
"farms:read", "farms:write",
"crops:read", "crops:write",
"fields:read", "fields:write",
"analytics:read",
"tasks:read", "tasks:write",
"team:read", "team:write",
"webhooks:read", "webhooks:write",
"all"
]
}
}
{
"error": "Limit exceeded",
"message": "Maximum of 10 active API keys per user"
}
{
"error": "Validation failed",
"message": "Environment must be \"live\" or \"test\""
}
{
"error": "Validation failed",
"message": "Rate limit must be between 1 and 100,000"
}
{
"error": "Validation failed",
"message": "Expiry date must be in the future"
}
{
"error": "Unauthorized",
"message": "Authentication required"
}
{
"error": "Forbidden",
"message": "API access requires the Summit tier. Upgrade at /dashboard/billing.",
"code": "TIER_INSUFFICIENT",
"details": { "currentTier": "professional", "requiredTier": "summit" }
}
{
"error": "Internal server error"
}
Endpoint
POST https://www.wiseyield.co/api/api-keys
Dashboard-only endpoint. Called from the WiseYield UI with browser cookies (Clerk session). Not callable from a server-to-server integration today. To mint API keys, sign in to the dashboard and use Settings → API Keys → Create API Key.
Summit-tier only. API key creation requires an active Summit subscription. Requests from users on Seed / Sprout / Harvest / Grove / Trial tiers return
403 TIER_INSUFFICIENT. See Subscription tiers for what’s included at each tier.Authentication
Requires a signed-in WiseYield session. TheBearer examples below show the response wire format but are not directly callable outside the browser session.
Request Body
User-friendly name for the API key (e.g., “Production Server”, “Mobile App”)
Array of permission scopes. At least one scope required.Available Scopes:
farms:read,farms:writecrops:read,crops:writefields:read,fields:writelibrary:read,library:writemarket:readanalytics:readtasks:read,tasks:writeteam:read,team:writewebhooks:read,webhooks:writeall(full access)
Environment type:
live (production) or test (development)Maximum API requests per hour (1-100,000)
ISO 8601 datetime when key should expire (optional, no expiration if omitted)
Custom metadata to attach to the key (optional)
Response
Returns the newly created API key object with the full key.Unique identifier (format:
key_{nanoid})⚠️ CRITICAL: Full API key (shown ONLY ONCE, never retrievable again)Format:
wy_{environment}_{48_hex_characters}First 16 characters for identification
Masked version for display
Name provided in request
Environment:
live or testArray of granted permission scopes
Requests per hour limit
Always
true on creationAlways
0 on creationAlways
null on creationISO 8601 timestamp of creation
ISO 8601 timestamp of last update
Expiration timestamp (null if no expiration)
Custom metadata (includes userAgent automatically)
curl -X POST https://www.wiseyield.co/api/api-keys \
-H "Authorization: Bearer {CLERK_SESSION_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0"
}
}'
const response = await fetch(
'https://www.wiseyield.co/api/api-keys',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production API Key',
environment: 'live',
scopes: ['farms:read', 'farms:write', 'crops:read', 'crops:write'],
rateLimit: 5000,
metadata: {
application: 'web-dashboard',
version: '1.0.0'
}
})
}
);
const apiKey = await response.json();
// ⚠️ SAVE THIS KEY - IT WON'T BE SHOWN AGAIN!
console.log('Your API Key:', apiKey.key);
// Store in environment variables
process.env.WISEYIELD_API_KEY = apiKey.key;
async function createAndStoreApiKey(keyData) {
try {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(keyData)
});
if (!response.ok) {
const error = await response.json();
if (response.status === 400) {
if (error.message?.includes('Maximum of 10')) {
toast.error('You have reached the maximum of 10 API keys. Please revoke unused keys.');
} else if (error.details?.invalidScopes) {
toast.error(`Invalid scopes: ${error.details.invalidScopes.join(', ')}`);
} else {
toast.error(error.message || 'Validation failed');
}
return;
}
if (response.status === 401) {
router.push('/sign-in');
return;
}
toast.error('Failed to create API key');
return;
}
const newKey = await response.json();
// ⚠️ CRITICAL: Show key to user for copying
await showApiKeyModal({
key: newKey.key,
name: newKey.name,
message: '⚠️ Save this key now! It will never be shown again.'
});
toast.success('API key created successfully');
return newKey;
} catch (error) {
toast.error('Network error. Please try again.');
}
}
import requests
from datetime import datetime, timedelta
# Create key that expires in 90 days
expires_at = (datetime.utcnow() + timedelta(days=90)).isoformat()
response = requests.post(
'https://www.wiseyield.co/api/api-keys',
headers={
'Authorization': 'Bearer {CLERK_SESSION_TOKEN}',
'Content-Type': 'application/json'
},
json={
'name': 'Production API Key',
'environment': 'live',
'scopes': ['farms:read', 'crops:read', 'analytics:read'],
'rateLimit': 2000,
'expiresAt': expires_at
}
)
result = response.json()
if response.status_code == 201:
# ⚠️ SAVE THIS KEY IMMEDIATELY!
api_key = result['key']
print(f"Your API Key: {api_key}")
print("Save this key securely - it won't be shown again!")
# Store in environment file (example)
with open('.env', 'a') as f:
f.write(f'\nWISEYIELD_API_KEY={api_key}\n')
else:
print(f"Error: {result.get('error')}")
if 'details' in result:
print(f"Details: {result['details']}")
{
"id": "key_abc123xyz789def456",
"key": "wy_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2",
"keyPrefix": "wy_live_a1b2c3d4",
"keyPreview": "wy_live_a1b2c3d4...****",
"name": "Production API Key",
"environment": "live",
"scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
"rateLimit": 5000,
"isActive": true,
"usageCount": 0,
"lastUsedAt": null,
"createdAt": "2025-10-30T10:00:00.000Z",
"updatedAt": "2025-10-30T10:00:00.000Z",
"expiresAt": null,
"metadata": {
"application": "web-dashboard",
"version": "1.0.0",
"userAgent": "Mozilla/5.0..."
}
}
{
"error": "Validation failed",
"message": "Name and at least one scope are required"
}
{
"error": "Validation failed",
"message": "Invalid scopes provided",
"details": {
"invalidScopes": ["invalid:scope"],
"validScopes": [
"farms:read", "farms:write",
"crops:read", "crops:write",
"fields:read", "fields:write",
"analytics:read",
"tasks:read", "tasks:write",
"team:read", "team:write",
"webhooks:read", "webhooks:write",
"all"
]
}
}
{
"error": "Limit exceeded",
"message": "Maximum of 10 active API keys per user"
}
{
"error": "Validation failed",
"message": "Environment must be \"live\" or \"test\""
}
{
"error": "Validation failed",
"message": "Rate limit must be between 1 and 100,000"
}
{
"error": "Validation failed",
"message": "Expiry date must be in the future"
}
{
"error": "Unauthorized",
"message": "Authentication required"
}
{
"error": "Forbidden",
"message": "API access requires the Summit tier. Upgrade at /dashboard/billing.",
"code": "TIER_INSUFFICIENT",
"details": { "currentTier": "professional", "requiredTier": "summit" }
}
{
"error": "Internal server error"
}
Errors
Bad Request - Validation failed (missing fields, invalid scopes, limit exceeded)
Unauthorized - User not signed in
Internal Server Error - Failed to create API key
How It Works
Creation Flow:- Authentication: Verifies user is signed in
- Validation: Checks all required fields and constraints:
- Name and scopes are required
- Scopes must be from valid list
- Environment must be “live” or “test”
- Rate limit: 1-100,000
- Expiry date must be in future
- Limit Check: Ensures user has < 10 active keys
- Key Generation:
- Generates 24 random bytes (48 hex chars)
- Formats as
wy_{environment}_{random} - Creates SHA-256 hash for storage
- Extracts first 16 chars as prefix
- Database Insert: Saves key with metadata
- Audit Log: Records creation for security tracking
- Response: Returns full key (only time it’s shown)
- Only SHA-256 hash stored in database
- Full key never retrievable after creation
- Prefix stored for identification
- User-agent automatically captured in metadata
API Key Structure
Key Format
wy_{environment}_{48_hexadecimal_characters}
wy_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2
wy_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8
wy_- WiseYield identifier{environment}-liveortest{random}- 48 hexadecimal characters (cryptographically secure)
Storage
Database:keyHash- SHA-256 hash of full keykeyPrefix- First 16 characters (for display/identification)
- Full API key value (security best practice)
Scopes Reference
Farm Management
Crop Management
Field Management
Analytics
Task Management
Team Management
Webhooks
Full Access
Use Cases
Production Key with Limited Scopes
async function createProductionKey() {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production Server',
environment: 'live',
scopes: [
'farms:read',
'crops:read',
'fields:read',
'analytics:read'
], // Read-only access
rateLimit: 10000,
metadata: {
server: 'prod-api-01',
region: 'us-east-1'
}
})
});
const key = await response.json();
// ⚠️ Save to secure storage
await storeInVault('WISEYIELD_API_KEY', key.key);
return key;
}
Test Key with Full Access
async function createTestKey() {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Local Development',
environment: 'test',
scopes: ['all'], // Full access for testing
rateLimit: 1000
})
});
const key = await response.json();
// Can safely add to .env.local for development
console.log('Add to .env.local:');
console.log(`WISEYIELD_API_KEY=${key.key}`);
return key;
}
Temporary Key with Expiration
async function createTemporaryKey(daysUntilExpiry = 30) {
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + daysUntilExpiry);
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: `Temporary Access (${daysUntilExpiry}d)`,
environment: 'live',
scopes: ['farms:read', 'crops:read'],
expiresAt: expiresAt.toISOString(),
rateLimit: 500,
metadata: {
purpose: 'temporary-integration',
requestedBy: 'partner-xyz'
}
})
});
const key = await response.json();
// Share with partner
console.log('Temporary key created');
console.log(`Expires: ${new Date(key.expiresAt).toLocaleDateString()}`);
return key;
}
Mobile App Key
async function createMobileAppKey() {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'iOS App v2.1',
environment: 'live',
scopes: [
'farms:read',
'crops:read',
'crops:write',
'tasks:read',
'tasks:write'
],
rateLimit: 2000,
metadata: {
platform: 'ios',
appVersion: '2.1.0',
buildNumber: '142'
}
})
});
const key = await response.json();
// Embed in app configuration
return key;
}
Best Practices
Save Immediately: Copy the full key to secure storage as soon as it’s created. It cannot be retrieved later.
Principle of Least Privilege: Grant only the scopes needed for the specific use case.
Use Test Keys for Development: Create
test environment keys for local development and testing.Set Expiration: For temporary access, always set an
expiresAt date.Descriptive Names: Use clear, descriptive names that indicate purpose and environment.
Metadata for Tracking: Use metadata to track which application, server, or user is using each key.
One-Time Display: The full API key is shown ONLY once. Save it immediately or lose it forever.
10 Key Limit: Maximum 10 active API keys per user. Revoke unused keys before creating new ones.
Never Commit Keys: Never commit API keys to version control. Use environment variables.
Rotate Regularly: Create new keys and revoke old ones periodically for security.
Security Best Practices
Key Storage:# ✅ GOOD: Environment variables
WISEYIELD_API_KEY=wy_live_abc123...
# ✅ GOOD: Secret management services
aws secretsmanager create-secret --name wiseyield-api-key
# ❌ BAD: Hardcoded in code
const apiKey = "wy_live_abc123..."
# ❌ BAD: Committed to git
git add .env # If .env contains keys!
async function rotateApiKey(oldKeyId) {
// 1. Create new key
const newKey = await createApiKey({
name: 'Production Server (Rotated)',
environment: 'live',
scopes: [...],
rateLimit: 10000
});
// 2. Update application config
await updateEnvVar('WISEYIELD_API_KEY', newKey.key);
// 3. Test new key
await testApiKey(newKey.key);
// 4. Revoke old key
await revokeApiKey(oldKeyId);
}
// ✅ GOOD: Minimal scopes
const readOnlyKey = {
scopes: ['farms:read', 'crops:read']
};
// ⚠️ CAUTION: Broad access
const writeKey = {
scopes: ['farms:write', 'crops:write', 'fields:write']
};
// ⚠️ DANGER: Full access
const adminKey = {
scopes: ['all'] // Only for trusted applications
};
Integration Examples
API Key Creation Modal
function CreateApiKeyModal({ isOpen, onClose, onCreated }) {
const [formData, setFormData] = useState({
name: '',
environment: 'live',
scopes: [],
rateLimit: 1000,
expiresAt: '',
});
const [creating, setCreating] = useState(false);
const [createdKey, setCreatedKey] = useState(null);
async function handleCreate() {
setCreating(true);
try {
const response = await fetch('/api/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${clerkSessionToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
...formData,
expiresAt: formData.expiresAt || undefined
})
});
if (!response.ok) {
const error = await response.json();
toast.error(error.message || 'Failed to create API key');
return;
}
const newKey = await response.json();
setCreatedKey(newKey);
toast.success('API key created');
onCreated?.(newKey);
} finally {
setCreating(false);
}
}
if (createdKey) {
return (
<Modal open={isOpen} onClose={onClose}>
<ModalTitle>API Key Created</ModalTitle>
<ModalContent>
<Alert severity="warning">
<AlertTitle>Save This Key Now!</AlertTitle>
<p>This is the only time you'll see the full key. Copy it to a secure location.</p>
</Alert>
<div className="my-4">
<label className="block text-sm font-medium mb-2">API Key</label>
<div className="flex gap-2">
<code className="flex-1 p-3 bg-gray-100 rounded font-mono text-sm break-all">
{createdKey.key}
</code>
<button
onClick={() => {
navigator.clipboard.writeText(createdKey.key);
toast.success('Copied to clipboard');
}}
className="btn btn-secondary"
>
Copy
</button>
</div>
</div>
<div className="text-sm text-gray-600">
<div><strong>Name:</strong> {createdKey.name}</div>
<div><strong>Environment:</strong> {createdKey.environment}</div>
<div><strong>Rate Limit:</strong> {createdKey.rateLimit}/hour</div>
</div>
</ModalContent>
<ModalActions>
<button onClick={onClose} className="btn btn-primary">
I've Saved My Key
</button>
</ModalActions>
</Modal>
);
}
return (
<Modal open={isOpen} onClose={onClose}>
<ModalTitle>Create API Key</ModalTitle>
<ModalContent>
<form className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">Name *</label>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="e.g., Production Server"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Environment</label>
<select
value={formData.environment}
onChange={(e) => setFormData({ ...formData, environment: e.target.value })}
>
<option value="live">Live (Production)</option>
<option value="test">Test (Development)</option>
</select>
</div>
<div>
<label className="block text-sm font-medium mb-2">Scopes *</label>
<ScopeSelector
selected={formData.scopes}
onChange={(scopes) => setFormData({ ...formData, scopes })}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Rate Limit (requests/hour)
</label>
<input
type="number"
value={formData.rateLimit}
onChange={(e) => setFormData({ ...formData, rateLimit: parseInt(e.target.value) })}
min="1"
max="100000"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Expiration Date (optional)
</label>
<input
type="datetime-local"
value={formData.expiresAt}
onChange={(e) => setFormData({ ...formData, expiresAt: e.target.value })}
/>
</div>
</form>
</ModalContent>
<ModalActions>
<button onClick={onClose} disabled={creating}>
Cancel
</button>
<button
onClick={handleCreate}
disabled={!formData.name || formData.scopes.length === 0 || creating}
className="btn btn-primary"
>
{creating ? 'Creating...' : 'Create API Key'}
</button>
</ModalActions>
</Modal>
);
}
Related Endpoints
- List API Keys - GET to list all API keys
- Revoke API Key - DELETE to revoke existing key
⌘I