← All Docs

API Reference

Complete REST API documentation for IPCraft. Manage sections, subnets, and IP addresses programmatically.

Base URL

https://api.ipcraft.io

All endpoint paths below are relative to this base URL.

Authentication

All requests except the Network Tools endpoints require authentication via one of two methods:

State-changing requests (POST, PATCH, DELETE) using a session cookie must include the X-Requested-With: XMLHttpRequest header for CSRF protection. API key requests do not need this header.
Example (API key)
curl https://api.ipcraft.io/api/v1/sections \
  -H "Authorization: Bearer ipc_abc123..."
Example (Session cookie with CSRF)
curl -X POST https://api.ipcraft.io/api/v1/sections \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest" \
  -b "session=..." \
  -d '{"name": "Production"}'

Errors & Plan Limits

All errors return a JSON object with an error key and an appropriate HTTP status code.

{
  "error": "Subnet overlaps with existing subnet 10.0.0.0/16"
}
StatusMeaning
400Bad request — invalid input or validation error
401Unauthorized — missing or invalid credentials
402Payment required — plan limit exceeded
403Forbidden — insufficient permissions
404Not found
429Rate limited — too many requests

Plan Limits

LimitFreePro ($29/mo)Teams ($199/mo)Enterprise
Users115Custom
Folders52550Custom
Subnets100500500Custom
IP Addresses1,5007,0007,000Custom
API AccessRead-onlyRead/WriteRead/WriteRead/Write
Rate Limit10 req/s30 req/s50 req/sCustom
Activity Log7 days14 days90 daysCustom

Requests that would exceed your plan limits return 402.

Auth Endpoints

Public endpoints for account creation and session management.

POST /api/v1/auth/send-link

Send a passwordless login link to the given email address. If the user doesn't exist yet, an account and organization are created when the link is verified.

Request body
{
  "email": "[email protected]"
}
Response
{
  "message": "magic link sent"
}

Verify Magic Link

GET /api/v1/auth/verify?token=<token>

Verify the magic link token from the email. Sets a session cookie on success and redirects to the app. Creates a new user and organization on first login.

Response
{
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "name": "John Smith"
  },
  "organization": {
    "id": "org_xyz789",
    "name": "John Smith's Org"
  }
}

Logout

POST /api/v1/auth/logout

Destroys the current session. No request body required.

Response
204 No Content

Get Current User

GET /api/v1/auth/me

Returns the authenticated user and their organization. Requires auth.

Response
{
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "name": "John Smith"
  },
  "organization": {
    "id": "org_xyz789",
    "name": "John Smith's Org",
    "plan": "free"
  }
}

Folders

Folders are top-level organizational containers for grouping subnets (e.g., "Production", "Development").

List Folders

GET /api/v1/sections

Returns all folders for the authenticated organization.

Response
[
  {
    "id": "sec_001",
    "name": "Production",
    "description": "Production network ranges",
    "sort_order": 0,
    "created_at": "2026-03-01T12:00:00Z"
  }
]

Create Folder

POST /api/v1/sections

Create a new folder.

Request body
{
  "name": "Production",
  "description": "Production network ranges",
  "sort_order": 0
}

Only name is required. description and sort_order are optional.

Response
{
  "id": "sec_001",
  "name": "Production",
  "description": "Production network ranges",
  "sort_order": 0,
  "created_at": "2026-03-01T12:00:00Z"
}

Get Folder

GET /api/v1/sections/{id}

Returns a single folder by ID.

Response
{
  "id": "sec_001",
  "name": "Production",
  "description": "Production network ranges",
  "sort_order": 0,
  "created_at": "2026-03-01T12:00:00Z"
}

Update Folder

PATCH /api/v1/sections/{id}

Update a folder. All fields are optional — only provided fields are changed.

Request body
{
  "name": "Prod (US-East)",
  "description": "US East production ranges",
  "sort_order": 1
}
Response

Returns the updated folder object.

Delete Folder

DELETE /api/v1/sections/{id}

Delete a folder.

Response
204 No Content

Subnets

Subnets represent CIDR network ranges. They form a hierarchy — creating a subnet within an existing range automatically nests it as a child. Overlap detection prevents conflicting ranges.

List Subnets

GET /api/v1/subnets?section_id={section_id}

