Skip to main content
All routes in this guide require an API key. See Integration API for creating and using API keys (Bearer token in the Authorization header). Many routes use an organization ID in the path — see Organization ID for where to find it.
This guide is a minimal walkthrough for creating core Pangolin components (sites, resources, targets) via the API. It is not exhaustive — some elements are omitted for simplicity — but everything shown here works and illustrates patterns used elsewhere in the API. For full coverage of endpoints (get, update, delete, list, etc.), use the Swagger docs.

Create site

This section assumes you’re creating a Newt site. For all Site endpoints, see Site API (Swagger).
1

Get site defaults

Call the pick-site-defaults endpoint to get values you pass into the create-site endpoint, such as the Newt ID and secret.
2

Create the site

Call the create-site endpoint with the values from the defaults response.

Get site defaults

GET /org/{orgId}/pick-site-defaults Returns values you pass into the create-site endpoint. Path
  • orgId (string) — organization ID
Example Response
{
  "data": {
    "newtId": "jwhk5154mfmos0s",
    "newtSecret": "8afipi4i79jjbsxjqpkgc0xe2ge143s54oi64mw5567mxgr8",
    "clientAddress": "100.90.128.0"
  },
  "success": true,
  "error": false,
  "message": "Site defaults chosen successfully",
  "status": 200
}

Create site

PUT /org/{orgId}/site Path
  • orgId (string) — organization ID
Body (Newt)
FieldTypeRequiredDescription
namestringYesDisplay name for the site
addressstringYesFrom pick-site-defaults clientAddress
typestringYesUse "newt"
newtIdstringYesFrom pick-site-defaults newtId
secretstringYesFrom pick-site-defaults newtSecret
Example Response
{
  "data": {
    "siteId": 8723,
    "niceId": "quiet-lerista-labialis",
    "name": "My Site",
    "type": "newt",
    "online": false,
    "address": "100.90.128.0/24"
  },
  "success": true,
  "error": false,
  "message": "Site created successfully",
  "status": 201
}

Create public HTTP resource

You need a domain ID before creating a resource. List your org’s domains, then create the resource with the chosen domain. For all Resource endpoints, see Resource API (Swagger).
1

List domains

Call the list-domains endpoint to get available domains and their domainId values.
2

Create the resource

Call the create-resource endpoint with http: true and the domainId from step 1.
3

Add targets to the resource

Call the create-target endpoint for each backend (site + ip:port) that should serve traffic for the resource.

List domains

GET /org/{orgId}/domains Returns all domains for the organization. Use domainId from a domain when creating a resource. Path
  • orgId (string) — organization ID
Query (optional)
ParamTypeDefaultDescription
limitnumber1000Max domains to return
offsetnumber0Pagination offset
Example Response
{
  "data": {
    "domains": [
      {
        "domainId": "pg3i1k4lhibhl3i",
        "baseDomain": "pangolin.net",
        "verified": true,
        "type": "ns"
      },
      {
        "domainId": "q1ngj5341k7oydo",
        "baseDomain": "bitwarden.pangolin.net",
        "verified": true,
        "type": "cname"
      }
    ],
    "pagination": {
      "total": 2,
      "limit": 1000,
      "offset": 0
    }
  },
  "success": true,
  "error": false,
  "message": "Domains retrieved successfully",
  "status": 200
}

Create public HTTP resource

PUT /org/{orgId}/resource Path
  • orgId (string) — organization ID
Body (HTTP resource)
FieldTypeRequiredDescription
namestringYesDisplay name for the resource (1–255 chars)
httpbooleanYesUse true for public HTTP resource
domainIdstringYesFrom list-domains
protocolstringYes"tcp"
subdomainstring | nullNoSee below.
Subdomain and domain types Domains come in three types: ns | cname | wildcard.
Wildcard is only available in self-hosted Pangolin. Pangolin Cloud uses ns and cname only.
  • ns — You can use the base domain (set subdomain to null) or set a subdomain (e.g. my-appmy-app.digpangolin.io).
  • cname — Only the base domain is used; set subdomain to null (the domain’s baseDomain is the FQDN).
  • wildcard — Same as ns for subdomain behavior (self-hosted only).
The subdomain value is combined with the base domain from domainId to form the FQDN. Omit subdomain or pass null when using the base domain alone. Example request
{
  "name": "My Resource",
  "http": true,
  "subdomain": "my-subdomain",
  "domainId": "pg3i1k4lhibhl3i",
  "protocol": "tcp"
}
Example Response
{
  "data": {
    "resourceId": 9942,
    "niceId": "decent-louisiana-waterthrush",
    "name": "My Resource",
    "subdomain": "my-subdomain",
    "fullDomain": "my-subdomain.pangolin.net",
    "domainId": "pg3i1k4lhibhl3i"
  },
  "success": true,
  "error": false,
  "message": "Http resource created successfully",
  "status": 201
}

