Share Servers
Section titled “Share Servers”Pools group rented servers so a team can share them. Instead of managing servers one at a time, you assign them to a pool and give each member a role that decides what they can do there.
Pool basics
Section titled “Pool basics”A pool is a group of rented servers that its members share. It groups servers, not containers. Assign rented servers to a pool and every member gets access according to their role.
- Default pool: Every user has one automatically. All servers go here unless you specify another pool during rental.
- Shared pools: Pools you create for a team, a client, or an organizational unit.
- Role-based access: Owner is implicit and belongs to the pool creator. Two roles are assignable:
adminanduser. - Server assignment: You assign a server to a pool when you rent it, via
pool_id. - Container deployment: Pool members deploy containers to pool servers.
API endpoints summary
Section titled “API endpoints summary”Pool management uses these endpoints:
GET /api/v1/pools- List your poolsPOST /api/v1/pools- Create new poolGET /api/v1/pools/{id}- View pool detailsPUT /api/v1/pools/{id}- Update pool settingsPATCH /api/v1/pools/{id}- Update pool settingsDELETE /api/v1/pools/{id}- Delete pool
GET /api/v1/pools/invitations/pending- List your pending invitationsPOST /api/v1/pools/{id}/accept- Accept an invitation (here{id}is the Pool ID, thepool_idreturned by the pending-invitations list)POST /api/v1/pools/{id}/reject- Decline an invitation (here{id}is the Pool ID, thepool_idreturned by the pending-invitations list)
- Assign server to a pool during rental (
pool_idonPOST /api/v1/servers/{id}/rent) - View pool’s servers
For detailed API documentation, see Servers API.
Pool roles
Section titled “Pool roles”Only admin and user are assignable via the members API (role enum). Owner is implicit: it is whoever created the pool, and it is never passed as a role string.
Owner (full control; pool creator, not assignable)
- Create the pool
- Add/remove members
- Assign servers to the pool at rental time
- Modify pool settings
- Delete the pool, but only when it holds no servers and has never held a rental
Admin (management)
- Add/remove members
- View all pool resources
- Cannot rent servers into the pool, change member roles, modify pool settings, or delete pool (owner only)
User (access)
- Deploy containers to pool servers
- View pool servers and members
- Cannot modify pool structure
Create a pool
Section titled “Create a pool”-
Create the pool
Terminal window # Create a team poolhoody pools create \--name "Frontend Team Pool" \--description "Shared servers for frontend development"# Invite a team memberhoody pools members invite $POOL_ID \--username "$USERNAME" \--role "user"# List your poolshoody pools listimport { HoodyClient } from 'hoody-sdk';const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });// Create a team poolconst pool = await client.api.pools.create({name: 'Frontend Team Pool',description: 'Shared servers for frontend development',});// Invite a member (by username)await client.api.poolMembers.invite(pool.data.id, {username: 'teammate_handle',role: 'user',});// List poolsconst pools = await client.api.pools.list();Terminal window # Create a team poolcurl -X POST "https://api.hoody.com/api/v1/pools" \-H "Authorization: Bearer $HOODY_TOKEN" \-H "Content-Type: application/json" \-d '{"name": "Frontend Team Pool","description": "Shared servers for frontend development"}'# Invite a membercurl -X POST "https://api.hoody.com/api/v1/pools/$POOL_ID/members" \-H "Authorization: Bearer $HOODY_TOKEN" \-H "Content-Type: application/json" \-d '{"username": "teammate_handle", "role": "user"}'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must encode is an
&inside a value, which happens when the wrapped URL carries its own query string. Left raw it ends the value early, and the rest is read as cURL's own parameters, so you get a200on a request you did not make.How the wrapping works Chaining calls into one link Turning a link into a shortcut
Create the pool, then invite a teammate into it by username.
# Create pool https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/pools&method=POST&bearer_token=TOKEN&json={"name":"Frontend%20Team%20Pool","description":"Shared%20servers%20for%20frontend%20development"}&response=transparent # Invite a member https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/pools/POOL_ID/members&method=POST&bearer_token=TOKEN&json={"username":"teammate_handle","role":"user"}&response=transparentThe link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
-
Invite team members
Add members with appropriate roles. Invited users find pending invitations via
GET /api/v1/pools/invitations/pending(or the dashboard) and accept withPOST /api/v1/pools/{id}/accept(or decline withPOST /api/v1/pools/{id}/reject). -
Assign servers
When renting servers, specify the pool:
{"pool_id": "507f1f77bcf86cd799439011","rental_days": 30,"max_charge_cents": 27500}max_charge_centsis required on every paid rental. Readpricing.price_tiers[rental_days].total_first_payment, which is a decimal-dollar string, and convert it to integer cents ("275.00"→27500).A server’s pool is set at rental time, and
pool_idmust name a pool you own. To place servers in different pools, rent each one directly into the pool you want by passing itspool_id. Only the pool’s owner can rent into it, so a shared team pool is stocked by its owner. -
Members deploy containers
Pool members can now deploy containers to pool servers, within the limits of their role.
Ways to organize pools
Section titled “Ways to organize pools”By team or department
Section titled “By team or department”One pool per team: Development, QA, DevOps.
- Each team manages its own servers
- Clear resource ownership
- Budget tracking per team
By client or project
Section titled “By client or project”One pool per client: Client A, Client B, Client C.
- Fits agency and consultancy work
- Complete client data isolation
- Per-client billing
By environment
Section titled “By environment”One pool per environment: Production, Staging, Development.
- Separate environments by security level
- Different access rules per pool
By more than one axis
Section titled “By more than one axis”These groupings combine:
Production Pool (3 servers) → Owner: CTO → Admins: Senior DevOps (2) → Users: Backend team (8)
Client Projects Pool (5 servers) → Owner: Account Manager → Admins: Project Leads (3) → Users: Developers (12)
AI Experiments Pool (2 servers) → Owner: AI Lead → Admins: ML Engineers (4) → Users: Whole company (open access)Member management
Section titled “Member management”Add members
Section titled “Add members”# Invite a user to a poolhoody pools members invite $POOL_ID \ --username "$USERNAME" \ --role "user"
# Update a member's role (positional pool ID and user ID)hoody pools members update-role $POOL_ID $USER_ID \ --role "admin"
# Remove a member (--yes skips the confirmation prompt)hoody pools members delete $POOL_ID $USER_ID --yesimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
// Invite a user to a pool (by username)await client.api.poolMembers.invite(poolId, { username: 'teammate_handle', role: 'user',});
// Update member roleawait client.api.poolMembers.updateRole(poolId, userId, { role: 'admin',});
// Remove a memberawait client.api.poolMembers.remove(poolId, userId);# Invite a user to a poolcurl -X POST "https://api.hoody.com/api/v1/pools/$POOL_ID/members" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"username": "teammate_handle", "role": "user"}'
# Update member role (role must be "admin" or "user")curl -X PUT "https://api.hoody.com/api/v1/pools/$POOL_ID/members/$USER_ID" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"role": "admin"}'
# Remove a membercurl -X DELETE "https://api.hoody.com/api/v1/pools/$POOL_ID/members/$USER_ID" \ -H "Authorization: Bearer $HOODY_TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Invite, promote, or remove a pool member. Role must be admin or user.
# Invite a member
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/pools/POOL_ID/members&method=POST&bearer_token=TOKEN&json={"username":"teammate_handle","role":"user"}&response=transparent
# Update member role
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/pools/POOL_ID/members/USER_ID&method=PUT&bearer_token=TOKEN&json={"role":"admin"}&response=transparent
# Remove a member
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/pools/POOL_ID/members/USER_ID&method=DELETE&bearer_token=TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Once a member accepts the invitation (POST /api/v1/pools/{id}/accept), they have pool access immediately.
Roles and permissions
Section titled “Roles and permissions”| Action | Owner | Admin | User |
|---|---|---|---|
| View pool servers | Yes | Yes | Yes |
| Deploy containers | Yes | Yes | Yes |
| Add members | Yes | Yes | No |
| Remove members | Yes | Yes | No |
| Change member role | Yes | No | No |
| Assign servers (rent into this pool) | Yes | No | No |
| Change pool settings | Yes | No | No |
| Delete pool | Yes | No | No |
Remove members
Section titled “Remove members”You can remove a member at any time:
- Their containers on pool servers remain
- They lose access to deploy new containers
- Their existing containers can be reassigned or deleted
Server assignment
Section titled “Server assignment”During rental
Section titled “During rental”Every server is assigned to a pool. Name the pool you want, or leave it out and the server goes to your default pool.
Specify a pool:
{ "pool_id": "507f1f77bcf86cd799439011", "rental_days": 30, "max_charge_cents": 27500}Omit the pool (uses the default):
{ "rental_days": 30, "max_charge_cents": 27500}// Automatically assigned to your default poolmax_charge_cents is required on every paid rental. Read pricing.price_tiers[rental_days].total_first_payment, which is a decimal-dollar string, and convert it to integer cents ("275.00" → 27500).
The server is immediately accessible to every pool member, within the limits of their role.
Which pool a server can join
Section titled “Which pool a server can join”A server’s pool is chosen when you rent it, and a rented server can only be attached to a pool you own. Passing a pool you merely belong to, even as an Admin, returns 403 ACCESS_DENIED. So the owner of a shared team pool is the one who rents servers into it; other members rent into their own pools. There is no public endpoint to move an existing server between pools.
That shapes a few common setups:
- The pool owner rents into the shared team pool so the whole team has access immediately
- Rent a testing server into a dedicated staging pool you own
- Rent client work into a per-client pool for isolation
Pool settings
Section titled “Pool settings”Each pool carries a free-form settings JSON object that you can set at creation and update later. It defaults to an empty object and accepts arbitrary keys.
Hoody stores and returns settings unchanged. Nothing on the platform interprets or enforces its contents, so it is metadata for your own tooling, not a place to configure caps or approval workflows.
{ "settings": { "owning_team": "frontend", "cost_center": "R&D-114" }}The only rules Hoody applies are structural: settings must be a JSON object (not an array), and both its serialized size and its nesting depth are capped. Exceed either and the create or update returns 400 with field: "pool_settings".
Use cases
Section titled “Use cases”Small development team
- Create a “Dev Team Pool”
- Rent one or more servers into the pool
- Every developer deploys to the same servers
- One set of servers covers the whole team
Digital agency (multiple clients)
- One pool per client
- Rent servers into the matching client pool
- Complete data separation between clients
- Per-client billing
- Rent new servers into client pools as clients come and go
Enterprise multi-team
- Create pools by department or function
- Rent as many servers per pool as the work needs
- Role-based access across pools
- Developers can be members of multiple pools
- Budget and resource tracking per pool
Open source project
- Create a “Community Pool”
- Rent one or more servers and add every contributor as a User
- Anyone can deploy demos and test branches
- The owner keeps production deployments
- Contributors share the infrastructure cost
Freelancer to agency
- Start in the default pool with your personal servers
- First client: create a “Client Pool” and rent a server into it
- More clients: more pools
- Hiring: add developers to the client pools they work on
Multi-pool access
Section titled “Multi-pool access”One user can belong to several pools, with a different role in each:
Developer Jane: → "Frontend Pool" (User) - Can deploy frontend containers → "Staging Pool" (Admin) - Manages staging infrastructure → "AI Experiments" (User) - Access to AI playgroundRoles are per pool, so someone’s access can change in one pool without touching any other, and a pool’s member list shows who can reach its servers.
Best practices
Section titled “Best practices”Pool design:
- Create pools for logical boundaries (team, client, environment)
- Don’t create one pool per server, which defeats the grouping
- Name pools clearly, because teams grow and members forget context
Role assignment:
- Start everyone as User and promote to Admin as needed
- Owners should be team leads or managers
- Audit roles quarterly, because people change responsibilities
Server organization:
- Group related work on the same servers
- Production servers in strict-access pools
- Development servers in open-access pools
- Scale servers together logically (e.g. 3 production servers in the production pool)
Security:
- Separate production and development pools
- Remember that server commands stay with the renter; pool roles never widen them
- Review pool membership regularly
- Remove members promptly when they leave the team or project
Cost management:
- Use pools to track infrastructure costs per team or client
- Pool-level usage monitoring
- Each pool shows the total cost of its servers
- Delete pools that never held a rental to clean up (a pool with rental history is permanent)
Useful questions
Section titled “Useful questions”Can members see each other’s containers?
Pool members see that containers exist on pool servers, but privacy depends on container permissions. By default, containers are isolated. Use container permissions to control access.
What happens when I delete a pool?
A pool can only be deleted when it is empty. Any server currently assigned to it, any past rental row referencing it, or any pending paid server reservation naming it as the delivery destination blocks deletion. Rental rows reference a pool permanently, so a pool that has ever held a rental can never be deleted. Only the owner may delete a pool, and the default pool can never be deleted.
Can a server be in multiple pools?
No, each server belongs to exactly one pool. A server’s pool is chosen when you rent it via pool_id.
Do pool members share container limits?
Container limits are per-server and per-project, not per-user. A server can carry an operator-set max_containers (10 on a free-tier slice; unset means unlimited on a rented machine), and that count includes every member’s containers on that host. On a capped server, pool members do share one set of slots. Projects can carry their own max_containers on top of that.
Can I change a member’s role after adding them?
Yes. Changing a member’s role (PUT /api/v1/pools/{id}/members/{userId}) is restricted to the pool owner. Admins can invite and remove members, but only the owner can promote or demote roles. Changes take effect immediately.
What if a pool member leaves the organization?
Remove them from the pool via API or dashboard. Their containers remain on pool servers but they lose all access. You can then delete their containers or reassign them to other members.
Can I limit which servers in a pool a member can access?
Not directly per server, but you can create separate pools with different server groups and add members to specific pools based on their needs.
Troubleshooting
Section titled “Troubleshooting”Can’t add a member to a pool
Cause: Unknown username, or member already in pool
Solution: Verify the username exists exactly as registered. Check the existing member list: inviting a user who is already a member returns a conflict, so you can’t add the same user twice.
Member can’t deploy containers to pool servers
Cause: Role doesn’t grant deployment permission, or server resource limits
Solution: Verify the member has the User role or higher, check that the server has resources available, and confirm the member’s container quota is not exhausted.
Server assignment fails
Cause: Invalid pool_id, or the target pool is not yours
Solution: A server’s pool is set at rental time via pool_id on POST /api/v1/servers/{id}/rent. Verify the pool_id is a valid 24-character hex ID and that you own that pool. A rented server can only be attached to a pool you own. Passing a pool you merely belong to, even as an Admin, returns 403 ACCESS_DENIED. Rent into your own pool instead.
Pool deletion blocked
Cause: You aren’t the owner, or the pool isn’t empty
Solution: Verify you’re the pool owner, because only the owner may delete a pool. Beyond that, a pool can only be deleted when it is empty: any server currently assigned to it, any past rental row referencing it, or any pending paid server reservation naming it blocks deletion, and the default pool can never be deleted. To remove a member from a pool, use DELETE /api/v1/pools/{id}/members/{userId} (admin or owner).
Member can’t accept a pool invitation
Cause: Member is looking in the wrong place, or the invitation was already removed
Solution: Invitations are not delivered by email. The invited user finds them via GET /api/v1/pools/invitations/pending (or the dashboard) and accepts with POST /api/v1/pools/{id}/accept. Verify you invited the correct username, and that you haven’t since removed the member (which clears the pending invitation).
What’s next
Section titled “What’s next”Servers:
- Rent Servers → - Get servers to add to pools
- Servers API → - Complete pools API reference
Team workflows:
- Projects & Containers → - Understand container deployment
- Proxy Permissions → - Control container access
Collaboration:
- Container Copy/Sync → - Share containers between servers
- Storage Shares → - Shared files across pool containers