Skip to main content

API Reference

Monitor domains, read scan results and issue free certificates from your own code or an AI agent. Generated from the running code, so it matches what the API returns. Machine-readable: openapi.json.

Overview

Base URL and responses

  • All endpoints live under https://tlsradar.com/api/v1.
  • Successful JSON responses wrap the result in data: {"data": {...}} for one record, {"data": [...]} for a list.
  • Errors return {"error": "..."} or {"errors": ["..."]} with a 4xx status. The full machine-readable spec is at /api/v1/openapi.json.

Authentication

  • Send a credential as Authorization: Bearer <token> on every authenticated request.
  • API keys: create one on the API Keys page of the dashboard (/api_keys) or with POST /api/v1/api_keys. A key is shown once. New keys get the read scope unless you choose more.
  • OAuth 2.0: OAuth 2.0 Authorization Code + PKCE. Public clients can self-register via RFC 7591 at /oauth/register. See /.well-known/oauth-authorization-server for the full metadata document.
  • A credential stops working when it is revoked or expires, or when the account is suspended or deleted.

Scopes

  • read: Read access to scans, monitors, teams, and account.
  • write: Create and modify monitors, teams, scans.
  • admin: All read + write plus account-level operations.
  • admin includes write and read. A request with too narrow a credential gets 403 with required_scope and your_scopes.

Team roles

  • A credential acts as its user, and the user's role in a team decides what they can change there.
  • Owner: everything, including members, deleting the team and billing.
  • Admin: add and remove monitors, edit scan groups, run scans and rename the team. Inviting, removing and changing members is owner-only.
  • Guest: read-only. A guest can list monitors and read scan results, but any change returns 403, whatever the credential's scope.
  • An invited user has no access until they accept the invitation. A team they are not an accepted member of returns 404.

Rate and plan limits

  • Authenticated endpoints: 1,000 requests per hour per credential, on every plan.
  • Public endpoints (/info, /pricing, /features, /openapi.json): 100 requests per minute per IP address.
  • Free scan (POST /scan): 20 per hour per IP address, and 10 per hour for any one scanned domain.
  • Over a limit you get 429 with retry_after in seconds and a Retry-After header.
  • Manual scans: one every 5 minutes on the free plan and during a trial (429 with retry_after when it is too soon). Paid plans have no cooldown. The team owner's plan sets it, whoever asks for the scan.
  • Domains per plan: Free 1, Starter 10, Pro 50, Business 200, Enterprise unlimited; 3 during the 30-day trial. The team owner's plan counts, whoever adds the domain.
  • Adding a domain past the limit returns 402 (single host) or 422 (a scan group with a list of addresses); nothing is created.

Public

Publicly accessible endpoints (no authentication required)

GET /api/v1/info

  • Get application information
  • Returns general information about TLS Radar service
  • Authentication: none (public).
  • Response 200: Application information

GET /api/v1/pricing

  • Get pricing information
  • Returns all subscription tiers with pricing, limits, and features
  • Authentication: none (public).
  • Response 200: Pricing tiers
  • Response field currency (string)
  • Response field tiers (array of object)

GET /api/v1/features

  • Get available features
  • Returns all features and which tiers have access to them
  • Authentication: none (public).
  • Response 200: Feature list

Free Scanner

Free SSL/TLS scanner - no authentication required