List subnets, optionally filtered by folder. Includes utilization statistics.

Query parameters
  • section_id — filter by folder (optional)
Response
[
  {
    "id": "sub_001",
    "network": "10.0.0.0/16",
    "name": "Core network",
    "description": "Main production range",
    "section_id": "sec_001",
    "vrf_id": null,
    "gateway": "10.0.0.1",
    "is_pool": false,
    "utilization": 0.12,
    "created_at": "2026-03-01T12:00:00Z"
  }
]

Create Subnet

POST /api/v1/subnets

Create a new subnet. The parent is auto-detected based on CIDR containment. Overlapping ranges are rejected.

Request body
{
  "network": "10.0.1.0/24",
  "name": "Web servers",
  "description": "Web tier subnet",
  "section_id": "sec_001",
  "vrf_id": null,
  "gateway": "10.0.1.1",
  "is_pool": false
}

Only network is required. All other fields are optional.

Response

Returns the created subnet object.

Get Subnet

GET /api/v1/subnets/{id}

Returns a subnet and its child subnets.

Response
{
  "id": "sub_001",
  "network": "10.0.0.0/16",
  "name": "Core network",
  "children": [
    {
      "id": "sub_002",
      "network": "10.0.1.0/24",
      "name": "Web servers"
    }
  ]
}

Update Subnet

PATCH /api/v1/subnets/{id}

Update subnet metadata. All fields are optional.

Request body
{
  "name": "Web servers (prod)",
  "description": "Production web tier",
  "section_id": "sec_001",
  "is_pool": true,
  "gateway": "10.0.1.1"
}
Response

Returns the updated subnet object.

Delete Subnet

DELETE /api/v1/subnets/{id}

Delete a subnet. Cascades to all child subnets and addresses.

This action is irreversible. All child subnets and their addresses will also be deleted.
Response
204 No Content

Split Subnet

POST /api/v1/subnets/{id}/split

Split a subnet into equal parts. The number of parts must be a power of 2 (2, 4, 8, etc.).

Request body
{
  "parts": 4
}
Response
[
  { "id": "sub_010", "network": "10.0.0.0/26" },
  { "id": "sub_011", "network": "10.0.0.64/26" },
  { "id": "sub_012", "network": "10.0.0.128/26" },
  { "id": "sub_013", "network": "10.0.0.192/26" }
]

Subnet Usage

GET /api/v1/subnets/{id}/usage

Returns utilization statistics for a subnet.

Response
{
  "used": 42,
  "total": 254,
  "utilization": 0.165
}

First Free IP

GET /api/v1/subnets/{id}/first-free

Returns the first available IP address in the subnet. Returns null if the subnet is full.

Response
{
  "ip": "10.0.1.5"
}
Response (full subnet)
{
  "ip": null
}

Addresses

Individual IP address records within a subnet. Each address is validated against the parent subnet's CIDR range.

List Addresses

GET /api/v1/subnets/{id}/addresses

List all IP addresses in a subnet.

Response
[
  {
    "id": "addr_001",
    "ip": "10.0.1.10",
    "hostname": "web-01.prod",
    "mac_address": "00:1A:2B:3C:4D:5E",
    "description": "Primary web server",
    "status": "active",
    "owner": "platform-team",
    "created_at": "2026-03-01T12:00:00Z"
  }
]

Create Address

POST /api/v1/subnets/{id}/addresses

Assign an IP address within a subnet. The IP is validated to be within the subnet's CIDR range.

Request body
{
  "ip": "10.0.1.10",
  "hostname": "web-01.prod",
  "mac_address": "00:1A:2B:3C:4D:5E",
  "description": "Primary web server",
  "status": "active",
  "owner": "platform-team"
}

Only ip is required. All other fields are optional.

Response

Returns the created address object.

Get Address

GET /api/v1/addresses/{id}

Returns a single address by ID.

Response
{
  "id": "addr_001",
  "ip": "10.0.1.10",
  "hostname": "web-01.prod",
  "mac_address": "00:1A:2B:3C:4D:5E",
  "description": "Primary web server",
  "status": "active",
  "owner": "platform-team",
  "subnet_id": "sub_002",
  "created_at": "2026-03-01T12:00:00Z",
  "updated_at": "2026-03-10T08:30:00Z"
}

Update Address

PATCH /api/v1/addresses/{id}

