API Overview

Fence provides a RESTful API for integrating security scanning into your development workflow, CI/CD pipelines, and custom applications.

Availability

Tier API Access Rate Limit Features
Hobby ❌ No N/A Web interface only
Startup ✅ Yes 1,000 requests/hour Full API access, webhooks
Enterprise ✅ Yes Unlimited Full API, custom integrations, priority support
Custom ✅ Yes Custom White-label API, dedicated endpoints

Authentication

Fence uses API tokens for authentication. Tokens are prefixed with fence_ for leak detection.

Creating an API Token

  1. Log in to Fence dashboard
  2. Navigate to SettingsAPI Tokens
  3. Click Create Token
  4. Choose token scope:
  5. Read-only - View domains, scans, vulnerabilities (no modifications)
  6. Full access - Read + write + trigger scans
  7. Copy token (shown once only)
  8. Store securely (environment variable, secrets manager)

Using Tokens

Include token in Authorization header:

curl -H "Authorization: Bearer fence_abc123..." \
  https://fence.dev/api/domains/

Token security:
- Tokens expire after 90 days (automatic rotation)
- Tokens can be revoked anytime
- Leaked tokens detected via GitHub Secret Scanning
- Last used timestamp tracked for auditing

API Base URL

Production: https://fence.dev/api/
Staging: https://beta.fence.dev/api/

Response Format

All responses are JSON with consistent structure:

Success Response

{
  "id": "uuid",
  "name": "example.com",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-20T14:45:00Z"
}

List Response (Paginated)

{
  "count": 47,
  "next": "https://fence.dev/api/domains/?page=2",
  "previous": null,
  "results": [
    {
      "id": "uuid-1",
      "name": "example.com"
    },
    {
      "id": "uuid-2",
      "name": "api.example.com"
    }
  ]
}

Error Response

{
  "error": "Not found",
  "message": "Domain with ID 'abc123' does not exist",
  "code": 404
}

Rate Limiting

API responses include rate limit headers (GitHub-style):

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1640995200

When rate limited:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200
Retry-After: 3600

Rate limit tiers:
- Startup: 1,000 requests/hour
- Enterprise: Unlimited
- Custom: Custom limits

Common Endpoints

Domains

# List all domains
GET /api/domains/

# Create domain
POST /api/domains/
{
  "name": "example.com",
  "verification_method": "dns"
}

# Get domain details
GET /api/domains/{domain_id}/

# Trigger scan
POST /api/domains/{domain_id}/scan/

Scans

# List scans
GET /api/scans/

# Get scan details
GET /api/scans/{scan_id}/

# Get scan results
GET /api/scans/{scan_id}/vulnerabilities/

Vulnerabilities

# List all vulnerabilities
GET /api/vulnerabilities/

# Get vulnerability details
GET /api/vulnerabilities/{vuln_id}/

# Mark as false positive
POST /api/vulnerabilities/{vuln_id}/false-positive/
{
  "reason": "Input sanitized by WAF"
}

Webhooks

Receive real-time notifications when:
- Scan completes
- Vulnerability detected (Critical/High severity)
- Certificate expires soon
- Domain verification fails

Learn more about webhooks →

SDKs

Official SDKs available:

Language Install Documentation
Python pip install fence-sdk https://pypi.org/project/fence-sdk
Node.js npm install @fence/sdk https://www.npmjs.com/package/@fence/sdk
Go go get github.com/fence/go-sdk https://pkg.go.dev/github.com/fence/go-sdk
Ruby gem install fence https://rubygems.org/gems/fence

Python SDK Example

from fence import FenceClient

client = FenceClient(api_token="fence_abc123...")

# List domains
domains = client.domains.list()

# Trigger scan
scan = client.domains.scan(domain_id="uuid")

# Wait for completion
scan.wait()

# Get vulnerabilities
vulnerabilities = scan.vulnerabilities()
for vuln in vulnerabilities:
    print(f"{vuln.severity}: {vuln.title}")

CI/CD Integration

GitHub Actions

name: Security Scan
on: [push, pull_request]