POST /api/v1/scan

  • Scan a domain's SSL/TLS configuration
  • Initiates a free, one-time SSL/TLS scan of any domain. Scans run asynchronously - the response returns immediately with status 202 (Accepted) and a share_token. Poll GET /scan/{share_token} until scan_status changes from 'pending' to 'success' or 'failed'. Results are cached. Rate limited to 20 requests/hour per IP, 10/hour per domain, 30/hour per device.
  • Authentication: none (public).
  • Request body field domain (string, required): Domain to scan (e.g., example.com)
  • Response 200: Cached scan result (already completed)
  • Response field data.domain (string): Scanned domain
  • Response field data.grade (string, one of A+/A/B/C/D/F, may be null): Overall SSL/TLS grade (null while pending)
  • Response field data.scan_status (string, one of pending/success/failed): Current scan status. Poll until not 'pending'.
  • Response field data.scanned_at (date-time)
  • Response field data.share_token (string): Token for sharing/polling this result
  • Response field data.share_url (uri): Shareable URL for this result
  • Response field data.pdf_url (uri, may be null): PDF report download URL (null while pending)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.issues (array of object)
  • Response field data.certificate (object)
  • Response field data.monitor_cta (object): Call-to-action for continuous monitoring signup
  • Response 202: Scan initiated - poll GET /scan/{share_token} for results
  • Response field data.domain (string): Scanned domain
  • Response field data.grade (string, one of A+/A/B/C/D/F, may be null): Overall SSL/TLS grade (null while pending)
  • Response field data.scan_status (string, one of pending/success/failed): Current scan status. Poll until not 'pending'.
  • Response field data.scanned_at (date-time)
  • Response field data.share_token (string): Token for sharing/polling this result
  • Response field data.share_url (uri): Shareable URL for this result
  • Response field data.pdf_url (uri, may be null): PDF report download URL (null while pending)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.issues (array of object)
  • Response field data.certificate (object)
  • Response field data.monitor_cta (object): Call-to-action for continuous monitoring signup
  • Error 422: Invalid domain or scan failure
  • Error 429: Rate limit exceeded

GET /api/v1/scan/{share_token}

  • Retrieve or poll a scan result by share token
  • Returns a scan result by share token. Use this endpoint to poll for async scan completion - check scan_status field: 'pending' means still scanning, 'success' or 'failed' means done. Results are retained for 1 year. Share tokens are included in scan responses so results can be shared with colleagues.
  • Authentication: none (public).
  • Path parameter share_token (string, required): Unique share token from a scan result
  • Response 200: Scan result (may be pending, success, or failed)
  • Response field data.domain (string): Scanned domain
  • Response field data.grade (string, one of A+/A/B/C/D/F, may be null): Overall SSL/TLS grade (null while pending)
  • Response field data.scan_status (string, one of pending/success/failed): Current scan status. Poll until not 'pending'.
  • Response field data.scanned_at (date-time)
  • Response field data.share_token (string): Token for sharing/polling this result
  • Response field data.share_url (uri): Shareable URL for this result
  • Response field data.pdf_url (uri, may be null): PDF report download URL (null while pending)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.issues (array of object)
  • Response field data.certificate (object)
  • Response field data.monitor_cta (object): Call-to-action for continuous monitoring signup
  • Error 404: Scan result not found

GET /api/v1/scan/{share_token}/pdf

  • Download PDF report for a scan result
  • Generates and returns a PDF report for a completed scan result. Returns 202 if the scan is still in progress.
  • Authentication: none (public).
  • Path parameter share_token (string, required): Unique share token from a scan result
  • Response 200: PDF report file
  • Response 202: Scan is still in progress
  • Error 404: Scan result not found

POST /api/v1/scan/{share_token}/email_pdf

  • Email PDF report for a scan result
  • Sends a PDF report of the scan result to the specified email address.
  • Authentication: none (public).
  • Path parameter share_token (string, required): Unique share token from a scan result
  • Request body field email (email, required): Recipient email address
  • Response 200: PDF report queued for delivery
  • Response field data.message (string)
  • Response field data.domain (string)
  • Response field data.email (email)
  • Error 404: Scan result not found
  • Error 422: Invalid email address

POST /api/v1/scan/{share_token}/email_link

  • Email shareable link for a scan result
  • Sends a shareable link to the scan result to the specified email address.
  • Authentication: none (public).
  • Path parameter share_token (string, required): Unique share token from a scan result
  • Request body field email (email, required): Recipient email address
  • Response 200: Shareable link queued for delivery
  • Response field data.message (string)
  • Response field data.domain (string)
  • Response field data.email (email)
  • Error 404: Scan result not found
  • Error 422: Invalid email address

