Skip to main content
GET
/
api
/
api-keys
curl -X GET https://www.wiseyield.co/api/api-keys \
  -H "Authorization: Bearer {CLERK_SESSION_TOKEN}"
{
  "data": [
    {
      "id": "key_abc123xyz789",
      "name": "Production API Key",
      "keyPrefix": "wy_live_a1b2c3d4",
      "keyPreview": "wy_live_a1b2c3d4...****",
      "environment": "live",
      "scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
      "isActive": true,
      "lastUsedAt": "2025-10-29T14:30:00.000Z",
      "usageCount": 1523,
      "rateLimit": 5000,
      "createdAt": "2025-10-01T10:00:00.000Z",
      "updatedAt": "2025-10-29T14:30:00.000Z",
      "expiresAt": null,
      "metadata": {
        "userAgent": "Mozilla/5.0..."
      }
    },
    {
      "id": "key_def456uvw012",
      "name": "Development Testing",
      "keyPrefix": "wy_test_e5f6g7h8",
      "keyPreview": "wy_test_e5f6g7h8...****",
      "environment": "test",
      "scopes": ["all"],
      "isActive": true,
      "lastUsedAt": null,
      "usageCount": 0,
      "rateLimit": 1000,
      "createdAt": "2025-10-15T16:20:00.000Z",
      "updatedAt": "2025-10-15T16:20:00.000Z",
      "expiresAt": "2025-12-31T23:59:59.000Z",
      "metadata": {}
    }
  ],
  "total": 2
}

Documentation Index

Fetch the complete documentation index at: https://docs.wiseyield.co/llms.txt

Use this file to discover all available pages before exploring further.

Endpoint

GET https://www.wiseyield.co/api/api-keys
Dashboard-only endpoint. Authentication is via the WiseYield browser session (Clerk cookies). It cannot be called from a server-to-server integration today. Use the WiseYield dashboard’s Settings → API Keys page to manage keys; this page documents the wire format that page consumes.

Authentication

Requires a signed-in WiseYield session (Clerk cookies set by the dashboard). The cURL and Bearer examples below illustrate the wire shape but are not directly callable outside the browser — fetch('/api/api-keys', { credentials: 'include' }) from the dashboard is how it’s actually invoked.

Response

Returns list of API keys with usage statistics.
data
array
Array of API key objects (sorted by creation date, newest first)
total
number
Total number of active API keys
curl -X GET https://www.wiseyield.co/api/api-keys \
  -H "Authorization: Bearer {CLERK_SESSION_TOKEN}"
{
  "data": [
    {
      "id": "key_abc123xyz789",
      "name": "Production API Key",
      "keyPrefix": "wy_live_a1b2c3d4",
      "keyPreview": "wy_live_a1b2c3d4...****",
      "environment": "live",
      "scopes": ["farms:read", "farms:write", "crops:read", "crops:write"],
      "isActive": true,
      "lastUsedAt": "2025-10-29T14:30:00.000Z",
      "usageCount": 1523,
      "rateLimit": 5000,
      "createdAt": "2025-10-01T10:00:00.000Z",
      "updatedAt": "2025-10-29T14:30:00.000Z",
      "expiresAt": null,
      "metadata": {
        "userAgent": "Mozilla/5.0..."
      }
    },
    {
      "id": "key_def456uvw012",
      "name": "Development Testing",
      "keyPrefix": "wy_test_e5f6g7h8",
      "keyPreview": "wy_test_e5f6g7h8...****",
      "environment": "test",
      "scopes": ["all"],
      "isActive": true,
      "lastUsedAt": null,
      "usageCount": 0,
      "rateLimit": 1000,
      "createdAt": "2025-10-15T16:20:00.000Z",
      "updatedAt": "2025-10-15T16:20:00.000Z",
      "expiresAt": "2025-12-31T23:59:59.000Z",
      "metadata": {}
    }
  ],
  "total": 2
}

Errors

401
error
Unauthorized - User not signed in via Clerk
500
error
Internal Server Error - Failed to fetch API keys

How It Works

Query Flow:
  1. Authentication: Verifies user is signed in via Clerk
  2. Database Query: Fetches all API keys where:
    • userId matches authenticated user
    • revokedAt is null (not revoked)
  3. Sorting: Orders by createdAt descending (newest first)
  4. Security Masking: Masks full keys using maskApiKey() function
  5. Response: Returns array of masked keys with metadata
What’s Hidden: Full API key value is NEVER returned in list responses. Only the prefix and masked preview are shown. What’s Shown: All metadata (name, scopes, usage stats, expiration) is visible.

API Key Structure

Key Format

wy_{environment}_{48_hex_characters}

Example (Live):
wy_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2

Example (Test):
wy_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8
Components:
  • Prefix: wy_ (WiseYield identifier)
  • Environment: live or test
  • Random part: 48 hexadecimal characters (24 random bytes)

