Verification API

Public endpoints for checking license validity. These endpoints don't require authentication, allowing your software to verify licenses from anywhere.

Get Public Key

Fetch the RSA public key for offline verification:

GET /api/v1/apps/:slug/public-key
$ curl https://license.yourapp.com/api/v1/apps/my-app/public-key

# Response (Content-Type: application/x-pem-file)
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2K3...
-----END PUBLIC KEY-----

Verify License

Check license status by installation_id or JTI:

GET /api/v1/apps/:slug/licenses/verify
# By installation_id
$ curl "https://license.yourapp.com/api/v1/apps/my-app/licenses/verify?installation_id=550e8400-e29b-41d4-a716-446655440000"

# Or by JTI (JWT ID)
$ curl "https://license.yourapp.com/api/v1/apps/my-app/licenses/verify?jti=lic_abc123xyz"

# Response
{
  "data": {
    "valid": true,
    "status": "active",
    "tier": "pro",
    "features": ["api_access", "export"],
    "expires_at": "2027-01-23T00:00:00Z",
    "installation_id": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Response Fields

Field Type Description
valid boolean Whether the license is currently valid
status string "active", "expired", or "revoked"
tier string Tier slug
features string[] Enabled feature slugs
expires_at datetime? Expiration timestamp (null for forever licenses)

Batch Verify

Verify multiple licenses in a single request (max 100):

POST /api/v1/apps/:slug/licenses/verify/batch
$ curl -X POST https://license.yourapp.com/api/v1/apps/my-app/licenses/verify/batch \
  -H "Content-Type: application/json" \
  -d '{
    "installation_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "660e8400-e29b-41d4-a716-446655440001"
    ]
  }'

# Or by JTIs
{
  "jtis": ["lic_abc123", "lic_def456"]
}

# Response
{
  "data": {
    "results": {
      "550e8400-e29b-41d4-a716-446655440000": {
        "valid": true,
        "status": "active",
        "tier": "pro"
      },
      "660e8400-e29b-41d4-a716-446655440001": {
        "valid": false,
        "status": "expired",
        "tier": "free"
      }
    }
  },
  "meta": {
    "total": 2,
    "valid_count": 1,
    "invalid_count": 1
  }
}

Rate Limits

Public verification endpoints are rate limited per IP address:

Single Verify

100 requests/minute

Batch Verify

20 requests/minute

429 Too Many Requests

Response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please try again later."
  }
}

Online vs Offline Verification

Online (API)

  • Real-time revocation checks
  • Latest license data
  • Requires network

Offline (JWT)

  • Works without network
  • Instant verification
  • Can't check revocation
Learn more about offline verification

Health Check

Monitor your Blackwalnut instance:

GET /api/health
$ curl https://license.yourapp.com/api/health

{
  "status": "ok",
  "timestamp": "2026-01-23T10:00:00Z"
}