Update address metadata. All fields are optional.

Request body
{
  "hostname": "web-01a.prod",
  "mac_address": "00:1A:2B:3C:4D:5F",
  "description": "Migrated web server",
  "status": "active",
  "owner": "platform-team"
}
Response

Returns the updated address object.

Delete Address

DELETE /api/v1/addresses/{id}

Remove an IP address assignment.

Response
204 No Content

Webhooks

Subscribe to real-time event notifications. See the Webhooks guide for setup instructions and signature verification.

List Webhooks

GET /api/v1/webhooks

List all webhook subscriptions. The signing secret is never included in list responses.

Response
[
  {
    "id": "wh_001",
    "url": "https://example.com/webhooks/ipcraft",
    "description": "CMDB sync",
    "event_types": ["subnet.created", "subnet.deleted"],
    "is_active": true,
    "failure_count": 0,
    "created_at": "2026-03-21T16:00:00Z"
  }
]

Create Webhook

POST /api/v1/webhooks

Create a new webhook subscription. Returns the signing secret — store it securely, it is only shown once.

Request body
{
  "url": "https://example.com/webhooks/ipcraft",
  "description": "CMDB sync",
  "event_types": ["subnet.created", "subnet.deleted"]
}

Leave event_types empty ([]) to receive all event types.

Response
{
  "id": "a1b2c3d4-...",
  "url": "https://example.com/webhooks/ipcraft",
  "secret": "whsec_a1b2c3d4e5f6...",
  "event_types": ["subnet.created", "subnet.deleted"],
  "is_active": true
}
Copy the secret value immediately. It cannot be retrieved again. Use it to verify webhook signatures.

Get Webhook

GET /api/v1/webhooks/{id}

Get a single webhook subscription. The signing secret is not included.

Update Webhook

PATCH /api/v1/webhooks/{id}

Update a webhook's URL, description, event types, or active status. Re-enabling a disabled webhook resets the failure count.

Request body
{
  "url": "https://new-endpoint.example.com/hook",
  "event_types": ["address.created"],
  "is_active": true
}
Response
200 OK

Delete Webhook

DELETE /api/v1/webhooks/{id}

Permanently delete a webhook subscription and all its delivery history.

Response
204 No Content

List Deliveries

GET /api/v1/webhooks/{id}/deliveries

List recent delivery attempts for a webhook. Supports ?limit= and ?offset= query parameters (max 200).

Response
[
  {
    "id": "del_001",
    "event_type": "subnet.created",
    "response_status": 200,
    "duration_ms": 142,
    "attempt": 1,
    "delivered_at": "2026-03-21T16:30:00Z"
  }
]

Test Ping

POST /api/v1/webhooks/{id}/test

Send a test ping event to the webhook endpoint. Returns the delivery result so you can verify connectivity.

Response
{
  "event_type": "ping",
  "response_status": 200,
  "duration_ms": 95,
  "attempt": 1
}

Returns 502 if the endpoint is unreachable or returns a non-2xx status.

Rotate Secret

POST /api/v1/webhooks/{id}/rotate-secret

Generate a new signing secret for the webhook. The old secret stops working immediately.

Response
{
  "secret": "whsec_new_secret_value..."
}
Update your endpoint to use the new secret before rotating, or you'll miss events during the transition.

API Keys

Manage API keys for programmatic access. The full key is only shown once at creation time.

List Keys

GET /api/v1/api-keys

List all API keys. Only the key prefix is shown — the full key is never returned after creation.

Response
[
  {
    "id": "key_001",
    "name": "Ansible automation",
    "key_prefix": "ipc_a1b2c3",
    "created_at": "2026-03-01T12:00:00Z",
    "last_used_at": "2026-03-14T09:15:00Z"
  }
]

Create Key

POST /api/v1/api-keys

Generate a new API key. The full key is only returned in this response — store it securely.

Request body
{
  "name": "Ansible automation"
}
Response
{
  "id": "key_001",
  "name": "Ansible automation",
  "key": "ipc_a1b2c3d4e5f6g7h8i9j0...",
  "key_prefix": "ipc_a1b2c3"
}
Copy the key value immediately. It cannot be retrieved again.

Delete Key

DELETE /api/v1/api-keys/{id}

Revoke an API key. Any requests using this key will immediately start returning 401.