Environments

Available Scopes

Farm Management:
  • farms:read - View farms
  • farms:write - Create and update farms
Crop Management:
  • crops:read - View crops
  • crops:write - Create and update crops
Field Management:
  • fields:read - View fields
  • fields:write - Create and update fields
Analytics:
  • analytics:read - View analytics and predictions
Task Management:
  • tasks:read - View tasks
  • tasks:write - Create and update tasks
Team Management:
  • team:read - View team members
  • team:write - Manage team members
Webhooks:
  • webhooks:read - View webhooks
  • webhooks:write - Create and update webhooks
Full Access:
  • all - Full access to all resources

Use Cases

Display API Keys Table

function ApiKeysTable() {
  const [keys, setKeys] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadKeys() {
      const response = await fetch('/api/api-keys', {
        headers: { 'Authorization': `Bearer ${clerkSessionToken}` }
      });

      const { data } = await response.json();
      setKeys(data);
      setLoading(false);
    }

    loadKeys();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Key</th>
          <th>Environment</th>
          <th>Scopes</th>
          <th>Usage</th>
          <th>Created</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        {keys.map((key) => (
          <tr key={key.id}>
            <td>{key.name}</td>
            <td>
              <code className="text-sm">{key.keyPreview}</code>
            </td>
            <td>
              <Badge color={key.environment === 'live' ? 'green' : 'blue'}>
                {key.environment}
              </Badge>
            </td>
            <td>
              <div className="flex flex-wrap gap-1">
                {key.scopes.map((scope) => (
                  <Badge key={scope} variant="outline" size="sm">
                    {scope}
                  </Badge>
                ))}
              </div>
            </td>
            <td>
              <div className="text-sm">
                <div>{key.usageCount.toLocaleString()} requests</div>
                <div className="text-gray-500">
                  {key.rateLimit.toLocaleString()}/hour limit
                </div>
              </div>
            </td>
            <td>
              {new Date(key.createdAt).toLocaleDateString()}
            </td>
            <td>
              <button onClick={() => revokeKey(key.id)}>
                Revoke
              </button>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Check Key Usage

async function checkKeyUsage(keyId) {
  const response = await fetch('/api/api-keys');
  const { data } = await response.json();

  const key = data.find(k => k.id === keyId);

  if (!key) {
    console.log('Key not found or revoked');
    return;
  }

  const percentUsed = (key.usageCount / key.rateLimit) * 100;

  console.log(`Key: ${key.name}`);
  console.log(`Usage: ${key.usageCount} / ${key.rateLimit} (${percentUsed.toFixed(1)}%)`);
  console.log(`Last used: ${key.lastUsedAt || 'Never'}`);

  if (percentUsed > 80) {
    console.warn('⚠️ Approaching rate limit!');
  }
}

Filter by Environment

async function getProductionKeys() {
  const response = await fetch('/api/api-keys');
  const { data } = await response.json();

  const liveKeys = data.filter(key => key.environment === 'live');
  const testKeys = data.filter(key => key.environment === 'test');

  return { liveKeys, testKeys };
}

Check for Expiring Keys

async function checkExpiringKeys() {
  const response = await fetch('/api/api-keys');
  const { data } = await response.json();

  const now = new Date();
  const thirtyDaysFromNow = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

  const expiringSoon = data.filter(key => {
    if (!key.expiresAt) return false;

    const expiresAt = new Date(key.expiresAt);
    return expiresAt < thirtyDaysFromNow && expiresAt > now;
  });

  if (expiringSoon.length > 0) {
    console.warn(`${expiringSoon.length} key(s) expiring within 30 days:`);
    expiringSoon.forEach(key => {
      console.log(`- ${key.name}: expires ${new Date(key.expiresAt).toLocaleDateString()}`);
    });
  }
}

Best Practices

Regular Audits: Review API keys list monthly to remove unused keys.
Monitor Usage: Check usageCount and lastUsedAt to identify inactive keys.
Environment Separation: Use test keys for development, live keys only in production.
Scope Principle: Grant minimum scopes needed for each use case.
Full Keys Never Shown: The complete API key is only shown once during creation. Save it securely.
Revoked Keys Excluded: This endpoint only returns active keys (revokedAt = null).
10 Key Limit: Each user can have maximum 10 active API keys. Revoke unused ones.

Security Considerations

Key Storage:
  • Only SHA-256 hash stored in database
  • Prefix stored for identification (first 16 chars)
  • Full key never retrievable after creation
Display Safety:
  • Keys masked in UI: wy_live_abc123de...****
  • Prevents accidental exposure in screenshots
  • Safe to display in logs and monitoring
Scope Isolation:
  • Keys cannot access resources outside their scopes
  • all scope grants full access (use cautiously)
  • Scopes validated on every API request