jobs:
  fence-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Fence scan
        run: |
          curl -X POST \
            -H "Authorization: Bearer ${{ secrets.FENCE_API_TOKEN }}" \
            -H "Content-Type: application/json" \
            https://fence.dev/api/domains/${{ secrets.DOMAIN_ID }}/scan/

      - name: Wait for scan completion
        run: |
          # Poll scan status until complete
          SCAN_ID=$(curl -H "Authorization: Bearer ${{ secrets.FENCE_API_TOKEN }}" \
            https://fence.dev/api/scans/latest/ | jq -r '.id')

          while true; do
            STATUS=$(curl -H "Authorization: Bearer ${{ secrets.FENCE_API_TOKEN }}" \
              https://fence.dev/api/scans/$SCAN_ID/ | jq -r '.status')

            if [ "$STATUS" = "COMPLETED" ]; then
              break
            fi
            sleep 30
          done

      - name: Check for critical vulnerabilities
        run: |
          CRITICAL=$(curl -H "Authorization: Bearer ${{ secrets.FENCE_API_TOKEN }}" \
            "https://fence.dev/api/scans/$SCAN_ID/vulnerabilities/?severity=CRITICAL" | jq '.count')

          if [ "$CRITICAL" -gt 0 ]; then
            echo "❌ Critical vulnerabilities detected!"
            exit 1
          fi

GitLab CI

fence-scan:
  stage: security
  script:
    - |
      # Trigger scan
      SCAN_RESPONSE=$(curl -X POST \
        -H "Authorization: Bearer $FENCE_API_TOKEN" \
        https://fence.dev/api/domains/$DOMAIN_ID/scan/)

      SCAN_ID=$(echo $SCAN_RESPONSE | jq -r '.id')

      # Wait for completion
      while true; do
        STATUS=$(curl -H "Authorization: Bearer $FENCE_API_TOKEN" \
          https://fence.dev/api/scans/$SCAN_ID/ | jq -r '.status')

        [ "$STATUS" = "COMPLETED" ] && break
        sleep 30
      done

      # Fail on critical vulnerabilities
      CRITICAL=$(curl -H "Authorization: Bearer $FENCE_API_TOKEN" \
        "https://fence.dev/api/scans/$SCAN_ID/vulnerabilities/?severity=CRITICAL" | jq '.count')

      [ "$CRITICAL" -gt 0 ] && exit 1 || exit 0
  only:
    - main

OpenAPI Specification

Full API documentation available in OpenAPI 3.0 format:

https://fence.dev/api/schema/
https://fence.dev/api/swagger/  (Swagger UI)
https://fence.dev/api/redoc/    (ReDoc UI)

Import into Postman:
1. Open Postman
2. File → Import
3. Enter URL: https://fence.dev/api/schema/
4. Click Import

Error Codes

Code Meaning Common Causes
400 Bad Request Invalid JSON, missing required fields
401 Unauthorized Missing or invalid API token
403 Forbidden Token doesn't have required permissions
404 Not Found Resource doesn't exist
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Contact support
503 Service Unavailable Scheduled maintenance

Best Practices

Token Security

  • ✅ Store tokens in environment variables
  • ✅ Use secrets managers (AWS Secrets Manager, HashiCorp Vault)
  • ✅ Rotate tokens every 90 days
  • ✅ Use read-only tokens when possible
  • ❌ Never commit tokens to Git
  • ❌ Never share tokens in logs or error messages

Rate Limiting

  • Use pagination for large result sets
  • Implement exponential backoff when rate limited
  • Cache responses when possible
  • Batch operations instead of individual API calls

Error Handling

import requests
from requests.exceptions import HTTPError

try:
    response = requests.post(
        "https://fence.dev/api/domains/uuid/scan/",
        headers={"Authorization": f"Bearer {api_token}"},
        timeout=30
    )
    response.raise_for_status()
except HTTPError as e:
    if e.response.status_code == 429:
        # Rate limited - wait and retry
        retry_after = int(e.response.headers.get('Retry-After', 3600))
        time.sleep(retry_after)
    elif e.response.status_code == 401:
        # Token invalid/expired
        print("API token expired - please renew")
    else:
        raise

Support

  • API Documentation: https://fence.dev/api/docs/
  • Status Page: https://status.fence.dev
  • Support Email: [email protected]
  • Slack Community: https://fence.dev/slack (Enterprise+)

Next Steps

Was this page helpful?

Let us know if you have any questions or suggestions.