Teams

Team management operations

GET /api/v1/teams

  • List all teams
  • Returns all teams the authenticated user belongs to Requires the read scope.
  • Response 200: List of teams
  • Response field data[].id (uuid)
  • Response field data[].name (string)
  • Response field data[].status (string, one of active/disabled)
  • Response field data[].owner_id (uuid)
  • Response field data[].created_at (date-time)
  • Response field data[].updated_at (date-time)
  • Response field data[].stats (object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.

POST /api/v1/teams

  • Create a new team
  • Creates a new team owned by the authenticated user Requires the write scope.
  • Request body field team.name (string, required): Team name
  • Response 201: Team created
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.status (string, one of active/disabled)
  • Response field data.owner_id (uuid)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Response field data.stats (object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 402: Plan limit reached. The body names the limit, the current plan and the upgrade options.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

GET /api/v1/teams/{team_id}

  • Get team details
  • Returns detailed information about a specific team Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Response 200: Team details
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.status (string, one of active/disabled)
  • Response field data.owner_id (uuid)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Response field data.stats (object)
  • Response field data.members (array of object): Accepted members only
  • Response field data.scan_groups (array of object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

PATCH /api/v1/teams/{team_id}

  • Update a team (rename it)
  • Updates team information (requires admin or owner role) Requires the write scope. Team owner or admin. Guests have read-only access and get 403.
  • Path parameter team_id (uuid, required): Team UUID
  • Request body field team.name (string)
  • Response 200: Team updated
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.status (string, one of active/disabled)
  • Response field data.owner_id (uuid)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Response field data.stats (object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

DELETE /api/v1/teams/{team_id}

  • Delete team
  • Soft deletes a team (requires owner role) Requires the write scope. Team owner only.
  • Path parameter team_id (uuid, required): Team UUID
  • Response 204: Team deleted
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.

Scan Groups

Domain monitoring group operations

GET /api/v1/teams/{team_id}/scan_groups

  • List scan groups
  • Returns all scan groups for a team Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Response 200: List of scan groups
  • Response field data[].id (uuid)
  • Response field data[].name (string)
  • Response field data[].scan_port (integer)
  • Response field data[].status (string, one of active/disabled)
  • Response field data[].hosts_count (integer)
  • Response field data[].created_at (date-time)
  • Response field data[].updated_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

POST /api/v1/teams/{team_id}/scan_groups

  • Create scan group (add many domains at once)
  • Creates a scan group and starts monitoring every domain in hosts in one request. This is the way to add many domains at once; to add one domain to an existing group, use POST /teams/{team_id}/scan_groups/{scan_group_id}/hosts. Requires the write scope. Team owner or admin. Guests have read-only access and get 403. Every address in hosts counts against the team owner's domain limit; a list that would exceed it is rejected with 422 and nothing is created. Creating a group also starts a scan unless the caller's scan cooldown is active.
  • Path parameter team_id (uuid, required): Team UUID
  • Request body field scan_group.friendly_name (string, required): Name for the scan group
  • Request body field scan_group.scan_port (integer): Port to scan
  • Request body field scan_group.hosts (string): Comma or space-separated list of domains to monitor, all added in this request
  • Response 201: Scan group created
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.scan_port (integer)
  • Response field data.status (string, one of active/disabled)
  • Response field data.hosts_count (integer)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

GET /api/v1/teams/{team_id}/scan_groups/{id}

  • Get scan group details
  • Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Scan group details
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.scan_port (integer)
  • Response field data.status (string, one of active/disabled)
  • Response field data.hosts_count (integer)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Response field data.hosts (array of object)
  • Response field data.schedule (object): Present when the group has a schedule
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

PATCH /api/v1/teams/{team_id}/scan_groups/{id}

  • Update scan group
  • Requires the write scope. Team owner or admin. Guests have read-only access and get 403. hosts replaces the group's list: addresses not listed are removed, new ones added (and counted against the owner's domain limit).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Scan group updated
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.scan_port (integer)
  • Response field data.status (string, one of active/disabled)
  • Response field data.hosts_count (integer)
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

DELETE /api/v1/teams/{team_id}/scan_groups/{id}

  • Delete scan group
  • Requires the write scope. Team owner or admin. Guests have read-only access and get 403.
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 204: Scan group deleted
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.

Hosts

Individual domain/host operations

GET /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts

  • List the domains (hosts) monitored in a scan group
  • Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Response 200: List of hosts
  • Response field data[].id (uuid)
  • Response field data[].address (string): Domain name (e.g., example.com)
  • Response field data[].status (string, one of active/disabled)
  • Response field data[].last_scan_status (string, may be null)
  • Response field data[].last_scanned_at (date-time, may be null)
  • Response field data[].expiration_date (date-time, may be null)
  • Response field data[].expiring_soon (boolean): True if the certificate is unexpired and inside its expiry-warning window. The window opens shortly after an automated client should have renewed (a third of the lifetime left) and is never longer than 30 days: 28 days for a 90-day certificate, 19 for a 64-day one
  • Response field data[].created_at (date-time)
  • Response field data[].updated_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

POST /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts

  • Add a domain to monitoring (a monitor, stored as a host in a scan group)
  • Requires the write scope. Team owner or admin. Guests have read-only access and get 403. 402 when the team owner's plan has no domain left (the body says which plan and how to upgrade).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Request body field host.address (string, required): Domain name (e.g., example.com)
  • Response 201: Host added
  • Response field data.id (uuid)
  • Response field data.address (string): Domain name (e.g., example.com)
  • Response field data.status (string, one of active/disabled)
  • Response field data.last_scan_status (string, may be null)
  • Response field data.last_scanned_at (date-time, may be null)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.expiring_soon (boolean): True if the certificate is unexpired and inside its expiry-warning window. The window opens shortly after an automated client should have renewed (a third of the lifetime left) and is never longer than 30 days: 28 days for a 90-day certificate, 19 for a 64-day one
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 402: Plan limit reached. The body names the limit, the current plan and the upgrade options.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

GET /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts/{id}

  • Get one monitored domain (host) with its latest scan
  • Returns detailed host information including latest scan result Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Host details
  • Response field data.id (uuid)
  • Response field data.address (string): Domain name (e.g., example.com)
  • Response field data.status (string, one of active/disabled)
  • Response field data.last_scan_status (string, may be null)
  • Response field data.last_scanned_at (date-time, may be null)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.expiring_soon (boolean): True if the certificate is unexpired and inside its expiry-warning window. The window opens shortly after an automated client should have renewed (a third of the lifetime left) and is never longer than 30 days: 28 days for a 90-day certificate, 19 for a 64-day one
  • Response field data.created_at (date-time)
  • Response field data.updated_at (date-time)
  • Response field data.latest_scan (object): Present once the host has been scanned
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

DELETE /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts/{id}

  • Stop monitoring a domain (remove a host)
  • Requires the write scope. Team owner or admin. Guests have read-only access and get 403.
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 204: Host removed
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.

Scans

Scan operations and results

POST /api/v1/teams/{team_id}/scan_groups/{id}/scan

  • Trigger scan for all domains in group
  • Triggers an immediate TLS scan for all domains in the scan group Requires the write scope. Team owner or admin. Guests have read-only access and get 403.
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Scan triggered successfully
  • Response field message (string)
  • Response field scan_group_id (uuid): Scan group scans only
  • Response field domains_scanned (integer): Scan group scans only
  • Response field host_id (uuid): Host scans only
  • Response field address (string): Host scans only
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.
  • Error 429: Too many requests: the 1,000 requests per hour per credential limit, or the manual scan cooldown. Both bodies carry retry_after in seconds.

POST /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts/{id}/scan

  • Scan one monitored domain now
  • Triggers an immediate TLS scan for a specific domain Requires the write scope. Team owner or admin. Guests have read-only access and get 403.
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Scan triggered
  • Response field message (string)
  • Response field scan_group_id (uuid): Scan group scans only
  • Response field domains_scanned (integer): Scan group scans only
  • Response field host_id (uuid): Host scans only
  • Response field address (string): Host scans only
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.
  • Error 429: Too many requests: the 1,000 requests per hour per credential limit, or the manual scan cooldown. Both bodies carry retry_after in seconds.

GET /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts/{host_id}/scan_results

  • List scan results for host
  • Returns scan history for a specific host Requires the read scope. Any accepted member of the team (owner, admin or guest). The 50 most recent results, newest first. scan_data is only in the single-result view.
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Path parameter host_id (uuid, required): Host UUID
  • Response 200: List of scan results
  • Response field data[].id (uuid)
  • Response field data[].scanned_at (date-time)
  • Response field data[].status (string)
  • Response field data[].host_address (string)
  • Response field data[].expiration_date (date-time, may be null)
  • Response field data[].elapsed_time_seconds (number, may be null)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

GET /api/v1/teams/{team_id}/scan_groups/{scan_group_id}/hosts/{host_id}/scan_results/{id}

  • Get scan result details
  • Returns detailed scan data including certificate information Requires the read scope. Any accepted member of the team (owner, admin or guest).
  • Path parameter team_id (uuid, required): Team UUID
  • Path parameter scan_group_id (uuid, required): Scan group UUID
  • Path parameter host_id (uuid, required): Host UUID
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: Scan result details
  • Response field data.id (uuid)
  • Response field data.scanned_at (date-time)
  • Response field data.status (string)
  • Response field data.host_address (string)
  • Response field data.expiration_date (date-time, may be null)
  • Response field data.elapsed_time_seconds (number, may be null)
  • Response field data.scan_data (object): The full scanner output: certificates, protocols, cipher suites and vulnerability checks
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

API Keys

API key management

GET /api/v1/api_keys

  • List API keys
  • Returns all active API keys for the authenticated user Requires the read scope.
  • Response 200: List of API keys
  • Response field data[].id (uuid)
  • Response field data[].name (string)
  • Response field data[].key_prefix (string): The key's first 8 characters followed by asterisks
  • Response field data[].scopes (array of string)
  • Response field data[].status (string, one of active/revoked)
  • Response field data[].team_id (uuid, may be null)
  • Response field data[].last_used_at (date-time, may be null)
  • Response field data[].expires_at (date-time, may be null)
  • Response field data[].created_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.

POST /api/v1/api_keys

  • Create new API key
  • Creates a new API key. The raw key is only shown once in the response. Requires the admin scope.
  • Request body field api_key.name (string, required): Name for the API key
  • Request body field api_key.scopes (array of string, one of read/write/admin)
  • Request body field api_key.team_id (uuid): Scope key to specific team
  • Request body field api_key.expires_at (date-time): Expiration date
  • Response 201: API key created. IMPORTANT: The raw_key is only shown once.
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.key_prefix (string): The key's first 8 characters followed by asterisks
  • Response field data.scopes (array of string)
  • Response field data.status (string, one of active/revoked)
  • Response field data.team_id (uuid, may be null)
  • Response field data.last_used_at (date-time, may be null)
  • Response field data.expires_at (date-time, may be null)
  • Response field data.created_at (date-time)
  • Response field raw_key (string): The full key. Shown once; store it now.
  • Response field warning (string)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 422: Validation failed. {errors: [...]} lists every message, including the domain limit.

GET /api/v1/api_keys/{id}

  • Get API key details
  • Requires the read scope.
  • Path parameter id (uuid, required): Resource UUID
  • Response 200: API key details
  • Response field data.id (uuid)
  • Response field data.name (string)
  • Response field data.key_prefix (string): The key's first 8 characters followed by asterisks
  • Response field data.scopes (array of string)
  • Response field data.status (string, one of active/revoked)
  • Response field data.team_id (uuid, may be null)
  • Response field data.last_used_at (date-time, may be null)
  • Response field data.expires_at (date-time, may be null)
  • Response field data.created_at (date-time)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 404: Not found, or not in a team the user has accepted membership of.

DELETE /api/v1/api_keys/{id}

  • Revoke API key
  • Requires the admin scope.
  • Path parameter id (uuid, required): Resource UUID
  • Response 204: API key revoked
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.
  • Error 403: The credential lacks the required scope ({error, required_scope, your_scopes}), the user's team role does not allow the change, or the free trial has ended.
  • Error 404: Not found, or not in a team the user has accepted membership of.

User

Current user information

GET /api/v1/me

  • Get current user information
  • Returns information about the authenticated user Requires the read scope.
  • Response 200: User information
  • Response field data.id (uuid)
  • Response field data.email (email)
  • Response field data.name (string)
  • Response field data.first_name (string, may be null)
  • Response field data.last_name (string, may be null)
  • Response field data.status (string)
  • Response field data.email_confirmed (boolean)
  • Response field data.created_at (date-time)
  • Response field data.teams_count (integer)
  • Response field data.api_access (boolean)
  • Response field data.subscription (object, may be null)
  • Response field data.plan (object)
  • Response field data.limits (object): null means no cap. Accounts with a scan cooldown (free plan, trial) are limited by it, not by scans_per_day; manual_scans states the rule that applies
  • Response field data.usage (object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.

Expiring

Convenience: certificates expiring within a window

GET /api/v1/expiring

  • List certificates expiring within N days
  • Convenience query that flattens all monitored hosts the user can see and returns those whose latest scan shows an expiration date within the requested window. Sorted by days until expiration ascending. Requires the read scope.
  • Query parameter within (integer): Days from now to look ahead
  • Response 200: List of expiring monitors with metadata
  • Response field data[].host_id (uuid)
  • Response field data[].address (string)
  • Response field data[].expiration_date (date-time)
  • Response field data[].days_until_expiration (integer)
  • Response field data[].last_scanned_at (date-time)
  • Response field data[].scan_group (object)
  • Response field data[].team (object)
  • Response field meta (object)
  • Error 401: Missing, invalid, expired or revoked credential. Suspending or deleting an account revokes all of its API keys and OAuth tokens.

MCP

Model Context Protocol (JSON-RPC 2.0) transport for AI agents

POST /api/v1/mcp

  • Model Context Protocol JSON-RPC 2.0 endpoint
  • Single JSON-RPC 2.0 endpoint that exposes TLS Radar tools to AI agents. Supports initialize, ping, tools/list, and tools/call. Bearer auth is required for tools that touch user data; public tools (scan) work without a token.
  • Request body field jsonrpc (string, one of 2.0, required)
  • Request body field id (object): JSON-RPC request id (number, string, or null)
  • Request body field method (string, required)
  • Request body field params (object)
  • Response 200: JSON-RPC response (result or error envelope)

MCP tools

The same account and certificate actions as tools for AI agents, at POST /api/v1/mcp (JSON-RPC 2.0). Certificate tools issue free Let's Encrypt certificates through Beacon; monitoring tools act on your TLS Radar account.

MCP tool scan_domain

  • Run a free, anonymous SSL/TLS scan against a hostname and return certificate details. No account required.
  • Works without an account.
  • Input domain (string, required): Hostname to scan (e.g. example.com). No scheme, no path.
  • Input client_id (string): Optional anonymous install id from ~/.config/tlsradar/install_id. Pass it for funnel attribution. If you omit it, the response's install_id is a fresh one to save there.

MCP tool create_certificate

  • Start issuing a FREE Let's Encrypt certificate for a domain (no account required). Step 1 of 3. Lifetime is Let's Encrypt's default: 90 days today, 64 days from 2027-02-10; read the real expiry from the issued certificate. Pick a validation method with challenge: "dns-01" (default; publish a TXT record; covers apex + www) or "http-01" (serve a file over HTTP on port 80; issues the exact domain only). dns-01 with a DNS-provider API token is the most automatable; http-01 suits a server you control on port 80. Returns an order_id plus either dns_records (dns-01) or http_files (http-01) to put in place. Next: poll check_certificate_propagation until all_found, then call finalize_certificate. Strongly prefer the CSR path at finalize (the private key never leaves the user's machine). Issuing automatically offers the user ongoing monitoring by email once it completes - don't add a monitor manually afterward.
  • Works without an account.
  • Input domain (string, required): Apex domain, no scheme/www (e.g. example.com).
  • Input email (string, required): Contact email for Let's Encrypt expiry notices and the monitoring handoff.
  • Input challenge (string, one of dns-01/http-01): Validation method: dns-01 (default) or http-01.
  • Input marketing_consent (boolean): Only true if the user explicitly opts in to a free account + reminder email. Default false.
  • Input client_id (string): Optional anonymous install id from ~/.config/tlsradar/install_id (funnel attribution). If omitted, the response's install_id is a fresh one to save there.

MCP tool check_certificate_propagation

  • Check whether the DNS TXT records for a certificate order have propagated (Cloudflare/Google/Quad9). Step 2 of issuance - poll until all_found is true, then call finalize_certificate. Returns per-record resolver results.
  • Works without an account.
  • Input order_id (string, required): The order_id from create_certificate.

MCP tool finalize_certificate

  • Finalize and issue a certificate order in one call: validates the DNS challenges, waits for Let's Encrypt, and returns the issued cert. Step 3 of issuance - call after check_certificate_propagation reports all_found. STRONGLY PREFER passing csr_pem (generate the key + CSR locally with openssl so the private key never leaves the machine). Returns leaf_pem/chain_pem/fullchain_pem. If you must, pass a passphrase instead to get a PKCS#12 bundle - but a CSR is safer. If it replies "still validating", DNS hasn't fully propagated: re-check check_certificate_propagation and call again. Needs a locally-generated CSR (csr_pem) - requires a local shell with openssl. On a surface without one (e.g. a Claude.ai custom connector) this can't complete; it returns guidance to finish in Claude Code/Cowork or the web form. Scanning and monitoring work everywhere. On success the structuredContent carries a handoff object - relay handoff.message to the user and do NOT separately call add_monitor; the cert→monitoring handoff is automatic and server-side.
  • Works without an account.
  • Input order_id (string, required): The order_id from create_certificate.
  • Input csr_pem (string): PEM CERTIFICATE REQUEST covering exactly {domain, www.domain}. Preferred - key stays local.
  • Input passphrase (string): Fallback only: ≥8 chars, protects a returned PKCS#12 bundle. Omit when using csr_pem.
  • Input max_wait_seconds (integer): How long to wait for validation server-side. Default 60, capped at 75.
  • Input resume_token (string): Optional. The resume_token from create_certificate; pass it to finalize an order whose row Beacon already purged (~24h).

MCP tool get_certificate_status

  • Return the current state of a certificate order (dns_pending, validating, ready, completed, failed) and per-authorization Let's Encrypt statuses. Use it to resume an interrupted issuance.
  • Works without an account.
  • Input order_id (string, required): The order_id from create_certificate.

MCP tool renew_certificate

  • Renew a certificate by cloning a recent order (requires the original order_id; Beacon purges orders after ~24h). Returns a new order_id and fresh DNS TXT records - then poll check_certificate_propagation and call finalize_certificate. If you don't have an order_id (the usual case at renewal time), call create_certificate for the domain instead; that IS the renewal.
  • Works without an account.
  • Input order_id (string, required): The original order_id to clone. If you don't have one, use create_certificate instead.

MCP tool get_account

  • Return the current user's plan, limits, and usage so the client can render upgrade nudges proactively.
  • Needs a signed-in account.

MCP tool list_monitors

  • List all certificates currently being monitored across the user's teams. If the response's structuredContent includes a nudge object, the user is at their monitor cap - surface it casually ONCE (lead with nudge.recommended_upgrade, mention nudge.also_available in one closing line); don't force it if it doesn't fit the conversation.
  • Needs a signed-in account.

MCP tool add_monitor

  • Add a domain to ongoing certificate monitoring with expiry alerts. Requires authentication (the user runs /mcp once). If the plan's monitor limit is reached, the response's structuredContent carries a limit-reached payload - when relaying it, LEAD with recommended_upgrade (it carries the plan name and price), mention also_available tiers in a single closing line, and offer removing an existing monitor as the free alternative. Don't dump a full tier comparison; that's choice paralysis at the moment of action.
  • Needs a signed-in account.
  • Changes data: needs the write scope, and an owner or admin role in the team it changes.
  • Input domain (string, required): Hostname to monitor (e.g. example.com). No scheme, no path.

MCP tool add_monitors

  • Add multiple domains to monitoring in one call. Returns a per-domain status so the caller can show partial-success outcomes. Honors the same plan-limit checks as add_monitor.
  • Needs a signed-in account.
  • Changes data: needs the write scope, and an owner or admin role in the team it changes.
  • Input domains (array of string, required): List of hostnames to monitor

MCP tool remove_monitor

  • Stop monitoring a domain. Accepts the domain name or the host_id returned by list_monitors.
  • Needs a signed-in account.
  • Changes data: needs the write scope, and an owner or admin role in the team it changes.
  • Input domain (string): Domain to stop monitoring
  • Input host_id (string): UUID of the host (alternative to domain)

MCP tool list_expiring_certificates

  • Return monitored certificates expiring within N days. Defaults to 30. If the response's structuredContent includes a nudge object, the user is watching enough soon-to-expire certs to benefit from a higher tier - mention it casually ONCE (lead with nudge.recommended_upgrade); skip it if it doesn't fit.
  • Needs a signed-in account.
  • Input within (integer): Days from now to look ahead

MCP tool get_scan_history

  • Return recent scan results for a domain the user monitors. Useful for spotting issuer changes, grade drops, or vulnerability appearances over time.
  • Needs a signed-in account.
  • Input domain (string, required): Domain name as it appears in list_monitors
  • Input limit (integer): Max results to return

MCP tool export_monitors

  • Dump the user's monitors as a JSON structure suitable for backup, migration, or infrastructure-as-code workflows. Tokens and PII are NEVER included - only domain configuration.
  • Needs a signed-in account.

MCP tool import_monitors

  • Create monitors from a JSON structure (typically produced by export). Skips domains the user is already monitoring; honors the plan's domain limit. Returns a per-domain status.
  • Needs a signed-in account.
  • Changes data: needs the write scope, and an owner or admin role in the team it changes.
  • Input payload (object, required): Export payload, version 1.0. Use the export tool to generate one.

MCP tool invite_team_member

  • Invite a user to a team by email. Defaults to the user's current team. Honors the plan's seat limit (returns the same upgrade payload as add_monitor when the cap is hit).
  • Needs a signed-in account.
  • Changes data: needs the write scope, and the team owner.
  • Input email (string, required): Email address of the person to invite
  • Input team_id (string): Team UUID; defaults to the current team
  • Input role (string, one of guest/admin): Invitee role: guest or admin. Defaults to guest.