Response
204 No Content

Billing

Manage your subscription plan via Stripe integration.

Get Plan

GET /api/v1/billing/plan

Returns current plan details, usage, and limits.

Response
{
  "plan": "free",
  "usage": {
    "sections": 1,
    "subnets": 3,
    "addresses": 42
  },
  "limits": {
    "sections": 1,
    "subnets": 5,
    "addresses": 100
  }
}

Checkout

POST /api/v1/billing/checkout

Creates a Stripe Checkout session for upgrading to Pro. Redirect the user to the returned URL.

Response
{
  "url": "https://checkout.stripe.com/c/pay/cs_live_..."
}

Customer Portal

POST /api/v1/billing/portal

Creates a Stripe Customer Portal session for managing billing, invoices, and cancellation.

Response
{
  "url": "https://billing.stripe.com/p/session/..."
}

Full-text search across subnets and addresses.

GET /api/v1/search?q={query}

Search by IP address, hostname, network CIDR, description, or any other field. Returns matching subnets and addresses.

Query parameters
  • q — search query (required)
Response
{
  "subnets": [
    {
      "id": "sub_002",
      "network": "10.0.1.0/24",
      "name": "Web servers"
    }
  ],
  "addresses": [
    {
      "id": "addr_001",
      "ip": "10.0.1.10",
      "hostname": "web-01.prod"
    }
  ]
}

Activity

Audit log of actions performed within your organization.

GET /api/v1/activity?limit={limit}&offset={offset}

Returns a paginated list of activity entries.

Query parameters
  • limit — number of entries to return (optional)
  • offset — pagination offset (optional)
Response
[
  {
    "id": "act_001",
    "action": "subnet.created",
    "resource_type": "subnet",
    "resource_id": "sub_002",
    "user_id": "usr_abc123",
    "details": "Created subnet 10.0.1.0/24",
    "created_at": "2026-03-14T10:30:00Z"
  }
]

Network Tools

Public endpoints for common network lookups. No authentication required. Rate-limited to 10 requests per minute per IP address.

DNS Lookup

GET /api/v1/tools/dns?domain={domain}&type={type}

Perform a DNS lookup from 3 independent resolvers (Google, Cloudflare, Quad9).

Query parameters
  • domain — domain name to resolve (required)
  • type — record type: A, AAAA, MX, TXT, NS, CNAME, SOA (required)
Response
{
  "domain": "example.com",
  "type": "A",
  "resolvers": {
    "google": ["93.184.216.34"],
    "cloudflare": ["93.184.216.34"],
    "quad9": ["93.184.216.34"]
  }
}

Reverse DNS

GET /api/v1/tools/rdns?ip={ip}

Perform a reverse DNS lookup for an IP address.

Query parameters
  • ip — IP address (required)
Response
{
  "ip": "8.8.8.8",
  "hostnames": ["dns.google"]
}

WHOIS Lookup

GET /api/v1/tools/whois?query={query}

Perform a WHOIS lookup for a domain or IP address.

Query parameters
  • query — domain name or IP address (required)
Response
{
  "query": "example.com",
  "raw": "Domain Name: EXAMPLE.COM\nRegistry Domain ID: ..."
}

Ping (TCP Check)

GET /api/v1/tools/ping?host={host}

TCP connectivity check to a host.

Query parameters
  • host — hostname or IP address (required)
Response
{
  "host": "example.com",
  "reachable": true,
  "latency_ms": 24
}

Port Scan

GET /api/v1/tools/ports?host={host}

Scan 19 common ports on a host (FTP, SSH, HTTP, HTTPS, DNS, SMTP, etc.).

Query parameters
  • host — hostname or IP address (required)
Response
{
  "host": "example.com",
  "ports": [
    { "port": 80, "service": "http", "open": true },
    { "port": 443, "service": "https", "open": true },
    { "port": 22, "service": "ssh", "open": false }
  ]
}

My IP

GET /api/v1/tools/myip

Returns the client's public IP address and related information.

Response
{
  "ip": "203.0.113.42"
}

Request Headers

GET /api/v1/tools/headers

Returns the HTTP headers sent by the client.

Response
{
  "headers": {
    "User-Agent": "curl/8.1.0",
    "Accept": "*/*",
    "Host": "api.ipcraft.io"
  }
}