Projects
Manage projects, members, roles, invitations, and billing responsibility.
Projects map to Better-Auth organizations. Every resource (app, server, domain, etc.) belongs to a project.
List Projects
GET /v1/projectsReturns all projects the authenticated user is a member of, with resource counts.
Auth: Required
Response (200):
{
"success": true,
"data": [
{
"id": "org_...",
"name": "My Project",
"slug": "my-project",
"servers": 2,
"domains": 3,
"members": 4,
"apps": 1,
"objectStorage": 1,
"containerRegistries": 0
}
]
}Get Project
GET /v1/projects/:projectIdReturns a single project with resource counts. Accepts project ID or slug.
Auth: Required
Get Project Stats
GET /v1/projects/:projectId/statsReturns resource creation history for the last 6 months, aggregated by month.
Auth: Required (member)
Response (200):
{
"success": true,
"data": [
{
"month": "2025-01",
"servers": 1,
"domains": 2,
"apps": 0,
"objectStorage": 0,
"containerRegistries": 0
}
]
}Create Project
POST /v1/projects/createCreates a new project. Provisions a DigitalOcean project and a platform organization.
Auth: Required
Request Body:
{
"name": "My New Project"
}Response (201):
{
"success": true,
"data": {
"id": "org_...",
"name": "My New Project",
"slug": "..."
}
}Rename Project
PATCH /v1/projects/:projectIdAuth: Required (owner or admin)
Request Body:
{
"name": "New Name"
}Update Billing Email
PATCH /v1/projects/:projectId/billing-emailSets or clears the project's billing email. This address receives invoices and
receipts sent by Stripe (it is mirrored onto the Stripe customer) as well as
billing notifications such as receipts and payment-failure notices. Pass null
to clear it — delivery then reverts to the biller's account email.
Auth: Required (owner or admin)
Request Body:
{
"billingEmail": "[email protected]"
}Response:
{
"success": true,
"data": {
"billingEmail": "[email protected]"
}
}Delete Project
DELETE /v1/projects/:projectIdDeletes a project. Fails if any resources (servers, apps, domains, etc.) still exist.
Auth: Required (owner only)
Members
Get My Role
GET /v1/projects/:projectId/members/meReturns the current user's role in the project.
Auth: Required (member)
List Members
GET /v1/projects/:projectId/membersReturns all members, pending invitations, and biller info.
Auth: Required (member, scope: members:read)
Invite Member
POST /v1/projects/:projectId/membersAuth: Required (write access, scope: members:write)
Request Body:
{
"email": "[email protected]",
"role": "developer"
}Remove Member
DELETE /v1/projects/:projectId/members/:memberIdAuth: Required (write access, scope: members:write)
The project's biller cannot be removed while they hold billing responsibility. Attempting to remove them returns 409 with a code of BILLER_CANNOT_LEAVE — transfer billing to another member first.
Update Member Role
PATCH /v1/projects/:projectId/members/:memberId/roleAuth: Required (write access, scope: members:write)
Request Body:
{
"role": "admin"
}Valid roles: viewer, developer, admin, owner
Cancel Invitation
DELETE /v1/projects/:projectId/members/invitations/:invitationIdAuth: Required (write access, scope: members:write)
Billing Responsibility Transfer
Initiate Transfer
POST /v1/projects/:projectId/members/biller/transferTransfers billing responsibility to another member. The nominated member is notified (email + in-app) with a link to accept. Accepting and declining also notify the outgoing biller.
Before initiating a transfer, the outgoing biller can optionally refund any remaining project credit to their payment method via Refund Credit Balance — otherwise the credit stays with the project for the incoming biller. That refund is issued minus non-recoverable payment-processing (transaction) fees, so the amount received is less than the credit balance; see Refund Credit Balance for details.
Accept Transfer
POST /v1/projects/:projectId/members/biller/acceptAccepting a transfer requires the new biller to add a payment method to the project. First create an org setup intent (POST /v1/projects/:projectId/billing/setup-intent) and confirm the card in the browser, then pass the resulting payment method id here.
Request Body:
{
"paymentMethodId": "pm_..."
}The supplied card becomes the project's new default. The previous biller's card is detached once the transfer commits.
Decline Transfer
POST /v1/projects/:projectId/members/biller/decline