Add targets to the resource

PUT /resource/{resourceId}/target Add a target (backend) to a resource. Use the numeric resourceId from the create-resource response. The target is the site and address (ip + port) that will receive traffic for the resource. For all Target endpoints, see Target API (Swagger). Path
  • resourceId (number) — From create-resource response (e.g. 9943)
Body
FieldTypeRequiredDescription
siteIdnumberYesSite that hosts the backend (from create-site or list sites)
ipstringYesBackend IP or hostname
portnumberYesBackend port
methodstringYese.g. "http" for HTTP resources
Example request
{
  "ip": "localhost",
  "port": 8080,
  "method": "http",
  "siteId": 5165
}
Example response
{
  "data": {
    "targetId": 11280,
    "resourceId": 9942,
    "siteId": 8723,
    "ip": "localhost",
    "method": "http",
    "port": 8080
  },
  "success": true,
  "error": false,
  "message": "Target created successfully",
  "status": 201
}

Create private resource

In the API Private Resources are called site resources. You need an existing site. For more endpoints, see API docs (Swagger).

Create site resource

PUT /org/{orgId}/site-resource Path
  • orgId (string) — organization ID
Body
FieldTypeRequiredDescription
namestringYesDisplay name (1–255 chars)
siteIdnumberYesSite that hosts the resource (from create-site or list sites)
modestringYes"host" | "cidr"
destinationstringYesFor host: IP or hostname (e.g. localhost). For cidr: CIDR (e.g. 10.0.0.0/24).
aliasstringFor host+domainAlias hostname (e.g. private-resource.internal). Required when destination is a domain; optional for IP. Must be unique in the org.
tcpPortRangeStringstringYesSee below.
udpPortRangeStringstringYesSee below.
disableIcmpbooleanNoDefault false
authDaemonModestringNo"site" | "remote"
roleIdsnumber[]NoRole IDs that can access (default [])
userIdsstring[]NoUser IDs that can access (default [])
TCP/UDP port range strings: Control which ports are allowed for the private resource.
  • "*" — Allow all ports (common for TCP when you want full access to the host).
  • "" (empty string) — Allow no ports. Use when you don’t need that protocol (e.g. udpPortRangeString: "" if only TCP is used).
  • Specific ports or ranges — Comma-separated list: single ports (e.g. "80,443") or ranges (e.g. "8000-9000"). Example: "80,443,8080-8090" allows 80, 443, and 8080–8090.
Use tcpPortRangeString and udpPortRangeString independently (e.g. TCP all, UDP none, or vice versa). If you omit roleIds/userIds, the org admin role is granted access by default. Add IDs to restrict access. Example request
{
  "name": "My Private Resource",
  "siteId": 8723,
  "mode": "host",
  "destination": "localhost",
  "alias": "private-resource.internal",
  "tcpPortRangeString": "*",
  "udpPortRangeString": "",
  "disableIcmp": false,
  "authDaemonMode": "site",
  "roleIds": [],
  "userIds": []
}
Example response
{
  "data": {
    "siteResourceId": 1165,
    "siteId": 8723,
    "niceId": "unsung-round-tailed-ground-squirrel",
    "name": "My Private Resource",
    "mode": "host",
    "destination": "localhost",
    "alias": "private-resource.internal",
    "tcpPortRangeString": "*",
    "udpPortRangeString": "",
    "disableIcmp": false,
    "authDaemonPort": 22123,
    "authDaemonMode": "site"
  },
  "success": true,
  "error": false,
  "message": "Site resource created successfully",
  "status": 201
}

Assign users and roles to a resource (public or private)

You can grant access to a public resource or a private (site) resource by adding roles or users. First list roles and users in the org to get IDs, then call the add endpoints. The Admin role cannot be assigned via these endpoints.

Get role and user IDs

GET /org/{orgId}/roles — Returns roles in the org. Use roleId (number) when adding a role to a resource. Query: limit, offset (optional). GET /org/{orgId}/users — Returns users in the org. Use id (string) as userId when adding a user to a resource. Query: limit, offset (optional).

Public resource (HTTP/resources)

POST /resource/{resourceId}/roles/addPath: resourceId (number, from create-resource). Body: { "roleId": number }. Admin role not allowed. POST /resource/{resourceId}/users/addPath: resourceId (number). Body: { "userId": string }. Both return { "data": {}, "success": true, "error": false, "message": "...", "status": 201 }.

Private resource (site resource)

POST /site-resource/{siteResourceId}/roles/addPath: siteResourceId (number, from create site-resource). Body: { "roleId": number }. Admin role not allowed. POST /site-resource/{siteResourceId}/users/addPath: siteResourceId (number). Body: { "userId": string }. Same response shape as above. Role must belong to the same org as the site resource. For more endpoints (list/remove), see Resource API.