# Create client Source: https://apidocs.neetoinvoice.com/api-reference-v1/clients/create bundled-v1/clients.yaml POST /clients Create a client. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Get client Source: https://apidocs.neetoinvoice.com/api-reference-v1/clients/get bundled-v1/clients.yaml GET /clients/{client_id} Get a client. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update client Source: https://apidocs.neetoinvoice.com/api-reference-v1/clients/update bundled-v1/clients.yaml PUT /clients/{client_id} Update a client. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update client status Source: https://apidocs.neetoinvoice.com/api-reference-v1/clients/update-status bundled-v1/clients.yaml POST /clients/update_status Update client status. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Generate invoice Source: https://apidocs.neetoinvoice.com/api-reference-v1/invoices/create bundled-v1/invoices.yaml POST /clients/{client_id}/invoices Generate an invoice for a client. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Add project user Source: https://apidocs.neetoinvoice.com/api-reference-v1/project-users/add bundled-v1/project-users.yaml POST /projects/{project_id}/project_users Add a user to a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List project users Source: https://apidocs.neetoinvoice.com/api-reference-v1/project-users/list bundled-v1/project-users.yaml GET /projects/{project_id}/project_users List all users assigned to a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Remove project user Source: https://apidocs.neetoinvoice.com/api-reference-v1/project-users/remove bundled-v1/project-users.yaml DELETE /projects/{project_id}/project_users/{project_user_id} Remove a user from a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update project user Source: https://apidocs.neetoinvoice.com/api-reference-v1/project-users/update bundled-v1/project-users.yaml PATCH /projects/{project_id}/project_users/{project_user_id} Update a project user. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create project Source: https://apidocs.neetoinvoice.com/api-reference-v1/projects/create bundled-v1/projects.yaml POST /projects Create a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Get project Source: https://apidocs.neetoinvoice.com/api-reference-v1/projects/get bundled-v1/projects.yaml GET /projects/{project_id} Get a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update project Source: https://apidocs.neetoinvoice.com/api-reference-v1/projects/update bundled-v1/projects.yaml PATCH /projects/{project_id} Update a project. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update project status Source: https://apidocs.neetoinvoice.com/api-reference-v1/projects/update-status bundled-v1/projects.yaml POST /projects/update_status Update project status. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create recipient Source: https://apidocs.neetoinvoice.com/api-reference-v1/recipients/create bundled-v1/recipients.yaml POST /clients/{client_id}/recipients Create a recipient. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Delete recipient Source: https://apidocs.neetoinvoice.com/api-reference-v1/recipients/delete bundled-v1/recipients.yaml DELETE /clients/{client_id}/recipients/{recipient_id} Delete a recipient. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update recipient Source: https://apidocs.neetoinvoice.com/api-reference-v1/recipients/update bundled-v1/recipients.yaml PUT /clients/{client_id}/recipients/{recipient_id} Update a recipient. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Add team members Source: https://apidocs.neetoinvoice.com/api-reference-v1/team-members/add bundled-v1/team-members.yaml POST /team_members Add team members. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List team members Source: https://apidocs.neetoinvoice.com/api-reference-v1/team-members/list bundled-v1/team-members.yaml GET /team_members List all team members. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Remove team members Source: https://apidocs.neetoinvoice.com/api-reference-v1/team-members/remove bundled-v1/team-members.yaml DELETE /team_members Remove team members. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update team member Source: https://apidocs.neetoinvoice.com/api-reference-v1/team-members/update bundled-v1/team-members.yaml PATCH /team_members/{team_member_id} Update a team member. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create time entry Source: https://apidocs.neetoinvoice.com/api-reference-v1/time-entry/create bundled-v1/time-entry.yaml POST /time_entry Create a time entry. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List time entries Source: https://apidocs.neetoinvoice.com/api-reference-v1/time-entry/list bundled-v1/time-entry.yaml GET /time_entries List unbilled time entries for a project. Only time entries not associated with billed invoices are returned. **Deprecated:** This is a **v1** endpoint and is deprecated. Please use the [v2 API](/api/introduction) instead. v1 endpoints will be removed in a future release. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Authentication Source: https://apidocs.neetoinvoice.com/api/authentication Learn how to authenticate your requests to the NeetoInvoice API using API keys. ## Generating an API key To use the NeetoInvoice APIs, you must first generate an API key: 1. Go to the **Admin panel** and click **API keys**. 2. Click **Add API key**. The **Add new API key** pane opens. 3. Enter a **Name** for the key. 4. Under **Type**, choose **General**. The **Zapier** type is only for the Zapier integration. 5. Pick an **Expiry date**, or check **Never expires**. 6. Click **Save changes**. 7. Copy the key from the **API keys** list using the copy icon. The key stays in the list, so you can copy it again later. [Learn more about API keys here.](https://help.neetoinvoice.com/articles/api-keys) ## Making authenticated API requests To authenticate your API requests, include a valid API key in the `X-Api-Key` header. ```bash theme={"system"} curl https://{your-subdomain}.neetoinvoice.com/api/external/v2/team-members \ --header 'X-Api-Key: your-api-key' \ --header 'Content-Type: application/json' ``` ## Header format Include your API key in the `X-Api-Key` header of every request: ```http theme={"system"} X-Api-Key: your-api-key ``` Generate separate API keys for different workspaces. An API key generated in one workspace will not work in another. API keys provide access to sensitive data. Treat them like passwords and follow security best practices. ## Error responses ### 401 Unauthorized If your API key is missing, invalid, or expired, you'll receive a 401 error: ```json theme={"system"} { "error": "Could not authenticate, invalid API Key" } ``` ### Common authentication issues **Problem**: API key is missing or invalid.
**Solution**: Verify your API key is correct and hasn't been revoked/expired.
**Problem**: Subdomain is left as the default value (**spinkart**) or incorrect.
**Solution**: Verify your subdomain name is properly added in the request URL.
# Create client Source: https://apidocs.neetoinvoice.com/api/clients/create bundled/clients.yaml POST /clients Create a client. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Get client Source: https://apidocs.neetoinvoice.com/api/clients/get bundled/clients.yaml GET /clients/{client_id} Get a client. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update client Source: https://apidocs.neetoinvoice.com/api/clients/update bundled/clients.yaml PATCH /clients/{client_id} Update a client. Can also be used to update client status by passing `status` in the request body. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Getting the checklist ID Source: https://apidocs.neetoinvoice.com/api/getting-checklist-id Understand how to retrieve checklist IDs for use in your API calls. ## What is a checklist ID? A checklist ID is a unique identifier assigned to each individual checklist within a project task. Each checklist contains one or more items and is associated with a specific task. It's required for making API requests that interact with specific checklists, such as marking checklist items as completed in time entries. ### Step-by-step instructions Send a `GET` request to the [Get project details](/api/projects/get) API endpoint, including your API key in the request header. The response will contain a `checklists` array with individual checklist objects, each containing an `id` field. Each checklist is associated with a specific task and contains one or more checklist items. Example: ```json theme={"system"} { "project": { ... }, "tasks": [ ... ], "checklists": [ { "id": "6725d555-752a-4e40-bfef-9d87682b15ec", "task_name": "UI Design", "items": ["Create wireframes"], "required": [true] }, { "id": "7fbf0f63-bf11-4126-bd97-c3f557583974", "task_name": "Frontend Development", "items": ["Write unit tests"], "required": [true] } ] } ``` Here the checklist ID for the `UI Design` task is: **6725d555-752a-4e40-bfef-9d87682b15ec**. You can access the checklist ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first checklist's ID const checklistId = response.checklists[0].id; // Or iterate through all checklists to find a specific one const uiDesignChecklist = response.checklists.find(checklist => checklist.task_name === "UI Design"); const uiDesignChecklistId = uiDesignChecklist.id; ``` ```python Python theme={"system"} # Get the first checklist's ID checklist_id = response['checklists'][0]['id'] # Or iterate through all checklists to find a specific one ui_design_checklist = next(checklist for checklist in response['checklists'] if checklist['task_name'] == "UI Design") ui_design_checklist_id = ui_design_checklist['id'] ``` ```bash Bash theme={"system"} # Extract checklist ID using jq checklist_id=$(echo "$response" | jq -r '.checklists[0].id') # Or find a specific checklist by task name ui_design_checklist_id=$(echo "$response" | jq -r '.checklists[] | select(.task_name == "UI Design") | .id') ``` # Getting the client ID Source: https://apidocs.neetoinvoice.com/api/getting-client-id Understand how to retrieve client IDs for use in your API calls. ## What is a client ID? A client ID is a unique identifier assigned to each client in your workspace. It's required for making API requests that interact with specific clients, such as retrieving client details or updating client information. The client ID appears in the URL when you view a client in your workspace. For example, in the URL: ``` https://spinkart.neetoinvoice.com/admin/clients/2cef2469d56b68282951 ``` The client ID is: **2cef2469d56b68282951** ### Step-by-step instructions Log into your NeetoInvoice workspace and navigate to the client you want to work with. Once you're viewing the client details, look at your browser's address bar. The URL will contain the client ID. The client ID is typically found in the URL path. Look for a pattern like: ``` https://your-subdomain.neetoinvoice.com/admin/clients/{client-id} ``` The `{client-id}` part is what you need. ### URL examples Here are some examples of how client IDs appear in URLs: | URL Example | Client ID | | - | - | | `https://mycompany.neetoinvoice.com/admin/clients/2cef2469d56b68282951` | `2cef2469d56b68282951` | | `https://marketing.neetoinvoice.com/admin/clients/ab3d789f1234cdef5678` | `ab3d789f1234cdef5678` | | `https://events.neetoinvoice.com/admin/clients/f94ac346aa728da5f91b` | `f94ac346aa728da5f91b` | # Getting the project ID Source: https://apidocs.neetoinvoice.com/api/getting-project-id Understand how to retrieve project IDs for use in your API calls. ## What is a project ID? A project ID is a unique identifier assigned to each project in your workspace. It's required for making API requests that interact with specific projects, such as retrieving project details or updating project information. The project ID appears in the URL when you view a project in your workspace. For example, in the URL: ``` https://sojanvarghese.neetoinvoice.com/admin/projects/71f70673bc9d5da257b1/project-info ``` The project ID is: **71f70673bc9d5da257b1** ### Step-by-step instructions Log into your NeetoInvoice workspace and navigate to the project you want to work with. Once you're viewing the project details, look at your browser's address bar. The URL will contain the project ID. The project ID is typically found in the URL path. Look for a pattern like: ``` https://your-subdomain.neetoinvoice.com/admin/projects/{project-id}/project-info ``` The `{project-id}` part is what you need. ### URL examples Here are some examples of how project IDs appear in URLs: | URL Example | Project ID | | - | - | | `https://mycompany.neetoinvoice.com/admin/projects/71f70673bc9d5da257b1/project-info` | `71f70673bc9d5da257b1` | | `https://marketing.neetoinvoice.com/admin/projects/f95ac346aa728da5f91b/more` | `f95ac346aa728da5f91b` | | `https://events.neetoinvoice.com/admin/projects/sv3d789f1234cdef5678/integrations` | `sv3d789f1234cdef5678` | # Getting the project user ID Source: https://apidocs.neetoinvoice.com/api/getting-project-user-id Understand how to retrieve project user IDs for use in your API calls. ## What is a project user ID? A project user ID is a unique identifier assigned to each user's association with a specific project. It's required for making API requests that interact with specific project users, such as updating user roles or hourly rates within a project. ### Step-by-step instructions Send a `GET` request to the [List project users](/api/project-users/list) API endpoint, including your API key in the request header. The response will contain a `project_users` array with project user objects, each containing an `id` field. Example: ```json theme={"system"} { "project_users": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "user_id": "5a2de667-243b-4da3-b090-b698a03d98da", "role": "project_manager", "hourly_rate": 75.5, "name": "John Doe", "email": "john.doe@example.com", "time_zone": "UTC" }, { "id": "6be815a8-9a10-455c-95d9-b0b548664420", "user_id": "7b3ef778-354c-5eb4-c1a1-c8a9b14e09eb", "role": "developer", "hourly_rate": 60.0, "name": "Jane Smith", "email": "jane.smith@example.com", "time_zone": "America/New_York" } ] } ``` Here the project user ID for `John Doe` is: **128c1dfc-b29f-4fda-9a05-8a90e197b81b**. You can access the project user ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first project user's ID const projectUserId = response.project_users[0].id; // Or iterate through all project users to find a specific one const johnProjectUser = response.project_users.find(user => user.name === "John Doe"); const johnProjectUserId = johnProjectUser.id; ``` ```python Python theme={"system"} # Get the first project user's ID project_user_id = response['project_users'][0]['id'] # Or iterate through all project users to find a specific one john_project_user = next(user for user in response['project_users'] if user['name'] == "John Doe") john_project_user_id = john_project_user['id'] ``` ```bash Bash theme={"system"} # Extract project user ID using jq project_user_id=$(echo "$response" | jq -r '.project_users[0].id') # Or find a specific project user by name john_project_user_id=$(echo "$response" | jq -r '.project_users[] | select(.name == "John Doe") | .id') ``` # Getting the recipient ID Source: https://apidocs.neetoinvoice.com/api/getting-recipient-id Understand how to retrieve recipient IDs for use in your API calls. ## What is a recipient ID? A recipient ID is a unique identifier assigned to each recipient associated with a client in your workspace. It's required for making API requests that interact with specific recipients, such as updating recipient details or deleting recipients. ### Step-by-step instructions Send a `GET` request to the [Get client details](/api/clients/get) API endpoint, including your API key in the request header. The response will contain a `recipients` array with recipient objects, each containing an `id` field. Example: ```json theme={"system"} { "client": { "id": "a8b90a464cad12b48e45", "name": "Neeto Client Inc.", "status": "active", // ... rest of the details }, "recipients": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "name": "Tim Bradford", "email": "tim@example.com", "client_id": "a8b90a464cad12b48e45", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, { "id": "6be815a8-9a10-455c-95d9-b0b548664420", "name": "Jane Smith", "email": "jane@example.com", "client_id": "a8b90a464cad12b48e45", "created_at": "2024-01-16T09:15:00Z", "updated_at": "2024-01-16T09:15:00Z" } ] } ``` Here the recipient ID for `Tim Bradford` is: **128c1dfc-b29f-4fda-9a05-8a90e197b81b**. You can access the recipient ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first recipient's ID const recipientId = response.recipients[0].id; // Or iterate through all recipients to find a specific one const timRecipient = response.recipients.find(recipient => recipient.name === "Tim Bradford"); const timRecipientId = timRecipient.id; ``` ```python Python theme={"system"} # Get the first recipient's ID recipient_id = response['recipients'][0]['id'] # Or iterate through all recipients to find a specific one tim_recipient = next(recipient for recipient in response['recipients'] if recipient['name'] == "Tim Bradford") tim_recipient_id = tim_recipient['id'] ``` ```bash Bash theme={"system"} # Extract recipient ID using jq recipient_id=$(echo "$response" | jq -r '.recipients[0].id') # Or find a specific recipient by name tim_recipient_id=$(echo "$response" | jq -r '.recipients[] | select(.name == "Tim Bradford") | .id') ``` # Getting the task ID Source: https://apidocs.neetoinvoice.com/api/getting-task-id Understand how to retrieve task IDs for use in your API calls. ## What is a task ID? A task ID is a unique identifier assigned to each task within a project. It's required for making API requests that interact with specific tasks, such as creating time entries or generating invoices. ### Step-by-step instructions Send a `GET` request to the [Get project details](/api/projects/get) API endpoint, including your API key in the request header. The response will contain a `tasks` array with task objects, each containing an `id` field. Example: ```json theme={"system"} { "project": { ... }, "tasks": [ { "id": "4d0d7ad1-91ce-44d0-abfe-6718422716dd", "name": "UI Design", "hourly_rate": 75.0, "deleted": false, "hourly_rate_with_currency": "$75.00", "is_billable": true }, { "id": "f23a9c19-1153-4ef9-b488-1789f047b245", "name": "Frontend Development", "hourly_rate": 85.0, "deleted": false, "hourly_rate_with_currency": "$85.00", "is_billable": true } ], "checklists": [ ... ] } ``` Here the task ID for `UI Design` is: **4d0d7ad1-91ce-44d0-abfe-6718422716dd**. You can access the task ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first task's ID const taskId = response.tasks[0].id; // Or iterate through all tasks to find a specific one const uiDesignTask = response.tasks.find(task => task.name === "UI Design"); const uiDesignTaskId = uiDesignTask.id; ``` ```python Python theme={"system"} # Get the first task's ID task_id = response['tasks'][0]['id'] # Or iterate through all tasks to find a specific one ui_design_task = next(task for task in response['tasks'] if task['name'] == "UI Design") ui_design_task_id = ui_design_task['id'] ``` ```bash Bash theme={"system"} # Extract task ID using jq task_id=$(echo "$response" | jq -r '.tasks[0].id') # Or find a specific task by name ui_design_task_id=$(echo "$response" | jq -r '.tasks[] | select(.name == "UI Design") | .id') ``` # Getting the time entry ID Source: https://apidocs.neetoinvoice.com/api/getting-time-entry-id Understand how to retrieve time entry IDs for use in your API calls. ## What is a time entry ID? A time entry ID is a unique identifier assigned to each time entry within a project. It's required for making API requests that interact with specific time entries, such as creating invoices with time entries. ### Step-by-step instructions Send a `GET` request to the [List time entries](/api/time-entry/list) API endpoint, including your API key in the request header. You'll need to provide the `client_id` and `project_id` as query parameters. The response will contain a `time_entries` array with time entry objects, each containing an `id` field. Example: ```json theme={"system"} { "time_entries": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "user_id": "5a2de667-243b-4da3-b090-b698a03d98da", "user_name": "John Doe", "user_email": "john@example.com", "task_id": "4d0d7ad1-91ce-44d0-abfe-6718422716dd", "task_name": "UI Design", "project_id": "e34204233797f4b637c5", "project_name": "Website Redesign", "client_id": "d3e77fe4b9cae1e82d8a", "client_name": "Acme Corp", "hours": 2.5, "recorded_on": "2025-01-15", "notes": "Completed working on adding tests.", "status": "unbilled", "created_at": "2025-01-15T10:30:00Z", "updated_at": "2025-01-15T10:30:00Z" }, { "id": "6be815a8-9a10-455c-95d9-b0b548664420", "user_id": "5a2de667-243b-4da3-b090-b698a03d98da", "user_name": "John Doe", "user_email": "john@example.com", "task_id": "f23a9c19-1153-4ef9-b488-1789f047b245", "task_name": "Frontend Development", "project_id": "e34204233797f4b637c5", "project_name": "Website Redesign", "client_id": "d3e77fe4b9cae1e82d8a", "client_name": "Acme Corp", "hours": 4.0, "recorded_on": "2025-01-16", "notes": "Implemented user authentication", "status": "unbilled", "created_at": "2025-01-16T09:15:00Z", "updated_at": "2025-01-16T09:15:00Z" } ], // ... rest of the details } ``` Here the time entry ID for the first entry is: **128c1dfc-b29f-4fda-9a05-8a90e197b81b**. You can access the time entry ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first time entry's ID const timeEntryId = response.time_entries[0].id; // Or iterate through all time entries to find a specific one const uiDesignEntry = response.time_entries.find(entry => entry.task_name === "UI Design"); const uiDesignEntryId = uiDesignEntry.id; ``` ```python Python theme={"system"} # Get the first time entry's ID time_entry_id = response['time_entries'][0]['id'] # Or iterate through all time entries to find a specific one ui_design_entry = next(entry for entry in response['time_entries'] if entry['task_name'] == "UI Design") ui_design_entry_id = ui_design_entry['id'] ``` ```bash Bash theme={"system"} # Extract time entry ID using jq time_entry_id=$(echo "$response" | jq -r '.time_entries[0].id') # Or find a specific time entry by task name ui_design_entry_id=$(echo "$response" | jq -r '.time_entries[] | select(.task_name == "UI Design") | .id') ``` # Getting the user ID Source: https://apidocs.neetoinvoice.com/api/getting-user-id Understand how to retrieve user IDs for use in your API calls. ## What is a user ID? A user ID is a unique identifier assigned to each team member in your workspace. It's required for making API requests that interact with specific users, such as adding users to projects or managing user permissions. ### Step-by-step instructions Send a `GET` request to the [List all team members](/api/team-members/list) API endpoint, including your API key in the request header. The response will contain a `team_members` array with team member objects, each containing an `id` field. Example: ```json theme={"system"} { "team_members": [ { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "time_zone": "UTC", "profile_image_url": null, "active": true, "organization_role": "admin" }, { "id": "7b3ef778-354c-5eb4-c1a1-c8a9b14e09eb", "email": "jane.smith@example.com", "first_name": "Jane", "last_name": "Smith", "time_zone": "America/New_York", "profile_image_url": "https://example.com/profile.jpg", "active": true, "organization_role": "editor" } ], // ... rest of the details } ``` Here the user ID for `John Doe` is: **5a2de667-243b-4da3-b090-b698a03d98da**. You can access the user ID in your code from the response using: ```javascript JavaScript theme={"system"} // Get the first user's ID const userId = response.team_members[0].id; // Or iterate through all users to find a specific one const johnUser = response.team_members.find(user => user.first_name === "John" && user.last_name === "Doe"); const johnUserId = johnUser.id; ``` ```python Python theme={"system"} # Get the first user's ID user_id = response['team_members'][0]['id'] # Or iterate through all users to find a specific one john_user = next(user for user in response['team_members'] if user['first_name'] == "John" and user['last_name'] == "Doe") john_user_id = john_user['id'] ``` ```bash Bash theme={"system"} # Extract user ID using jq user_id=$(echo "$response" | jq -r '.team_members[0].id') # Or find a specific user by name john_user_id=$(echo "$response" | jq -r '.team_members[] | select(.first_name == "John" and .last_name == "Doe") | .id') ``` # NeetoInvoice API Source: https://apidocs.neetoinvoice.com/api/introduction Welcome to the NeetoInvoice API documentation. The NeetoInvoice API is organized around REST principles and uses standard HTTP response codes. All API endpoints return JSON responses and require authentication. Before you start with NeetoInvoice APIs you will need the following: 1. [Workspace subdomain](/api/workspace-subdomain). 2. [API key](/api/authentication). ## Rate limiting API requests are subject to rate limiting to ensure fair use. If you exceed the rate limit, you'll receive a 429 response. If you encounter this error try again after some time. ## Need help? Visit our [help center](https://help.neetoinvoice.com), email us at [support@neetoinvoice.com](mailto:support@neetoinvoice.com), or join the [Neeto Community](https://neeto.com/community). The community is powered by Slack and is the fastest way to get help directly from the developers, designers, and product folks building NeetoInvoice. # Generate invoice Source: https://apidocs.neetoinvoice.com/api/invoices/create bundled/invoices.yaml POST /clients/{client_id}/invoices Generate an invoice for a client. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Pagination Source: https://apidocs.neetoinvoice.com/api/pagination Learn how to handle paginated responses in the NeetoInvoice API. ## Pagination parameters You can control pagination using the following query parameters: The page of results you want to retrieve (starting from 1). The number of items to return per page. ## Example usage Here's how to retrieve paginated results: ```bash cURL theme={"system"} curl --request GET \ --url "https://{your-subdomain}.neetoinvoice.com/api/external/v2/team-members?page_number=2&page_size=25" \ --header 'X-Api-Key: your-api-key' ``` ```javascript JavaScript theme={"system"} const response = await fetch( "https://{your-subdomain}.neetoinvoice.com/api/external/v2/team-members?page_number=2&page_size=25", { method: "GET", headers: { "X-Api-Key": "your-api-key", "Content-Type": "application/json", }, } ); const data = await response.json(); console.log(data); ``` ```python Python theme={"system"} import requests url = "https://{your-subdomain}.neetoinvoice.com/api/external/v2/team-members" params = { "page_number": 2, "page_size": 25 } headers = { "X-Api-Key": "your-api-key", "Content-Type": "application/json" } response = requests.get(url, params=params, headers=headers) data = response.json() print(data) ``` This retrieves the second page of team members, with 25 results per page. ## Response structure Paginated responses include metadata about the pagination: ```json Response example theme={"system"} { "team_members": [ // ... array of team member objects ], "pagination": { "total_records": 150, "current_page_number": 2, "total_pages": 6, "page_size": 25 } } ``` The total number of items across all pages. The current page number. The total number of pages available. The number of items per page. ## Default behavior * If you leave out `page_number`, you get the first page. * If you leave out `page_size`, each page has 30 items. ## Best practices 1. **Start with reasonable page sizes**: Use page sizes between 10-100 items for optimal performance. 2. **Handle empty results**: Always check if the returned array is empty to detect the end of data. 3. **Use total\_records**: Use the `pagination.total_records` field to calculate the total number of pages needed. 4. **Implement error handling**: Handle cases where the requested page doesn't exist. # Add project user Source: https://apidocs.neetoinvoice.com/api/project-users/add bundled/project-users.yaml POST /projects/{project_id}/project-users Add a user to a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List project users Source: https://apidocs.neetoinvoice.com/api/project-users/list bundled/project-users.yaml GET /projects/{project_id}/project-users List all users assigned to a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Remove project user Source: https://apidocs.neetoinvoice.com/api/project-users/remove bundled/project-users.yaml DELETE /projects/{project_id}/project-users/{project_user_id} Remove a user from a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update project user Source: https://apidocs.neetoinvoice.com/api/project-users/update bundled/project-users.yaml PATCH /projects/{project_id}/project-users/{project_user_id} Update a project user. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create project Source: https://apidocs.neetoinvoice.com/api/projects/create bundled/projects.yaml POST /projects Create a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Get project Source: https://apidocs.neetoinvoice.com/api/projects/get bundled/projects.yaml GET /projects/{project_id} Get a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update project Source: https://apidocs.neetoinvoice.com/api/projects/update bundled/projects.yaml PATCH /projects/{project_id} Update a project. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create recipient Source: https://apidocs.neetoinvoice.com/api/recipients/create bundled/recipients.yaml POST /clients/{client_id}/recipients Create a recipient. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Delete recipient Source: https://apidocs.neetoinvoice.com/api/recipients/delete bundled/recipients.yaml DELETE /clients/{client_id}/recipients/{recipient_id} Delete a recipient. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update recipient Source: https://apidocs.neetoinvoice.com/api/recipients/update bundled/recipients.yaml PUT /clients/{client_id}/recipients/{recipient_id} Update a recipient. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# HTTP response codes Source: https://apidocs.neetoinvoice.com/api/response-codes Learn about the HTTP status codes returned by the NeetoInvoice API. ## Success codes The request was successful and the server returned the requested data. The request was successful and a new resource was created. Returned for POST requests that create new resources. The request was successful but there is no content to return. Typically returned for DELETE operations. ## Error codes There was an issue with the request. This usually indicates malformed JSON, missing required parameters, or invalid parameter values. The request needs to be authenticated. This typically means: * Missing API key. * Invalid API key. * Expired API key. An operation was not allowed. This could mean: * Insufficient permissions for the requested action. * Attempting to access a resource you don't own. * API key doesn't have the required scope. The requested URL or resource was not found. This could indicate: * Incorrect endpoint URL. * Resource ID doesn't exist. * Workspace subdomain is incorrect. The given request could not be processed by the server due to malformed request. Check the request body once again. Rate limit exceeded. Try again after some time. ## Server error codes An unexpected error occurred on the server. If this persists, please contact support. The server does not support the functionality required to fulfill the request. ## Error response format When an error occurs, the API returns a JSON response with error details: ```json 401 Unauthorized theme={"system"} { "error": "Could not authenticate, invalid API Key" } ``` A human-readable error message. When debugging API issues, the HTTP status code often provides the first clue about what went wrong. Start by checking the status code before diving into the response body. # Add team members Source: https://apidocs.neetoinvoice.com/api/team-members/add bundled/team-members.yaml POST /team-members Add team members. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List team members Source: https://apidocs.neetoinvoice.com/api/team-members/list bundled/team-members.yaml GET /team-members List all team members. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Remove team members Source: https://apidocs.neetoinvoice.com/api/team-members/remove bundled/team-members.yaml DELETE /team-members Remove team members. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Update team member Source: https://apidocs.neetoinvoice.com/api/team-members/update bundled/team-members.yaml PATCH /team-members/{team_member_id} Update a team member. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Create time entry Source: https://apidocs.neetoinvoice.com/api/time-entry/create bundled/time-entry.yaml POST /time-entries Create a time entry. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# List time entries Source: https://apidocs.neetoinvoice.com/api/time-entry/list bundled/time-entry.yaml GET /time-entries List unbilled time entries for a project. Only time entries not associated with billed invoices are returned. Replace `{your-subdomain}` with your workspace's subdomain.
Learn how to find your subdomain in [Workspace subdomain](/api/workspace-subdomain).
# Workspace subdomain Source: https://apidocs.neetoinvoice.com/api/workspace-subdomain Learn how to find your workspace subdomain. ## What is a subdomain? A subdomain is the part of your workspace URL that comes before the main domain. For example, in the URL: ``` https://spinkart.neetoinvoice.com ``` **spinkart** is the subdomain. This subdomain is crucial for making API requests, as it identifies your specific workspace within NeetoInvoice. ## Step-by-step instructions You can usually find this in your browser's address bar when logged into your workspace. Example: ``` https://your-subdomain.neetoinvoice.com ``` Our main domain is: `neetoinvoice.com` Everything before `neetoinvoice.com` is your subdomain. **Example:** * URL: `https://green-earth.neetoinvoice.com` * Subdomain: `green-earth` ## Using your subdomain in API requests Once you've identified your subdomain, you'll use it in all API requests. The base URL format is: ``` https://{your-subdomain}.neetoinvoice.com/api/external/v2 ``` For example, if your subdomain is `mycompany`, your API base URL would be: ``` https://mycompany.neetoinvoice.com/api/external/v2 ``` ## Common examples Here are some common subdomain patterns: | Type | Example URL | Subdomain | | - | - | - | | Company | `https://acmecorp.neetoinvoice.com` | `acmecorp` | | Department | `https://marketing.neetoinvoice.com` | `marketing` | | Project | `https://product-launch.neetoinvoice.com` | `product-launch` | # Clients Source: https://apidocs.neetoinvoice.com/cli-reference/clients List, view, create, and update clients. A client is a billed entity in a workspace. Each one owns its projects and its invoice recipients. For fields and response details, see the [API reference](/api/clients/get). A client is addressed by its `identifier`, the short hex string returned by `clients list` and `clients show`. The record `id` (a UUID) is what `projects create --client-id` expects. ## List clients Find a client's identifier by name or status. Start here when you have a name and need an ID for another command. ```bash theme={"system"} neetoinvoice clients list --name acme ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--name` | `string` | No | | Filter by name (substring match) | | `--status` | `string` | No | | Filter by status: active or archived | The response reports pagination like the other list commands, but `clients list` has no `--page` or `--page-size` flags, so every call returns the first page. See [Pagination](/cli/output-formats#pagination). ```json Sample output (--json) theme={"system"} { "data": [ { "id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "identifier": "7c1f5e2a9b", "name": "Acme Corp", "secondary_name": "Acme Holdings", "status": "active", "currency": "USD", "default_invoice_due_in_days": 30 } ], "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice clients show " } ], "pagination": { "total_records": 1, "total_pages": 1, "current_page_number": 1, "page_size": 30 } } ``` ## Show a client Show one client together with its invoice recipients. ```bash theme={"system"} neetoinvoice clients show 7c1f5e2a9b ``` **Required arguments:** * `` - The client's `identifier`. ```json Sample output (--json) theme={"system"} { "data": { "client": { "id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "identifier": "7c1f5e2a9b", "name": "Acme Corp", "status": "active", "currency": "USD" }, "recipients": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "name": "Sam Smith", "email": "sam@example.com" } ] }, "breadcrumbs": [ { "label": "Update", "command": "neetoinvoice clients update --name " }, { "label": "Add recipient", "command": "neetoinvoice recipients create --client --name --email --user-email " } ] } ``` ## Create a client Create a client. Only `--name` is required; the rest can be filled in later with `clients update`. ```bash theme={"system"} neetoinvoice clients create \ --name "Acme Corp" \ --secondary-name "Acme Holdings" \ --address "1 Market St, San Francisco, CA" \ --due-in-days 30 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--address` | `string` | No | | Full address | | `--due-in-days` | `int` | No | `0` | Default invoice due in days | | `--internal-notes` | `string` | No | | Internal notes | | `--name` | `string` | Yes | | Client name | | `--secondary-name` | `string` | No | | Secondary name | | `--status` | `string` | No | | Status (active/archived) | ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963" }, "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice clients show " } ] } ``` With `--quiet` the command prints the raw response, so read the new client's ID from `client_id`: ```bash theme={"system"} CLIENT_ID=$(neetoinvoice clients create --name "Acme Corp" --quiet | jq -r .client_id) ``` ## Update a client Update a client. Only the flags you pass are changed. ```bash theme={"system"} neetoinvoice clients update 7c1f5e2a9b --status archived ``` **Required arguments:** * `` - The client's `identifier`. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--address` | `string` | No | | Full address | | `--due-in-days` | `int` | No | `0` | Default invoice due in days | | `--internal-notes` | `string` | No | | Internal notes | | `--name` | `string` | No | | Client name | | `--secondary-name` | `string` | No | | Secondary name | | `--status` | `string` | No | | Status (active/archived) | ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up" }, "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice clients show " } ] } ``` # Invoices Source: https://apidocs.neetoinvoice.com/cli-reference/invoices Generate an invoice for a client from unbilled time entries or services. An invoice is generated for a client from its unbilled time entries, services, or both, then optionally emailed to the client's recipients. For fields and response details, see the [API reference](/api/invoices/create). ## Create an invoice Generate an invoice. Scalar fields are available as flags; line items, taxes, and email details are passed as a JSON file with `--json-file`. Flag values override the file's top-level keys, so you can keep a template file and vary the number and dates per run. ```bash theme={"system"} neetoinvoice invoices create \ --client 7c1f5e2a9b \ --user-email oliver@example.com \ --number INV-EXT-001 \ --issue-date 07/14/2026 \ --due-date 08/13/2026 \ --project-id 89d1b47d9f36af3c9ecf \ --json-file ./invoice.json ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | | `--due-date` | `string` | No | | Due date (MM/DD/YYYY) | | `--issue-date` | `string` | No | | Issue date (MM/DD/YYYY) | | `--json-file` | `string` | No | | Path to a JSON file with the full invoice payload (line items, taxes, email details) | | `--notes` | `string` | No | | Invoice notes | | `--number` | `string` | Yes | | Invoice number | | `--project-id` | `stringSlice` | No | `[]` | Project ID(s) to invoice (repeatable) | | `--send-email` | `bool` | No | `false` | Email the invoice to the client's recipients | | `--user-email` | `string` | Yes | | Email of the acting organization user | Dates use `MM/DD/YYYY`, unlike time entries, which use `YYYY-MM-DD`. ### The `--json-file` file The file holds the full invoice payload. An invoice needs either `invoice_time_entries` or `invoice_services`, plus a `total`. Billing unbilled time entries: ```json invoice.json theme={"system"} { "total": 500.0, "notes": "Payment terms: Net 30 days", "invoice_time_entries": [ { "time_entry_id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "project_id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "task_id": "24e6a2fe-31bb-686c-541a-9f36af3c9ecf", "user_id": "5a2de667-243b-4da3-b090-b698a03d98da", "notes": "Reviewed the new dashboard layout", "hours": 2.5, "hourly_rate": 120.0 } ] } ``` Billing a flat service instead: ```json invoice.json theme={"system"} { "total": 500.0, "invoice_services": [ { "notes": "Quarterly retainer", "quantity": 1, "unit_amount": 500.0, "project_id": "f627c399-379d-4d07-a6f6-90b7c9470ac0" } ] } ``` Get `time_entry_id` values from [`time-entries list`](/cli-reference/time-entries#list-time-entries). ### Emailing the invoice Pass `--send-email` and put the email details in the data file. `recipient_ids` are the client's recipients; find them with [`clients show`](/cli-reference/clients#show-a-client). ```json invoice.json theme={"system"} { "total": 500.0, "invoice_services": [ { "notes": "Quarterly retainer", "quantity": 1, "unit_amount": 500.0 } ], "invoice_details": { "subject": "Invoice INV-EXT-001 from Acme Corp", "message": "Please find attached your invoice for the services rendered.", "attach_pdf_invoice": "true", "send_me_a_copy": "false", "recipient_ids": ["128c1dfc-b29f-4fda-9a05-8a90e197b81b"] } } ``` ```bash theme={"system"} neetoinvoice invoices create \ --client 7c1f5e2a9b \ --user-email oliver@example.com \ --number INV-EXT-001 \ --send-email \ --json-file ./invoice.json ``` ### Taxes Add a `tax_details` array to the data file: ```json invoice.json theme={"system"} { "tax_details": [ { "name": "GST", "percentage": 10, "notes": "Goods and Services Tax", "selected": true } ] } ``` ### Output ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up", "invoice": { "id": "6be815a8-9a10-455c-95d9-b0b548664420", "number": "INV-EXT-001", "total": 500.0, "status": "sent", "issue_date": "2026-07-14", "due_date": "2026-08-13", "notes": "Payment terms: Net 30 days", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "organization_id": "9f36af3c-9ecf-4d07-a6f6-90b7c9470ac0", "created_at": "2026-07-14T09:12:04.000Z", "updated_at": "2026-07-14T09:12:04.000Z" } }, "breadcrumbs": [ { "label": "Client", "command": "neetoinvoice clients show " } ] } ``` # Monthly PTO Source: https://apidocs.neetoinvoice.com/cli-reference/monthly-ptos List the monthly PTO report and update PTO earned. A monthly PTO record tracks, for one user in one month, the hours expected, the hours worked, the PTO earned and used, the balance carried from the previous month, and any resulting salary deduction. ## List monthly PTO Read the report for a month. Omit `--user-email` for the whole organization. ```bash theme={"system"} neetoinvoice monthly-ptos list --month 7 --year 2026 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--month` | `int` | Yes | `0` | Month number (1-12) | | `--user-email` | `string` | No | | Filter to a single user by email | | `--year` | `int` | Yes | `0` | Year, e.g. 2026 | ```json Sample output (--json) theme={"system"} { "data": { "month": 7, "year": 2026, "monthly_ptos": [ { "user_email": "oliver@example.com", "user_name": "Oliver Smith", "expected_hours": 176.0, "hours_worked": 168.0, "pto_earned": 8.0, "pto_used": 8.0, "previous_month_pto": 4.0, "net_pto": 4.0, "salary_deduction": 0.0, "locked": false } ] } } ``` ## Update PTO earned Set PTO earned for one or more users in a month. `--email` is repeatable. Pass `--pto-earned 0`, or omit the flag, to clear earned PTO. ```bash theme={"system"} neetoinvoice monthly-ptos update-earned \ --month 7 \ --year 2026 \ --email oliver@example.com \ --email sam@example.com \ --pto-earned 8 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--email` | `stringSlice` | Yes | `[]` | User email (repeatable) | | `--month` | `int` | Yes | `0` | Month number (1-12) | | `--pto-earned` | `float64` | No | `0` | New PTO earned in hours (default: 0) | | `--year` | `int` | Yes | `0` | Year, e.g. 2026 | The response reports each email separately, so a bad address in the list does not fail the whole run. ```json Sample output (--json) theme={"system"} { "data": { "month": 7, "year": 2026, "updated": [ { "user_email": "oliver@example.com", "pto_earned": 8.0, "net_pto": 4.0 } ], "skipped": [{ "user_email": "sam@example.com", "reason": "User not found" }] } } ``` Reading the report and changing it are separate permissions. An account that can view monthly PTO may still be refused `update-earned`. # Commands overview Source: https://apidocs.neetoinvoice.com/cli-reference/overview Every neetoinvoice command grouped by resource, with links to the full reference. ## Global flags These flags work on every command and are left out of the per-command flag tables below. See [Output formats](/cli/output-formats) for details. | Flag | Description | | - | - | | `--json` | Force the JSON envelope even on a terminal | | `--quiet` | Emit the raw payload only, with no envelope | | `--toon` | Emit TOON, a compact format for AI assistants | | `--subdomain` | Select which signed-in subdomain the command targets | ### clients Manage clients | Command | Description | | - | - | | [`neetoinvoice clients create`](/cli-reference/clients) | Create a client | | [`neetoinvoice clients list`](/cli-reference/clients) | List clients (find a client's id by name) | | [`neetoinvoice clients show`](/cli-reference/clients) | Show a client and its recipients | | [`neetoinvoice clients update`](/cli-reference/clients) | Update a client | ### doctor Check CLI health and connectivity | Command | Description | | - | - | | [`neetoinvoice doctor`](/cli-reference/utility) | Check CLI health and connectivity | ### invoices Manage invoices | Command | Description | | - | - | | [`neetoinvoice invoices create`](/cli-reference/invoices) | Generate an invoice for a client | ### login Authenticate to NeetoInvoice via browser | Command | Description | | - | - | | [`neetoinvoice login`](/cli-reference/utility) | Authenticate to NeetoInvoice via browser | ### logout Sign out and clear saved credentials | Command | Description | | - | - | | [`neetoinvoice logout`](/cli-reference/utility) | Sign out and clear saved credentials | ### monthly-ptos View and manage the monthly PTO report | Command | Description | | - | - | | [`neetoinvoice monthly-ptos list`](/cli-reference/monthly-ptos) | List the monthly PTO report for a month and year | | [`neetoinvoice monthly-ptos update-earned`](/cli-reference/monthly-ptos) | Set PTO earned for users (e.g. 0 to remove earned PTO) | ### project-users Manage project users | Command | Description | | - | - | | [`neetoinvoice project-users create`](/cli-reference/project-users) | Add a user to a project | | [`neetoinvoice project-users delete`](/cli-reference/project-users) | Remove a user from a project | | [`neetoinvoice project-users list`](/cli-reference/project-users) | List users on a project | | [`neetoinvoice project-users update`](/cli-reference/project-users) | Update a project user | ### projects Manage projects | Command | Description | | - | - | | [`neetoinvoice projects create`](/cli-reference/projects) | Create a project | | [`neetoinvoice projects list`](/cli-reference/projects) | List projects (find a project's id, or a user's projects) | | [`neetoinvoice projects show`](/cli-reference/projects) | Show a project | | [`neetoinvoice projects update`](/cli-reference/projects) | Update a project | ### recipients Manage client recipients | Command | Description | | - | - | | [`neetoinvoice recipients create`](/cli-reference/recipients) | Add a recipient to a client | | [`neetoinvoice recipients delete`](/cli-reference/recipients) | Delete a client recipient | | [`neetoinvoice recipients update`](/cli-reference/recipients) | Update a client recipient | ### reports Timesheet, payroll and PTO reports | Command | Description | | - | - | | [`neetoinvoice reports missing-entries`](/cli-reference/reports) | Working days with no timesheet entry for a user | | [`neetoinvoice reports payroll-summary`](/cli-reference/reports) | Per-user working days and LOP days for a month | | [`neetoinvoice reports timesheet-summary`](/cli-reference/reports) | Per-user, per-day, per-project hours for a date range | ### setup Set up NeetoInvoice for AI coding assistants | Command | Description | | - | - | | [`neetoinvoice setup claude`](/cli-reference/utility) | Register NeetoInvoice plugin with Claude Code | | [`neetoinvoice setup codex`](/cli-reference/utility) | Add NeetoInvoice instructions for OpenAI Codex | | [`neetoinvoice setup copilot`](/cli-reference/utility) | Add NeetoInvoice instructions for GitHub Copilot | | [`neetoinvoice setup cursor`](/cli-reference/utility) | Write NeetoInvoice rules for Cursor IDE | | [`neetoinvoice setup gemini`](/cli-reference/utility) | Add NeetoInvoice instructions for Gemini CLI | | [`neetoinvoice setup windsurf`](/cli-reference/utility) | Write NeetoInvoice rules for Windsurf IDE | ### team-members Manage team members | Command | Description | | - | - | | [`neetoinvoice team-members create`](/cli-reference/team-members) | Invite team members | | [`neetoinvoice team-members delete`](/cli-reference/team-members) | Remove a team member | | [`neetoinvoice team-members list`](/cli-reference/team-members) | List team members | | [`neetoinvoice team-members show`](/cli-reference/team-members) | Show a team member | | [`neetoinvoice team-members update`](/cli-reference/team-members) | Update a team member | ### time-entries Manage time entries | Command | Description | | - | - | | [`neetoinvoice time-entries create`](/cli-reference/time-entries) | Log a time entry | | [`neetoinvoice time-entries delete`](/cli-reference/time-entries) | Delete a time entry | | [`neetoinvoice time-entries list`](/cli-reference/time-entries) | List unbilled time entries for a project | | [`neetoinvoice time-entries update`](/cli-reference/time-entries) | Update a time entry | ### update Update the CLI to the latest version | Command | Description | | - | - | | [`neetoinvoice update`](/cli-reference/utility) | Update the CLI to the latest version | ### version Print the CLI version | Command | Description | | - | - | | [`neetoinvoice version`](/cli-reference/utility) | Print the CLI version | ### whoami Show current authenticated user(s) | Command | Description | | - | - | | [`neetoinvoice whoami`](/cli-reference/utility) | Show current authenticated user(s) | # Project users Source: https://apidocs.neetoinvoice.com/cli-reference/project-users List, create, update, and delete the users assigned to a project. A project user is an organization member assigned to a project. Only an assigned user can log time against it. For fields and response details, see the [API reference](/api/project-users/list). Every command here takes `--project `. Roles are `regular_user` and `project_manager`. ## List project users List the users on a project. Use it to find the `project-user-id` that `update` and `delete` need. ```bash theme={"system"} neetoinvoice project-users list --project 89d1b47d9f36af3c9ecf ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--project` | `string` | Yes | | Project identifier | ```json Sample output (--json) theme={"system"} { "data": [ { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "user_id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "role": "project_manager", "hourly_rate": 120.0, "name": "Oliver Smith", "email": "oliver@example.com" } ], "breadcrumbs": [ { "label": "Add user", "command": "neetoinvoice project-users create --project --user-id " }, { "label": "Update", "command": "neetoinvoice project-users update --project " } ] } ``` ## Create a project user Add a user to a project. `--user-id` is the organization user's record ID, not their email; see [Getting the user ID](/api/getting-user-id). ```bash theme={"system"} neetoinvoice project-users create \ --project 89d1b47d9f36af3c9ecf \ --user-id 128c1dfc-b29f-4fda-9a05-8a90e197b81b \ --role project_manager \ --hourly-rate 120 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--hourly-rate` | `float64` | No | `0` | Hourly rate | | `--project` | `string` | Yes | | Project identifier | | `--role` | `string` | No | | Role (regular\_user/project\_manager) | | `--user-id` | `string` | Yes | | User ID to add | ```json Sample output (--json) theme={"system"} { "data": { "project_user": { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "user_id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "role": "project_manager", "hourly_rate": 120.0, "name": "Oliver Smith", "email": "oliver@example.com", "time_zone": "Asia/Kolkata" } }, "breadcrumbs": [ { "label": "List", "command": "neetoinvoice project-users list --project " } ] } ``` ## Update a project user Change a project user's role or hourly rate. ```bash theme={"system"} neetoinvoice project-users update 5a2de667-243b-4da3-b090-b698a03d98da \ --project 89d1b47d9f36af3c9ecf \ --hourly-rate 140 ``` **Required arguments:** * `` - The project user's record ID, from `project-users list`. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--hourly-rate` | `float64` | No | `0` | Hourly rate | | `--project` | `string` | Yes | | Project identifier | | `--role` | `string` | No | | Role (regular\_user/project\_manager) | ## Delete a project user Remove a user from a project. ```bash theme={"system"} neetoinvoice project-users delete 5a2de667-243b-4da3-b090-b698a03d98da \ --project 89d1b47d9f36af3c9ecf ``` **Required arguments:** * `` - The project user's record ID, from `project-users list`. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--project` | `string` | Yes | | Project identifier | ```text Sample output theme={"system"} Project user removed. ``` # Projects Source: https://apidocs.neetoinvoice.com/cli-reference/projects List, view, create, and update client projects. A project belongs to a client, holds the tasks people log time against, and carries the billing method used when the work is invoiced. For fields and response details, see the [API reference](/api/projects/get). A project is addressed by its `identifier`, the short hex string returned by `projects list`. `--client-id` is different: it takes the client's record `id`, a UUID. See [Getting the project ID](/api/getting-project-id). ## List projects Find a project's identifier, or list the projects a user is on. ```bash theme={"system"} neetoinvoice projects list --client-id 7c1f5e2a9b --status active ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client-id` | `string` | No | | Filter to one client (identifier or ID) | | `--status` | `string` | No | | Filter by status: active or archived | | `--user-email` | `string` | No | | Filter to a user's projects | The response reports pagination like the other list commands, but `projects list` has no `--page` or `--page-size` flags, so every call returns the first page. See [Pagination](/cli/output-formats#pagination). ```json Sample output (--json) theme={"system"} { "data": [ { "id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "identifier": "89d1b47d9f36af3c9ecf", "name": "Website Redesign", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "status": "active", "requires_daily_entry": false } ], "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice projects show " } ], "pagination": { "total_records": 1, "total_pages": 1, "current_page_number": 1, "page_size": 30 } } ``` On a terminal, this renders as a plain table with a page summary, the same way `clients list` does: ```text Sample output theme={"system"} ID IDENTIFIER NAME STATUS CLIENT ID REQUIRES DAILY ENTRY ──────────────────── ───────────── ────────────── ────── ──────────────────── ──────────────────── f627c399-379d-4d0... 89d1b47d9f... Website Redesign active 3f0c0f87-ddc7-45f... No Page 1 of 1 (1 total records) Show: neetoinvoice projects show ``` `--client-id` accepts either the client's `identifier` or its record `id`. ## Show a project Show a project with its client, tasks, checklists, and recurring invoice settings. Use it to find the `task_id` that `time-entries create` needs. ```bash theme={"system"} neetoinvoice projects show 89d1b47d9f36af3c9ecf ``` **Required arguments:** * `` - The project's `identifier`. ```json Sample output (--json) theme={"system"} { "data": { "project": { "id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "identifier": "89d1b47d9f36af3c9ecf", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "name": "Website Redesign", "status": "active", "hourly_rate": 120.0, "hourly_rate_with_currency": "$120.00", "flat_amount": null, "flat_amount_with_currency": null, "currency": "USD", "currency_symbol": "$", "creator_name": "Oliver Smith", "internal_notes": null, "billing_method": "Hourly Project Rate", "fixed_price_project": false, "hourly_person_rate": false, "hourly_task_rate": false, "hourly_project_rate": true, "client": { "id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "identifier": "7c1f5e2a9b", "name": "Acme Corp", "currency": "USD", "status": "active", "internal_notes": null }, "recurring_invoice": { "id": "6be815a8-9a10-455c-95d9-b0b548664420", "enabled": false, "first_issue_date": null, "frequency": null, "frequency_type": null, "time_to_send": null, "timezone": null, "interval": null }, "invoice_count": 3 }, "tasks": [ { "id": "24e6a2fe-31bb-686c-541a-9f36af3c9ecf", "name": "Design", "hourly_rate": null, "hourly_rate_with_currency": null, "deleted": false, "is_billable": true } ], "checklists": [] }, "breadcrumbs": [ { "label": "Project users", "command": "neetoinvoice project-users list --project " }, { "label": "Update", "command": "neetoinvoice projects update --user-email " } ] } ``` ## Create a project Create a project under a client. At least one `--task` is required, because a project must always have a task to log time against. ```bash theme={"system"} neetoinvoice projects create \ --name "Website Redesign" \ --client-id 3f0c0f87-ddc7-45f4-ad7a-c3690fa04963 \ --task Design \ --task Development \ --billing-method hourly_project_rate \ --hourly-rate 120 \ --currency USD \ --user-email oliver@example.com ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--billing-method` | `string` | No | | Billing method (hourly\_project\_rate, hourly\_person\_rate, hourly\_task\_rate, fixed\_price\_project) | | `--client-id` | `string` | Yes | | Client record ID (UUID) the project belongs to | | `--currency` | `string` | No | | Currency code (e.g. USD) | | `--flat-amount` | `float64` | No | `0` | Flat amount (for fixed price projects) | | `--hourly-rate` | `float64` | No | `0` | Hourly rate | | `--internal-notes` | `string` | No | | Internal notes | | `--name` | `string` | Yes | | Project name | | `--task` | `stringSlice` | Yes | `[]` | Task name to add to the project (repeatable; at least one task is required on create) | | `--user-email` | `string` | Yes | | Email of the acting organization user | Billing methods are `hourly_project_rate`, `hourly_person_rate`, `hourly_task_rate`, and `fixed_price_project`. Use `--flat-amount` instead of `--hourly-rate` for a fixed price project. ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up", "project": { "id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "identifier": "89d1b47d9f36af3c9ecf", "name": "Website Redesign", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "status": "active" } }, "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice projects show " }, { "label": "Add user", "command": "neetoinvoice project-users create --project --user-id " } ] } ``` ## Update a project Update a project. Only the flags you pass are changed. `--user-email` identifies the acting organization user and is always required. ```bash theme={"system"} neetoinvoice projects update 89d1b47d9f36af3c9ecf \ --hourly-rate 140 \ --user-email oliver@example.com ``` **Required arguments:** * `` - The project's `identifier`. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--billing-method` | `string` | No | | Billing method (hourly\_project\_rate, hourly\_person\_rate, hourly\_task\_rate, fixed\_price\_project) | | `--client-id` | `string` | No | | Client record ID (UUID) the project belongs to | | `--currency` | `string` | No | | Currency code (e.g. USD) | | `--flat-amount` | `float64` | No | `0` | Flat amount (for fixed price projects) | | `--hourly-rate` | `float64` | No | `0` | Hourly rate | | `--internal-notes` | `string` | No | | Internal notes | | `--name` | `string` | No | | Project name | | `--task` | `stringSlice` | No | `[]` | Task name to add to the project (repeatable; at least one task is required on create) | | `--user-email` | `string` | Yes | | Email of the acting organization user | # Recipients Source: https://apidocs.neetoinvoice.com/cli-reference/recipients Create, update, and delete the people who receive a client's invoices. A recipient is a contact an invoice is emailed to. Recipients belong to a client, so every command here takes `--client `. For fields and response details, see the [API reference](/api/recipients/create). To list a client's recipients, run [`clients show`](/cli-reference/clients#show-a-client). ## Create a recipient Add a recipient to a client. `--user-email` identifies the acting organization user. ```bash theme={"system"} neetoinvoice recipients create \ --client 7c1f5e2a9b \ --name "Sam Smith" \ --email sam@example.com \ --user-email oliver@example.com ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | | `--email` | `string` | Yes | | Recipient email | | `--name` | `string` | Yes | | Recipient name | | `--user-email` | `string` | Yes | | Email of the acting organization user | ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up", "recipient": { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "name": "Sam Smith", "email": "sam@example.com" } }, "breadcrumbs": [ { "label": "Client", "command": "neetoinvoice clients show " } ] } ``` ## Update a recipient Change a recipient's name or email. Only the flags you pass are changed. ```bash theme={"system"} neetoinvoice recipients update 128c1dfc-b29f-4fda-9a05-8a90e197b81b \ --client 7c1f5e2a9b \ --email accounts@example.com ``` **Required arguments:** * `` - The recipient's record ID. See [Getting the recipient ID](/api/getting-recipient-id). | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | | `--email` | `string` | No | | Recipient email | | `--name` | `string` | No | | Recipient name | ```json Sample output (--json) theme={"system"} { "data": { "notice_code": "thumbs_up", "recipient": { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "name": "Sam Smith", "email": "accounts@example.com" } }, "breadcrumbs": [ { "label": "Client", "command": "neetoinvoice clients show " } ] } ``` ## Delete a recipient Remove a recipient from a client. ```bash theme={"system"} neetoinvoice recipients delete 128c1dfc-b29f-4fda-9a05-8a90e197b81b --client 7c1f5e2a9b ``` **Required arguments:** * `` - The recipient's record ID. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | ```text Sample output theme={"system"} Recipient deleted. ``` # Reports Source: https://apidocs.neetoinvoice.com/cli-reference/reports Show payroll summaries, timesheet summaries, and missing timesheet entries. A report is a read-only summary of logged time. Every report is gated by the permission to view time tracking entries, and viewing other people's entries is a separate permission from viewing your own. ## Show the payroll summary Per-user working days, present days, and loss-of-pay days for a month. ```bash theme={"system"} neetoinvoice reports payroll-summary --month 7 --year 2026 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--month` | `int` | Yes | `0` | Month number (1-12) | | `--year` | `int` | Yes | `0` | Year, e.g. 2026 | ```json Sample output (--json) theme={"system"} { "data": { "month": 7, "year": 2026, "working_days": 22, "rows": [ { "user_name": "Oliver Smith", "user_email": "oliver@example.com", "working_days": 22, "present_days": 21, "lop_days": 1 } ] } } ``` ## Show the timesheet summary Per-user, per-day, per-project hours for a date range. Omit `--user-email` for everyone. ```bash theme={"system"} neetoinvoice reports timesheet-summary \ --start-date 2026-07-01 \ --end-date 2026-07-07 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--end-date` | `string` | Yes | | Range end (YYYY-MM-DD) | | `--start-date` | `string` | Yes | | Range start (YYYY-MM-DD) | | `--user-email` | `string` | No | | Filter to a single user by email | ```json Sample output (--json) theme={"system"} { "data": { "start_date": "2026-07-01", "end_date": "2026-07-07", "users": [ { "user_email": "oliver@example.com", "user_name": "Oliver Smith", "total_hours": 36.5, "days": [ { "date": "2026-07-01", "entries": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "project_name": "Website Redesign", "task_name": "Design", "hours": 7.5 } ] } ] } ] } } ``` ## Show missing entries Working days in a range where a user logged nothing. Useful for a weekly nudge. ```bash theme={"system"} neetoinvoice reports missing-entries \ --user-email oliver@example.com \ --start-date 2026-07-01 \ --end-date 2026-07-31 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--end-date` | `string` | Yes | | Range end (YYYY-MM-DD) | | `--start-date` | `string` | Yes | | Range start (YYYY-MM-DD) | | `--user-email` | `string` | Yes | | User email | ```json Sample output (--json) theme={"system"} { "data": { "user_email": "oliver@example.com", "start_date": "2026-07-01", "end_date": "2026-07-31", "missing_days": ["2026-07-09", "2026-07-23"], "count": 2 } } ``` Pipe it into a script with `--quiet`: ```bash theme={"system"} neetoinvoice reports missing-entries \ --user-email oliver@example.com \ --start-date 2026-07-01 \ --end-date 2026-07-31 \ --quiet | jq -r '.missing_days[]' ``` # Team members Source: https://apidocs.neetoinvoice.com/cli-reference/team-members List, view, add, update, and remove team members. A team member is a user of a workspace. Each one carries an organization role, which decides what they can see and change. For fields and response details, see the [API reference](/api/team-members/list). A team member is addressed by its record `id`, a UUID returned by `team-members list`. The same value is what `project-users create --user-id` expects. Only active members resolve: a member removed with `team-members delete` is no longer found by `show`, `update`, or `delete`. ## List team members List the active members of the workspace. Use it to find a member's `id`, or to check who already has access before inviting someone. ```bash theme={"system"} neetoinvoice team-members list --email oliver@example.com ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--email` | `string` | No | | Filter by email address | | `--page` | `int` | No | `0` | Page number | | `--page-size` | `int` | No | `0` | Items per page (max 100) | `--email` matches one address exactly; it does not search by partial address. Results are paginated. `--page-size` defaults to `0`, which sends no page size and lets the API return 30 per page; the maximum is 100. ```json Sample output (--json) theme={"system"} { "data": [ { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "email": "oliver@example.com", "first_name": "Oliver", "last_name": "Smith", "time_zone": "Asia/Kolkata", "profile_image_url": null, "active": true, "organization_role": "Admin" } ], "breadcrumbs": [ { "label": "Show", "command": "neetoinvoice team-members show " } ], "pagination": { "total_records": 1, "total_pages": 1, "current_page_number": 1, "page_size": 30 } } ``` ## Show a team member Show one member: email, name, time zone, role, and whether they are active. ```bash theme={"system"} neetoinvoice team-members show 5a2de667-243b-4da3-b090-b698a03d98da ``` **Required arguments:** * `` - The team member's record ID, from `team-members list`. ```json Sample output (--json) theme={"system"} { "data": { "team_member": { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "email": "oliver@example.com", "first_name": "Oliver", "last_name": "Smith", "time_zone": "Asia/Kolkata", "profile_image_url": null, "active": true, "organization_role": "Admin" } }, "breadcrumbs": [ { "label": "Update", "command": "neetoinvoice team-members update --role " } ] } ``` ## Add team members Invite one or more people by email and give them an organization role. `--email` is repeatable. `--role` must name a role that exists on the workspace's Roles page, and the value is case sensitive. ```bash theme={"system"} neetoinvoice team-members create \ --email sam@example.com \ --email jane@example.com \ --role Admin ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--email` | `stringSlice` | Yes | `[]` | Email address to invite (repeatable) | | `--invited-by` | `string` | No | | Inviter name or email | | `--role` | `string` | Yes | | Organization role | | `--send-invitation-email` | `bool` | No | `true` | Send invitation email | Every invitee gets an invitation email unless you pass `--send-invitation-email=false`. `--invited-by` is the email of the admin the invitation is sent from; it defaults to the workspace's most recently added admin. ```json Sample output (--json) theme={"system"} { "data": { "message": "Users added successfully" }, "breadcrumbs": [ { "label": "List", "command": "neetoinvoice team-members list" } ] } ``` The response confirms the request and does not include the new member records. Run `team-members list --email
` afterwards to get an `id`. ## Update a team member Change a member's email, name, time zone, or role. Only the flags you pass are changed, and at least one is required. ```bash theme={"system"} neetoinvoice team-members update 5a2de667-243b-4da3-b090-b698a03d98da \ --first-name Oliver \ --role Admin ``` **Required arguments:** * `` - The team member's record ID, from `team-members list`. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--email` | `string` | No | | New email address | | `--first-name` | `string` | No | | First name | | `--last-name` | `string` | No | | Last name | | `--role` | `string` | No | | Organization role | | `--time-zone` | `string` | No | | Time zone | ```json Sample output (--json) theme={"system"} { "data": { "team_member": { "id": "5a2de667-243b-4da3-b090-b698a03d98da", "email": "oliver@example.com", "first_name": "Oliver", "last_name": "Smith", "time_zone": "Asia/Kolkata", "profile_image_url": null, "active": true, "organization_role": "Admin" } } } ``` ## Delete a team member Remove a member from the workspace. The member is deactivated rather than erased. ```bash theme={"system"} neetoinvoice team-members delete 5a2de667-243b-4da3-b090-b698a03d98da ``` **Required arguments:** * `` - The team member's record ID, from `team-members list`. ```text Sample output theme={"system"} Team member removed. ``` With `--quiet` the command prints `success`. # Time entries Source: https://apidocs.neetoinvoice.com/cli-reference/time-entries List, create, update, and delete time entries on a project. A time entry records hours logged by a user against a project's task. Unbilled entries are the raw material for invoices. For fields and response details, see the [API reference](/api/time-entry/list). `--task-id` is a task's record ID. Get it from [`projects show`](/cli-reference/projects#show-a-project), or see [Getting the task ID](/api/getting-task-id). ## List time entries List a project's unbilled time entries. The result is paginated, so the command accepts `--page` and `--page-size` and reports a `pagination` object in the envelope with `total_records`, `total_pages`, `current_page_number`, and `page_size`. See [Pagination](/cli/output-formats#pagination). ```bash theme={"system"} neetoinvoice time-entries list \ --client 7c1f5e2a9b \ --project 89d1b47d9f36af3c9ecf \ --start-date 2026-07-01 \ --end-date 2026-07-31 ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | | `--end-date` | `string` | No | | Filter entries recorded on or before this date (YYYY-MM-DD) | | `--page` | `int` | No | `0` | Page number | | `--page-size` | `int` | No | `0` | Items per page (max 100) | | `--project` | `string` | Yes | | Project identifier | | `--start-date` | `string` | No | | Filter entries recorded on or after this date (YYYY-MM-DD) | | `--task-id` | `string` | No | | Filter to a single task's entries by task ID | | `--user-email` | `string` | No | | Filter to a single user's entries by email | Pass `--task-id` to narrow the result to one task, which is how you read the hours logged against a single task without filtering the whole project by hand. Task IDs come from [`projects show`](/cli-reference/projects#show-a-project). ```bash theme={"system"} neetoinvoice time-entries list \ --client 7c1f5e2a9b \ --project 89d1b47d9f36af3c9ecf \ --task-id 4f2a91c7-3ebd-4c1a-9f77-58ac2d6e0b41 \ --start-date 2026-07-01 \ --end-date 2026-07-31 ``` ```json Sample output (--json) theme={"system"} { "data": [ { "id": "128c1dfc-b29f-4fda-9a05-8a90e197b81b", "user_id": "5a2de667-243b-4da3-b090-b698a03d98da", "task_id": "24e6a2fe-31bb-686c-541a-9f36af3c9ecf", "hours": 2.5, "recorded_on": "2026-07-14", "notes": "Reviewed the new dashboard layout", "status": "submitted", "created_at": "2026-07-14T09:12:04.000Z", "updated_at": "2026-07-14T09:12:04.000Z", "user_name": "Oliver Smith", "user_email": "oliver@example.com", "task_name": "Design", "project_id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "project_name": "Website Redesign", "client_id": "3f0c0f87-ddc7-45f4-ad7a-c3690fa04963", "client_name": "Acme Corp" } ], "breadcrumbs": [ { "label": "Log time", "command": "neetoinvoice time-entries create --client --project --task-id --user-email --recorded-on --hours " } ], "pagination": { "total_records": 42, "total_pages": 2, "current_page_number": 1, "page_size": 30 } } ``` ## Create a time entry Log time against a task. `--user-email` is the organization user the hours belong to, which is not necessarily the signed-in user. ```bash theme={"system"} neetoinvoice time-entries create \ --client 7c1f5e2a9b \ --project 89d1b47d9f36af3c9ecf \ --task-id 24e6a2fe-31bb-686c-541a-9f36af3c9ecf \ --user-email oliver@example.com \ --recorded-on 2026-07-14 \ --hours 2.5 \ --notes "Reviewed the new dashboard layout" ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--client` | `string` | Yes | | Client identifier | | `--hours` | `float64` | No | `0` | Hours spent (omit for no-hours projects) | | `--is-override` | `bool` | No | `false` | Override autolock for a locked date | | `--notes` | `string` | No | | Notes | | `--project` | `string` | Yes | | Project identifier | | `--recorded-on` | `string` | Yes | | Date the time was recorded (YYYY-MM-DD) | | `--task-id` | `string` | Yes | | Task ID | | `--user-email` | `string` | Yes | | Email of the organization user logging the time | Pass `--is-override` to log against a date that autolock has already closed. Your role must permit overriding autolock. ## Update a time entry Change an entry's hours, notes, or date. Only the flags you pass are changed. ```bash theme={"system"} neetoinvoice time-entries update 128c1dfc-b29f-4fda-9a05-8a90e197b81b \ --hours 3 \ --user-email oliver@example.com ``` **Required arguments:** * `` - The entry's record ID. See [Getting the time entry ID](/api/getting-time-entry-id). * `--user-email` - The email of the user the entry belongs to. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--hours` | `float64` | No | `0` | New hours | | `--is-override` | `bool` | No | `false` | Override autolock for a locked date | | `--notes` | `string` | No | | New notes | | `--recorded-on` | `string` | No | | New date (YYYY-MM-DD) | | `--user-email` | `string` | Yes | | Email of the user the time entry belongs to | An entry that has already been invoiced cannot be edited or deleted. Adjust the invoice instead. ## Delete a time entry Delete a time entry. ```bash theme={"system"} neetoinvoice time-entries delete 128c1dfc-b29f-4fda-9a05-8a90e197b81b \ --user-email oliver@example.com ``` **Required arguments:** * `` - The entry's record ID. * `--user-email` - The email of the user the entry belongs to. | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--user-email` | `string` | Yes | | Email of the user the time entry belongs to | ```text Sample output theme={"system"} Time entry deleted. ``` # Utility commands Source: https://apidocs.neetoinvoice.com/cli-reference/utility Authentication, diagnostics, versioning, upgrades, AI-assistant setup, and shell completion. These commands manage the CLI itself rather than a NeetoInvoice resource. ## Authentication ### login ```bash theme={"system"} neetoinvoice login --subdomain your-workspace ``` Opens your browser to sign in and saves credentials for the workspace. Omit `--subdomain` to be prompted. ```text Sample output theme={"system"} Authenticated as oliver@example.com on acme.neetoinvoice.com. ``` ### logout ```bash theme={"system"} neetoinvoice logout --subdomain your-workspace neetoinvoice logout --all ``` | Flag | Type | Required | Default | Description | | - | - | - | - | - | | `--all` | `bool` | No | `false` | Sign out of every saved subdomain | ```text Sample output theme={"system"} Signed out of acme.neetoinvoice.com. ``` ### whoami ```bash theme={"system"} neetoinvoice whoami ``` Lists each signed-in account and marks it `(default)` when only one is signed in. Pass `--subdomain ` to show one workspace. ```text Sample output theme={"system"} Authenticated as oliver@example.com on acme.neetoinvoice.com (default). ``` ## Diagnostics ### doctor ```bash theme={"system"} neetoinvoice doctor ``` Checks authentication, API reachability, and the CLI version. See [Troubleshooting](/cli/troubleshooting). When several workspaces are signed in, pass `--subdomain `. ```text Sample output theme={"system"} ✓ Authentication: authenticated as oliver@example.com on acme.neetoinvoice.com ✓ API connection: https://acme.neetoinvoice.com (responding in 214ms) ✓ CLI version: 1.4.0 ``` ### version ```bash theme={"system"} neetoinvoice version ``` Prints the CLI version, commit hash, and build date. ```text Sample output theme={"system"} neetoinvoice 1.4.0 (commit: a1b2c3d, built: 2026-07-01) ``` ### commands ```bash theme={"system"} neetoinvoice commands ``` Prints the complete command and flag catalog for the installed version as JSON. It is useful in scripts and with AI assistants. ```json Sample output theme={"system"} [ { "command": "neetoinvoice clients", "description": "Manage clients", "subcommands": [ { "command": "neetoinvoice clients list", "description": "List clients (find a client's id by name)", "flags": [ { "name": "status", "type": "string", "description": "Filter by status: active or archived" } ] } ] } ] ``` ## Upgrade ### update ```bash theme={"system"} neetoinvoice update ``` Updates the CLI to the latest release using the method that installed it. When the binary lives in a Homebrew Cellar it runs `brew update && brew upgrade neetozone/tap/neetoinvoice`; on other macOS and Linux installs it downloads the shell installer to a temporary file and runs it; on Windows it runs the PowerShell installer. The installers are the same ones the [Installation](/cli/installation) page uses, fetched over HTTPS. The command prints the detected method and the command it runs, and exits non-zero if that command fails. ```text Sample output theme={"system"} Detected Homebrew install. Running: brew update && brew upgrade neetozone/tap/neetoinvoice ``` After upgrading, re-run `neetoinvoice completion ` and any `neetoinvoice setup` command you use so their files match the new version. ## AI-assistant setup Add NeetoInvoice instructions to your AI coding assistant. See [AI assistants](/cli/ai-assistants) for details. ```bash theme={"system"} neetoinvoice setup claude neetoinvoice setup cursor neetoinvoice setup windsurf neetoinvoice setup copilot neetoinvoice setup gemini neetoinvoice setup codex ``` ```text Sample output theme={"system"} NeetoInvoice plugin extracted to /Users/oliver/.config/neetoinvoice/claude-plugin To finish installation, open Claude Code and run these slash commands: /plugin marketplace add /Users/oliver/.config/neetoinvoice/claude-plugin /plugin install neetoinvoice@neetoinvoice (Claude Code installs plugins via interactive slash commands - there is no shell equivalent today.) ``` ## Shell completion Shell completion fills in command names, subcommands, and flags when you press `Tab`. It saves you from having to remember the full command tree or look up `--help`. `neetoinvoice completion ` installs completion for your shell. For zsh, bash, and PowerShell it writes the script under `~/.config/neetoinvoice/completions` and adds a marked block to `~/.zshrc`, `~/.bashrc`, or `~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1` that loads it the next time the shell starts. For fish it writes `~/.config/fish/completions/neetoinvoice.fish`, which fish loads on its own. ```bash Zsh theme={"system"} neetoinvoice completion zsh ``` ```bash Bash theme={"system"} neetoinvoice completion bash ``` ```bash Fish theme={"system"} neetoinvoice completion fish ``` ```powershell PowerShell theme={"system"} neetoinvoice completion powershell ``` Start a new shell (or run `source ~/.zshrc`) to enable it. After upgrading the CLI, run the command again to update the available completions. Re-running it replaces the existing script and configuration without adding duplicates. To configure it yourself, pass `--print` to write the raw script to standard output instead of installing it: ```bash theme={"system"} neetoinvoice completion zsh --print ``` # AI assistants Source: https://apidocs.neetoinvoice.com/cli/ai-assistants Set up NeetoInvoice for Claude, Cursor, Copilot, and other AI coding assistants. Use the CLI with an AI coding assistant to manage NeetoInvoice in plain language. The `neetoinvoice setup` commands add NeetoInvoice instructions for your assistant, while [`--toon`](/cli/output-formats) keeps command output compact for it to read. ## Set up your assistant Run the subcommand for the tool you use: | Command | What it does | | - | - | | `neetoinvoice setup claude` | Extracts the NeetoInvoice plugin (manifest, marketplace, session-start hook, and skill) to `~/.config/neetoinvoice/claude-plugin`, replacing any earlier copy. Requires `~/.claude/` to exist. | | `neetoinvoice setup cursor` | Writes `.cursor/rules/neetoinvoice.mdc`. Overwrites the file. | | `neetoinvoice setup windsurf` | Writes `.windsurf/rules/neetoinvoice.md`. Overwrites the file. | | `neetoinvoice setup copilot` | Adds a NeetoInvoice section to `.github/copilot-instructions.md`. Keeps the rest of the file. | | `neetoinvoice setup gemini` | Adds a NeetoInvoice section to `GEMINI.md`. Keeps the rest of the file. | | `neetoinvoice setup codex` | Adds a NeetoInvoice section to `AGENTS.md`. Keeps the rest of the file. | Every subcommand except `setup claude` writes into the current directory, so run it from the root of the project the assistant works in. The `copilot`, `gemini`, and `codex` commands place their section between `` and `` markers and replace that section on re-run instead of adding a duplicate. Re-run the command after every CLI upgrade so the instructions match the installed version. ```bash theme={"system"} neetoinvoice setup claude ``` `setup claude` prints two slash commands to finish the installation inside Claude Code: ```text theme={"system"} /plugin marketplace add ~/.config/neetoinvoice/claude-plugin /plugin install neetoinvoice@neetoinvoice ``` After setup, your assistant can check the commands and flags available in your installed CLI version: ```bash theme={"system"} neetoinvoice commands ``` The command prints the complete catalog as JSON. ## Tips for agent workflows Prefer `--toon` when the assistant needs to read a list or record, and `--quiet` when it needs to pipe an identifier into the next command. See [Output formats](/cli/output-formats). * Authenticate once with [`neetoinvoice login`](/cli/authentication); the assistant reuses the stored credentials. * When several workspaces are signed in, the assistant must pass `--subdomain ` on each command. * Run [`neetoinvoice doctor`](/cli/troubleshooting) first to confirm the assistant is authenticated and connected. # Authentication Source: https://apidocs.neetoinvoice.com/cli/authentication Sign in through the browser and manage credentials for one or more workspaces. The CLI uses your browser to sign you in and securely saves your session, so you never need to enter an API key. ## Sign in ```bash theme={"system"} neetoinvoice login --subdomain your-workspace ``` Your browser opens to complete sign-in. The CLI also prints the sign-in URL in case the browser does not open, and waits up to five minutes for you to approve. Once you approve it, the CLI saves credentials for that subdomain. If you omit `--subdomain`, the CLI prompts for it. Your subdomain is the first part of your workspace URL - for `https://spinkart.neetoinvoice.com`, the subdomain is `spinkart`. See [Workspace subdomain](/cli/workspace-subdomain). ## Where credentials are stored Credentials for every signed-in workspace live in a single file: ```text theme={"system"} ~/.config/neetoinvoice/auth.json ``` Removing this file signs you out of every workspace, the same as `neetoinvoice logout --all`. ## Check who you are ```bash theme={"system"} neetoinvoice whoami ``` Lists every signed-in account. When exactly one is signed in, it is marked `(default)`. Pass `--subdomain ` to show just one. ## Sign out ```bash theme={"system"} neetoinvoice logout --subdomain your-workspace # remove one workspace neetoinvoice logout --all # remove every workspace neetoinvoice logout # remove the only one, if a single workspace is signed in ``` ## Working with multiple workspaces You can sign in to several subdomains at once. To add another workspace, name its subdomain: ```bash theme={"system"} neetoinvoice login --subdomain globex ``` When more than one workspace is signed in, every command that talks to the API requires `--subdomain`. If you omit it, the CLI errors and lists the signed-in workspaces. ```bash theme={"system"} neetoinvoice clients list --subdomain acme neetoinvoice clients list --subdomain globex ``` With one signed-in workspace, it is the default and `--subdomain` stays optional. ## Environment variables `NEETOINVOICE_BASE_URL` overrides the server the CLI talks to. By default every command, including `login`, uses `https://.neetoinvoice.com`. Set the variable to point the CLI at a staging or local server. Every request, including the session token saved in `~/.config/neetoinvoice/auth.json`, goes to that server, so only point it at a server you trust: ```bash theme={"system"} export NEETOINVOICE_BASE_URL=https://acme.neetoinvoice.net neetoinvoice login --subdomain acme ``` ## Troubleshooting If sign-in or connection problems come up, run `neetoinvoice doctor` first. See [Troubleshooting](/cli/troubleshooting) for common issues and fixes. # Installation Source: https://apidocs.neetoinvoice.com/cli/installation Install the neetoinvoice CLI on macOS, Linux, or Windows. Install the `neetoinvoice` binary with the command for your platform, then [verify it](#verify-the-installation). ```bash macOS theme={"system"} brew trust neetozone/tap brew install neetozone/tap/neetoinvoice ``` ```bash Linux theme={"system"} curl -fsSL https://neetoinvoice.com/cli/install.sh | sh ``` ```powershell Windows theme={"system"} irm https://neetoinvoice.com/cli/install.ps1 | iex ``` The shell and Windows installers download the latest release for your architecture (`amd64` or `arm64`), extract it, and add `neetoinvoice` to your `PATH`. ## Other install methods ```bash theme={"system"} curl -fsSL https://neetoinvoice.com/cli/install.sh | sh ``` Installs to `/usr/local/bin` and may prompt for `sudo`. To update a Homebrew installation, run `brew upgrade neetoinvoice`. ```cmd theme={"system"} curl -fsSL https://neetoinvoice.com/cli/install.cmd -o install.cmd && install.cmd ``` Extracts to `%LOCALAPPDATA%\Programs\neetoinvoice` and adds it to your user `PATH`. This is equivalent to the PowerShell method. ## Verify the installation Restart your terminal, then run: ```bash theme={"system"} neetoinvoice --help ``` You should see the list of available commands. To check the installed version: ```bash theme={"system"} neetoinvoice version ``` ## Upgrade ```bash theme={"system"} neetoinvoice update ``` The command detects how the CLI was installed and runs the matching upgrade: `brew update && brew upgrade neetozone/tap/neetoinvoice` for a Homebrew install, the shell installer for other macOS and Linux installs, and the PowerShell installer on Windows. It prints the command it runs and exits non-zero if that command fails. You can also run the install command for your platform again. See [`neetoinvoice update`](/cli-reference/utility#update). After an upgrade, re-run `neetoinvoice completion ` and any `neetoinvoice setup` command you use so their files match the new version. Next, [sign in](/cli/authentication) to a workspace and run `neetoinvoice doctor` to confirm the CLI can reach NeetoInvoice. # NeetoInvoice CLI Source: https://apidocs.neetoinvoice.com/cli/introduction Manage clients, projects, time entries, invoices, and more from your terminal. The **NeetoInvoice CLI** (`neetoinvoice`) lets you manage NeetoInvoice from your terminal. It covers the [v2 REST API](/api/introduction): list and create clients, log time entries, generate invoices, run PTO and payroll reports, and automate bulk changes. It is designed for people comfortable with a terminal or HTTP. You do not need to be a developer: run `neetoinvoice setup` to connect an AI assistant such as Claude or Cursor, then describe the task in plain language. ## Why use the CLI? Create clients, log time entries, and generate invoices from shell scripts and cron jobs. Pull time entries or timesheet summaries, pipe them to `jq`, and create one-off reports without leaving your shell. Page through thousands of time entries in one loop, update them unattended, and switch workspaces with a single flag. Use token-efficient `--toon` output and one-command setup for Claude, Cursor, Copilot, and more. ## CLI vs MCP: which should I use? NeetoInvoice's [MCP server](/mcp/introduction) reaches the same resources the CLI does - clients, projects, time entries, invoices, team members, and the rest. Neither one can do more than the other, so choose on how the work reaches NeetoInvoice. ### Reach for the CLI when * **No AI assistant should be in the loop.** A cron entry or a CI step runs `neetoinvoice` with nothing but the binary and the workspace you already signed in to - no assistant open, no model account, no tokens spent per run. Over MCP, something with model access has to be running before any call happens at all. * **The output feeds another program.** `--quiet` prints the bare invoice id for the next command; `--json` returns records plus pagination for `jq`, a spreadsheet, or your own script. An assistant replies in prose you would have to copy out by hand. * **You are working through thousands of records.** Over MCP every page is a separate tool call, and a list that long crowds out the assistant's context. The CLI pages on your terms instead: `time-entries list --page-size 100` with `--json` returns `total_pages` and `total_records` alongside the records, so a loop knows how many pages are left and walks all of them unattended. Each page lands in a file or goes straight into `jq`, so nothing has to be held in memory and the size of the list stops mattering. * **You need the same run every time.** A `neetoinvoice` command is plain text you can save. Drop it into a runbook or a pull request and anyone can read exactly what it will do before it runs, then run it later and get the identical call. An assistant works from a prompt rather than a fixed command, so the same request can come out as a different set of calls on a different day. ### Reach for MCP instead when * **The details live in your chat, not in your head.** An email, a thread, or a pasted note turns into the time entry with no retyping. The CLI cannot see any of it. * **You have not decided the steps yet.** "Acme's July hours look wrong - have a look" means looking at what is there and choosing. A command can only carry out a decision you have already made. * **One request should cover several steps.** Find the client, pull its unbilled time entries, generate the invoice, and email it to the recipients, with no glue between commands. * **The person doing it does not use a terminal.** NeetoInvoice hosts the server, so there is nothing to install or keep updated. You can have both. Run [`neetoinvoice setup claude`](/cli/ai-assistants) and your AI assistant drives the CLI itself, so a plain-language request still ends in an exact command you can read, repeat, and paste into a script. ## What you need 1. Access to one or more NeetoInvoice workspaces. 2. Permission to manage the resources you want to work with (clients, projects, time entries, and so on). 3. The `neetoinvoice` binary. See [Installation](/cli/installation). Unlike the API, which authenticates with an `X-Api-Key` header, the CLI signs you in through your browser and stores credentials locally. See [Authentication](/cli/authentication). # Output formats Source: https://apidocs.neetoinvoice.com/cli/output-formats Pretty tables, JSON, quiet, and TOON - and when to use each. Every command can return one of four output formats. In an interactive terminal, pretty output is the default. Use the flags below for machine-readable output. | Format | Flag | Best for | | - | - | - | | Pretty | *(default in a terminal)* | Reading a result yourself. | | JSON | `--json` | Machine-readable payloads with pagination metadata. | | Quiet | `--quiet` | Piping an identifier into another command or `jq`. | | TOON | `--toon` | Feeding list/show output back to an LLM (fewer tokens than JSON). | If more than one is set, precedence is `--toon` > `--quiet` > `--json` > pretty. `--verbose` changes pretty output only, so it has no effect alongside the other three. ## Global flags These flags work on every command: | Flag | Description | | - | - | | `--json` | Output as JSON | | `--quiet` | Output raw data only (no envelope) | | `--toon` | Output in TOON format (token-optimized for AI agents) | | `--verbose` | Expand every field of a record instead of a table | | `--subdomain` | Override saved subdomain | `--subdomain` selects the signed-in workspace a command targets. See [Authentication](/cli/authentication). ## Pretty The default in a terminal: tables for lists and key-value pairs for a single record. It is intended for people, not scripts. A table shows at most seven columns. The CLI picks identifier and name fields first (`id`, `identifier`, `name`, `user_email`, `hours`, and similar), fills the remaining columns alphabetically, and keeps any URL fields as the last columns without truncating them. ```bash theme={"system"} neetoinvoice clients list ``` ## Verbose `--verbose` prints every field of every record instead of a table, one label per line, with nested objects and lists indented underneath. Use it when a table leaves out a field you need. ```bash theme={"system"} neetoinvoice clients list --verbose ``` ## JSON JSON wraps the resource body with breadcrumbs and, for list commands, pagination details: ```json theme={"system"} { "data": [ { "id": "f627c399-379d-4d07-a6f6-90b7c9470ac0", "identifier": "89d1b47d9f36af3c9ecf", "name": "Website Redesign", "status": "active" } ], "breadcrumbs": [{ "label": "Show", "command": "neetoinvoice projects show " }], "pagination": { "total_records": 1, "total_pages": 1, "current_page_number": 1, "page_size": 30 } } ``` For list commands, `data` is the array of records; the CLI removes the API response's resource key. For `show`, `create`, and `update`, `data` holds the API response body, such as `{ "client": { ... } }`. `breadcrumbs` is omitted when empty, and `pagination` appears only on list commands. The CLI automatically uses JSON when output is piped (a non-TTY); use `--json` to force it. ## Quiet `--quiet` returns only the `data` payload. For `create` and `update`, it prints the resource identifier when the response carries one, and the raw response otherwise, as `clients create` and `projects create` do; for `delete`, it prints `success`. This is useful in scripts: ```bash theme={"system"} neetoinvoice project-users create \ --project 89d1b47d9f36af3c9ecf --user-id 5b8e2c1a-7d34-4f0e-9a6b-3c2d1e0f9a8b \ --quiet # → prints the new project user id ``` ## TOON `--toon` encodes the same data as [TOON](https://github.com/alpkeskin/gotoon) (Token-Optimized Output Notation). It keeps the JSON shape while compressing whitespace and keys, typically using 30-60% fewer tokens. Use it when giving list or show output to an AI assistant. ```bash theme={"system"} neetoinvoice time-entries list --client 7c1f5e2a9b --project 89d1b47d9f36af3c9ecf --toon ``` ## Pagination List commands return results in pages. The flags below control paging, and the JSON envelope's `pagination` block shows your position in the result set. Only `time-entries list` and `team-members list` accept the flags. `clients list` and `projects list` report `pagination` too, but always return the first page. ### Pagination parameters The page of results to retrieve, starting from 1. The number of records to return per page (max 100). ### Example usage ```bash theme={"system"} neetoinvoice time-entries list --client 7c1f5e2a9b --project 89d1b47d9f36af3c9ecf --page 2 --page-size 50 ``` This returns the second page of time entries, with 50 records per page. ### Response structure For list commands the JSON envelope carries a `pagination` block alongside the data: ```json theme={"system"} { "pagination": { "total_records": 250, "total_pages": 5, "current_page_number": 2, "page_size": 50 } } ``` The total number of records across all pages. The total number of pages available. The page you are currently on. The number of records returned per page. ### Default behavior If you omit both flags, the CLI lets the server use its defaults: page 1 with 30 records. Either flag overrides the defaults; `--page-size` accepts up to 100. The `--page` flag on `team-members list` has no effect in this release; see [List team members](/cli-reference/team-members#list-team-members). ### Best practices * To retrieve every page, increment `--page` until `current_page_number == total_pages`. * Use `--json` or `--toon` in scripts when you need the `pagination` block. `--quiet` removes the envelope, so it does not include pagination metadata. * Check `total_records` before you begin to estimate the work involved. # Troubleshooting Source: https://apidocs.neetoinvoice.com/cli/troubleshooting Diagnose authentication and connectivity issues with neetoinvoice doctor. ## Run the doctor When something goes wrong, start with `neetoinvoice doctor`. It checks your authentication, API connection, and CLI version. ```bash theme={"system"} neetoinvoice doctor ``` When multiple workspaces are signed in, name the one to check: ```bash theme={"system"} neetoinvoice doctor --subdomain your-workspace ``` ## Common errors When a command fails, it prints an error message to standard error and exits with status 1. Usage errors such as an unknown flag or a missing argument add `Run 'neetoinvoice --help' for usage.` **Problem**: no workspace is signed in.
**Solution**: run [`neetoinvoice login --subdomain `](/cli/authentication).
**Problem**: more than one workspace is signed in, so the target is ambiguous.
**Solution**: add `--subdomain ` to the command. For `logout`, `--all` signs out of every workspace.
**Problem**: the `--subdomain` value does not match any signed-in workspace.
**Solution**: use one of the listed subdomains, or [sign in](/cli/authentication) to the new one.
**Problem**: `neetoinvoice login` could not find a workspace at `.neetoinvoice.com`.
**Solution**: use the first part of your workspace URL. For `https://spinkart.neetoinvoice.com`, enter `spinkart`.
**Problem**: the browser sign-in was not approved before the session expired. `NeetoInvoice CLI authentication timed out after 5 minutes. Please try again.` means the CLI stopped waiting.
**Solution**: run `neetoinvoice login` again and approve the sign-in in the browser. If the browser does not open, visit the URL the CLI prints.
**Problem**: the CLI could not reach the API.
**Solution**: check your network and run `neetoinvoice doctor`. If [`NEETOINVOICE_BASE_URL`](/cli/authentication#environment-variables) is set, confirm it points at a reachable server.
**Problem**: a required flag was omitted.
**Solution**: check the command's [reference page](/cli-reference/overview) or run `neetoinvoice --help` for the required flags. For commands that accept `--json-file`, a key in the file satisfies the matching flag.
**Problem**: the `--json-file` path does not exist, is not readable, or does not contain a JSON object.
**Solution**: check the path and validate the file, for example with `jq . `.
**Problem**: the server rejected the request. The CLI prints `API error (): `, one line per additional error, and a `Suggestion:` line for common statuses: 401 (sign in again), 403 (no permission), 404 (check the ID), 422 (check required fields with `--help`), and 429 (rate limited, wait and retry).
**Solution**: follow the suggestion. For 401, run `neetoinvoice login` to refresh the session.
**Problem**: `team-members update` was run with no change flags.
**Solution**: pass at least one of the listed flags.
**Problem**: the entry is on an invoice, and billed entries cannot be changed or deleted.
**Solution**: leave the entry as it is and adjust the invoice instead.
**Problem**: `neetoinvoice setup claude` requires Claude Code to have been run at least once.
**Solution**: install and open Claude Code, then run the command again.
## Permission errors The CLI acts as the signed-in user, not as the workspace, so commands are limited by what your role allows. Viewing other users' time entries, managing monthly PTO, and overriding autolock are each gated separately. For `API error (403)`, ask a workspace admin to adjust your role, or run the equivalent [REST API](/api/introduction) call with a workspace API key. ## Check the version ```bash theme={"system"} neetoinvoice version ``` Prints the CLI version, commit hash, and build date - useful when reporting an issue. To upgrade, run [`neetoinvoice update`](/cli-reference/utility#update). # Workspace subdomain Source: https://apidocs.neetoinvoice.com/cli/workspace-subdomain Find your workspace subdomain and tell the CLI which workspace to use. Every NeetoInvoice workspace has its own subdomain. It is the part of your workspace URL before `neetoinvoice.com`. For `https://spinkart.neetoinvoice.com`, the subdomain is `spinkart`. The CLI uses the subdomain to know which workspace to sign in to and which workspace a command works on. ## Find your subdomain Sign in to NeetoInvoice in your browser and look at the address bar. For `https://green-earth.neetoinvoice.com`, the subdomain is `green-earth`. ## Sign in with it Pass the subdomain to `login`: ```bash theme={"system"} neetoinvoice login --subdomain green-earth ``` If you omit `--subdomain`, the CLI asks for it. ## Pick a workspace for a command With one signed-in workspace, the CLI uses it and `--subdomain` stays optional. When you sign in to more than one, add `--subdomain` to every command that talks to the API: ```bash theme={"system"} neetoinvoice clients list --subdomain green-earth ``` See [Authentication](/cli/authentication) for signing in to several workspaces. # Authentication Source: https://apidocs.neetoinvoice.com/mcp/authentication Connect as yourself with OAuth, or as the whole workspace with an API key. The MCP server accepts two kinds of credentials. The one you pick decides **what the assistant can see**. | | OAuth | API key | | - | - | - | | Scope | The person who approved it | The whole workspace | | Identity | Tied to a NeetoInvoice user | Tied to nobody | | Set up by | Signing in to NeetoInvoice from the assistant | Pasting a key into a config file | | Used by | Every client except Antigravity | Every client except Claude and ChatGPT | | Reaches several workspaces | Yes, tick them while approving | No, one key is one workspace | | Revoked by | Removing the connector | Revoking the key in workspace settings | In Claude Code, Codex, Cursor, Gemini CLI, VS Code, and Windsurf, leave the key out of the config to sign in with OAuth. Put the key in to use the API key. Both expose the same [tools](/mcp/tools). ## OAuth, scoped to you The assistant acts as the person who approved the connection. Lists and searches show only what that person can see. A client or project they cannot open is refused. Use OAuth when a person drives the assistant. For the steps, see [Connect agent](/mcp/connect#sign-in-with-your-neetoinvoice-account). | Detail | Value | | - | - | | Metadata | `https://connect.neetoinvoice.com/.well-known/oauth-authorization-server` | | Grant types | `authorization_code` and `refresh_token`, with PKCE (`S256`) required | | Scopes | `read`, `write`, `delete`, `offline_access` | | Client registration | Dynamic, per [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591), at `https://connect.neetoinvoice.com/mcp/oauth/register`. Loopback redirect URIs are accepted. | | Refresh | Refresh tokens are issued, so you stay signed in | | Revoke | Remove the connector from your assistant | ### What you approve | Scope | Shown as | What it means | Always granted | | - | - | - | - | | `read` | **Read** | See everything in the connected workspaces. | Yes | | `offline_access` | **Stay connected** | Keep working without asking you to sign in again. | Yes | | `write` | **Create and update** | Add new items and change existing ones. | No | | `delete` | **Delete** | Permanently delete items. This cannot be undone. | No | NeetoInvoice 'Authorize access' screen showing the workspace and signed-in email, a 'What this connection can do' list with Read and Stay connected always granted and Create and update and Delete as tickable boxes, a 'Workspaces to connect' list, and Cancel and Authorize buttons If you leave a scope unticked, a tool that needs it is refused with a message that names the scope. For example, a read-only connection can list time entries and check unbilled totals, but cannot log time, generate an invoice, or delete anything. One OAuth connection can reach several workspaces: the one you entered, plus any you tick under **Additional workspaces to connect**. Name the workspace in your prompt, or ask the assistant to list the workspaces it can reach. Every tool takes an optional `workspace` argument for this. ## API key, scoped to the workspace An API key is not tied to a person. Every tool call reaches the whole workspace, and role checks do not run. Use a key for automation that must see every time entry. Do not use one on a machine where the person should see only their own. The key is the same one the [REST API](/api/authentication) uses. Put it in the server entry of the assistant's config file: ```json theme={"system"} "headers": { "Authorization": "Bearer YOUR_API_KEY" } ``` For the full config of each client, see [Connect agent](/mcp/connect#use-an-api-key). [Learn how to generate your API key.](https://help.neetoinvoice.com/articles/api-keys) A key belongs to one workspace. To reach two workspaces, add the server twice, with a different key and a different server name in each entry. An API key gives access to every client, project, and time entry in the workspace, including every user's time entries and the payroll and PTO reports. Treat it like a password: keep it out of shared config files and commits, and revoke it if it leaks. ## How the three interfaces authenticate | Interface | Credential | Scope | Where it goes | | - | - | - | - | | [REST API](/api/authentication) | API key | Workspace | `X-Api-Key` header on each request. | | [CLI](/cli/authentication) | Browser sign-in, stored per workspace | The signed-in user | `~/.config/neetoinvoice/auth.json`. No API key involved. | | MCP | OAuth, or an API key | The approving user, or the workspace | Browser approval, or an `Authorization: Bearer` header in the assistant's config file. | # Connect agent Source: https://apidocs.neetoinvoice.com/mcp/connect Step-by-step setup for Claude, ChatGPT, and other AI agents. ## Sign in with your NeetoInvoice account 1. Open **[Customize > Connectors](https://claude.ai/customize/connectors)**, click **Add**, then click **Add custom connector**. Menu under the Add button in Claude's Connectors settings, with the single item Add custom connector 2. Enter the name NeetoInvoice and paste the server URL. ``` https://connect.neetoinvoice.com/mcp/messages ``` Claude's Add custom connector dialog with the name NeetoInvoice and the server URL https://connect.neetoinvoice.com/mcp/messages filled in, and a Continue button 3. Click **Continue** and sign in to NeetoInvoice. See [What the sign-in looks like](#what-the-sign-in-looks-like). NeetoInvoice then works in claude.ai, the Claude desktop app, Claude mobile, and Cowork. On a Team plan, an Owner must first add the same server URL under **[Organization settings > Connectors](https://claude.ai/admin-settings/connectors)**. Then connect it from your own Connectors list. To disconnect, open **[Customize > Connectors](https://claude.ai/customize/connectors)** and remove NeetoInvoice. 1. Go to [chatgpt.com](https://chatgpt.com) and open **Settings → Security and login**. 2. Turn on **Developer mode**. ChatGPT's Developer mode setting, tagged Elevated risk, with its toggle switched on If you do not see **Developer mode**, your ChatGPT workspace admin has turned it off. Ask them to allow it. 3. Go to [chatgpt.com/plugins](https://chatgpt.com/plugins) and click the **plus** button. 4. In **New Plugin**, enter the name NeetoInvoice, set **Connection** to **Server URL**, and paste: ``` https://connect.neetoinvoice.com/mcp/messages ``` 5. Leave **Authentication** on **OAuth**. 6. Tick **I understand and want to continue**, then click **Create**. 7. Sign in to NeetoInvoice. See [What the sign-in looks like](#what-the-sign-in-looks-like). 1. Add the server: ```bash theme={"system"} claude mcp add --transport http neetoinvoice https://connect.neetoinvoice.com/mcp/messages ``` 2. Start Claude Code and run `/mcp`. 3. Pick **neetoinvoice** and sign in to NeetoInvoice in the browser. 1. Add the server to `~/.cursor/mcp.json`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "url": "https://connect.neetoinvoice.com/mcp/messages" } } } ``` 2. Restart Cursor. 3. Sign in to NeetoInvoice when Cursor asks. 1. Add the server to `~/.gemini/settings.json`. Use `httpUrl`, not `url`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "httpUrl": "https://connect.neetoinvoice.com/mcp/messages" } } } ``` 2. Start Gemini CLI and sign in to NeetoInvoice when it asks. 1. Add the server to `~/.codex/config.toml`: ```toml theme={"system"} [mcp_servers.neetoinvoice] url = "https://connect.neetoinvoice.com/mcp/messages" ``` 2. Run this command and sign in to NeetoInvoice in the browser: ```bash theme={"system"} codex mcp login neetoinvoice ``` You need VS Code 1.99 or later, with GitHub Copilot in **Agent** mode. 1. Create `.vscode/mcp.json` in your workspace. Use `servers`, not `mcpServers`: ```json theme={"system"} { "servers": { "neetoinvoice": { "type": "http", "url": "https://connect.neetoinvoice.com/mcp/messages" } } } ``` 2. Sign in to NeetoInvoice when VS Code asks. 1. Add the server to `~/.codeium/windsurf/mcp_config.json`. Use `serverUrl`, not `url`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "serverUrl": "https://connect.neetoinvoice.com/mcp/messages" } } } ``` 2. Turn on the server under **Settings → Cascade → MCP Servers**. 3. Sign in to NeetoInvoice when Windsurf asks. ### What the sign-in looks like Enter your workspace subdomain. For `acme.neetoinvoice.com`, enter `acme`. You can also paste the workspace URL. The **Find your workspace subdomain** link on this screen opens the [Workspace subdomain](/mcp/workspace-subdomain) page. NeetoInvoice dialog headed 'Connect your workspace' with a field for the workspace subdomain, a .neetoinvoice.com suffix, and a Continue button Sign in to that workspace, if you are not signed in already. **Read** and **Stay connected** are always on. Tick **Create and update** and **Delete** only if the assistant needs them. One connection can reach more than one workspace at the same time. The workspace you entered is always connected. If your email belongs to other workspaces, tick any you also want under **Additional workspaces to connect**. The permissions you approve apply to all of them. NeetoInvoice 'Authorize access' screen showing the workspace and signed-in email, a 'What this connection can do' list with Read and Stay connected always granted and Create and update and Delete as tickable boxes, a 'Workspaces to connect' list with three workspaces, and Cancel and Authorize buttons Click **Authorize**. To add a workspace or a permission later, sign in again and tick it. ## Use an API key An API key reaches the whole workspace, not only what you can see. Use it for automation. See [Authentication](/mcp/authentication). 1. Add the server to `~/.claude.json`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "type": "http", "url": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` 2. Restart Claude Code. 1. Add the server to `~/.cursor/mcp.json`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "type": "http", "url": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` 2. Restart Cursor. 1. Add the server to `~/.gemini/settings.json`. Use `httpUrl`, not `url`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "httpUrl": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` 2. Restart Gemini CLI. 1. Add the server to `~/.codex/config.toml`: ```toml theme={"system"} [mcp_servers.neetoinvoice] url = "https://connect.neetoinvoice.com/mcp/messages" bearer_token_env_var = "NEETOINVOICE_API_KEY" ``` 2. Set `NEETOINVOICE_API_KEY` to your API key in the shell where you run Codex. You need VS Code 1.99 or later, with GitHub Copilot in **Agent** mode. 1. Create `.vscode/mcp.json` in your workspace: ```json theme={"system"} { "inputs": [ { "type": "promptString", "id": "neetoinvoice-api-key", "description": "NeetoInvoice API key", "password": true } ], "servers": { "neetoinvoice": { "type": "http", "url": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer ${input:neetoinvoice-api-key}" } } } } ``` 2. Paste your API key when VS Code asks. This file lives in your project. Do not paste the key into the file itself, or it can end up in a commit. 1. Add the server to `~/.codeium/windsurf/mcp_config.json`. Use `serverUrl`, not `url`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "serverUrl": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` 2. Turn on the server under **Settings → Cascade → MCP Servers**. 1. Open **Settings → Customizations → Open MCP Config**. 2. Add the server to `mcp_config.json`. Use `serverUrl`, not `url`: ```json theme={"system"} { "mcpServers": { "neetoinvoice": { "serverUrl": "https://connect.neetoinvoice.com/mcp/messages", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` 3. Reload Antigravity. Replace `YOUR_API_KEY` with a key from your workspace. [Learn how to generate your API key.](https://help.neetoinvoice.com/articles/api-keys) ## Confirm the connection Ask the assistant *"List my NeetoInvoice workspaces."* If it answers with your workspaces, the connection works. For more prompts, see [Examples](/mcp/examples). If it does not work, see [Troubleshooting](/mcp/troubleshooting). # Examples Source: https://apidocs.neetoinvoice.com/mcp/examples Prompts to try once your assistant is connected to NeetoInvoice. Once [connected](/mcp/connect), ask your assistant in plain language. It picks the right [tools](/mcp/tools), so you do not need to know any tool names. Try prompts like these: ## Clients and projects > Get details for client Acme Corp. > Create a Website Redesign project for Acme Corp with tasks Design and Development, > billed at an hourly project rate of 120 USD. > Which projects is [oliver@example.com](mailto:oliver@example.com) on? An assistant answering the first prompt typically calls `ListClients` to resolve the name to an ID, then `GetClient` for the details. You do not need to supply IDs yourself. ## Time tracking > Log 2.5 hours for me on the Website Redesign design task for yesterday. > Update my time entry from July 14 to 3 hours. > Show unbilled time entries on Website Redesign for July. ## Invoicing > Generate an invoice for Acme Corp from all unbilled time entries in July, > numbered INV-EXT-001, due in 30 days. > Add [accounts@example.com](mailto:accounts@example.com) as an invoice recipient for Acme Corp. > Email the last invoice to Acme Corp's recipients. ## Reports, PTO, and team > Show the payroll summary for July 2026. > Who is missing timesheet entries this month? > Show the monthly PTO report for July 2026. > List all active team members. > Invite [sam@example.com](mailto:sam@example.com) to the workspace as a standard user. ## Work across workspaces Every tool accepts an optional `workspace` argument. When the connection reaches more than one workspace, name the one you mean in your prompt: > Which NeetoInvoice workspaces can you see? ## When a prompt does not work Over OAuth the assistant acts as you, so it only sees what your role permits. With an API key it acts as the workspace and sees everything. If a prompt returns less than you expected, check which credential the connection uses. See [Authentication](/mcp/authentication). Ask the assistant to confirm before it generates an invoice, deletes a time entry, or deactivates a team member. MCP actions affect your live workspace. # NeetoInvoice MCP Source: https://apidocs.neetoinvoice.com/mcp/introduction Manage your NeetoInvoice billing and time tracking from an AI assistant in plain language. The NeetoInvoice **MCP server** lets your AI assistant manage billing and time tracking from plain-language requests. Ask it to log hours, create an invoice, list unbilled time entries, or generate a payroll report, and it works with your NeetoInvoice workspace for you. [MCP](https://modelcontextprotocol.io) (Model Context Protocol) is an open standard that connects AI assistants to tools such as NeetoInvoice. You describe the task; the assistant uses the right tool. ## What you can do Log hours, pull unbilled time entries, and check timesheets. Create invoices from unbilled entries and send them to recipients. List, invite, update, and deactivate team members. Ask your assistant to bill a client for the month, chase down missing timesheets, or flag a PTO conflict for you. ## MCP vs CLI: which should I use? NeetoInvoice's [CLI](/cli/introduction) reaches the same resources MCP does - clients, recipients, projects, project users, time entries, invoices, PTO, and the rest. Neither one can do more than the other, so choose on how the work reaches NeetoInvoice. ### Reach for MCP when * **The details live in your chat, not in your head.** A client writes "we approved 6 hours of design on the 14th" and your assistant turns that message into the time entry. The same entry from the shell needs the client, project, and task ids, the date, and the hours all typed out, and the CLI cannot see the message at all. * **You have not decided the steps yet.** "Acme's July hours look wrong - have a look" means reading what is there and choosing what to do about it. A command can only carry out a decision you have already made. * **One request should cover several steps.** "Bill Acme for July" finds the client, pulls its unbilled entries for the month, bills them, and emails the invoice to the recipients, with the ids carried from one call to the next. The same invoice from the shell needs a JSON file listing every entry with its ids, hours, and rate, plus a total you worked out yourself. * **The person doing it does not use a terminal.** The office manager chasing this week's missing timesheets installs nothing: NeetoInvoice hosts the server, and their assistant is already open. ### Reach for the CLI instead when * **No AI assistant should be in the loop.** A cron entry or a CI step runs `neetoinvoice reports payroll-summary --month 8 --year 2026` with nothing but the binary and a workspace it is already signed in to - no assistant open, no model account, no tokens spent per run. Every MCP call needs something with model access running. * **The output feeds another program.** The CLI prints a bare identifier or raw JSON for `jq`, a spreadsheet, or your own script. Here you get prose you would have to copy out by hand. * **You are working through thousands of records.** Here every page is a separate tool call, and a year of time entries crowds out the assistant's context. The CLI returns `total_pages` next to the entries, so a shell loop walks every page unattended and writes each one to a file or into `jq` - the size of the project's history stops mattering. * **The run has to be repeatable and reviewable.** Month-end close is the same commands in the same order every month: the timesheet summary, then the payroll summary, then the invoices. A command is the artifact: it records exactly what ran and repeats identically. Ask twice here and the assistant may take a different route. You can have both. Run [`neetoinvoice setup claude`](/cli/ai-assistants) and the same assistant drives the CLI for you, so a plain-language request still ends in an exact command you can read, repeat, and paste into a script. Ask your assistant to show you what it plans to do before it generates an invoice, deletes a time entry, or deactivates a team member. These tools act on your live workspace. ## What you need * An AI assistant that supports MCP, such as Claude, ChatGPT, Claude Code, Codex, Cursor, Gemini CLI, VS Code with GitHub Copilot, Windsurf, or Antigravity. * A NeetoInvoice account. You need an API key only if the assistant must reach the whole workspace, or if you use Antigravity. See [Authentication](/mcp/authentication). [Connect your assistant](/mcp/connect) to get started. # MCP server Source: https://apidocs.neetoinvoice.com/mcp/server The NeetoInvoice MCP server endpoint, transport, and the sign-in options each agent supports. NeetoInvoice hosts the MCP server. There is nothing to install. | | | | - | - | | **Endpoint** | `https://connect.neetoinvoice.com/mcp/messages` | | **Transport** | HTTP | | **Authentication** | OAuth, or `Authorization: Bearer YOUR_API_KEY` | ## How each agent connects | Agent | Sign in with NeetoInvoice | API key | | - | - | - | | Claude, ChatGPT | Yes | No | | Claude Code, Codex, Cursor, Gemini CLI, VS Code, Windsurf | Yes | Yes | | Antigravity | Not documented | Yes | When you sign in, the assistant sees only what you can see. An API key reaches the whole workspace. See [Authentication](/mcp/authentication). For the setup steps, see [Connect agent](/mcp/connect). # Tools Source: https://apidocs.neetoinvoice.com/mcp/tools Every tool the NeetoInvoice MCP server exposes, grouped by resource. You do not need these names to use the server. Ask in plain language and the assistant picks the right tool. The list is here for when you want to know exactly what a connection can do. Most tools match a [REST API](/api/introduction) endpoint and link to its reference. Every tool takes an optional `workspace` argument, the subdomain of a connected workspace. Left out, it runs against the workspace the connection was set up with. `ListWorkspaces` reports the values you can pass. What a tool returns depends on the credential. Over [OAuth](/mcp/authentication#oauth-scoped-to-you), lists come back filtered to the permissions of the person who approved the connection, and a record they cannot open is refused rather than returned; an [API key](/mcp/authentication#api-key-scoped-to-the-workspace) reaches the whole workspace. A tool that creates, updates, or deletes is also refused when the connection was not granted the **Create and update** or **Delete** permission. ## Workspaces | Tool | What it does | | - | - | | `ListWorkspaces` | Lists the workspaces this connection can reach. | `ListWorkspaces` has no REST endpoint, which is why it is not linked. ## Clients Clients are the billed entities that own projects and invoice recipients. | Tool | What it does | | - | - | | `ListClients` | Lists the organization's clients. Used to resolve a name to an ID. | | [`GetClient`](/api/clients/get) | Returns a client's details and its invoice recipients. | | [`CreateClient`](/api/clients/create) | Creates a client. | | [`UpdateClient`](/api/clients/update) | Updates a client. Only the provided fields change. | ## Recipients Recipients receive a client's invoices. | Tool | What it does | | - | - | | [`CreateRecipient`](/api/recipients/create) | Adds an invoice recipient to a client. | | [`UpdateRecipient`](/api/recipients/update) | Updates a recipient. Only the provided fields change. | | [`DeleteRecipient`](/api/recipients/delete) | Removes a recipient from a client. | ## Projects | Tool | What it does | | - | - | | `ListProjects` | Lists projects, or finds which projects a user is on. | | [`GetProject`](/api/projects/get) | Returns a project's details, including its client, tasks, and project users. | | [`CreateProject`](/api/projects/create) | Creates a project under a client. A project must have at least one task. | | [`UpdateProject`](/api/projects/update) | Updates a project. Only the provided fields change. | ## Project users | Tool | What it does | | - | - | | [`ListProjectUsers`](/api/project-users/list) | Lists the active users on a project. | | [`AddProjectUser`](/api/project-users/add) | Adds an organization user to a project so they can log time to it. | | [`UpdateProjectUser`](/api/project-users/update) | Updates a project user's role or hourly rate. | | [`RemoveProjectUser`](/api/project-users/remove) | Removes a user from a project. | ## Time entries | Tool | What it does | | - | - | | [`ListTimeEntries`](/api/time-entry/list) | Lists a project's unbilled time entries, optionally for one user or one task. | | [`CreateTimeEntry`](/api/time-entry/create) | Logs a time entry for a user against a project's task. | | `UpdateTimeEntry` | Updates an entry's hours, date, or notes. Billed entries cannot be changed. | | `DeleteTimeEntry` | Deletes a time entry. Billed entries cannot be deleted. | ## Invoices | Tool | What it does | | - | - | | `ListInvoices` | Lists the organization's invoices, optionally filtered by client, status, or issue date range. | | [`CreateInvoice`](/api/invoices/create) | Generates an invoice for a client from unbilled time entries or services. | | `SendInvoice` | Emails an invoice to the client's recipients. Every current recipient of the client receives it unless the call names some of them by recipient ID; an address that is not one of the client's recipients cannot be given. | An invoice can be sent once the `status` that `ListInvoices` reports is `generated`, `pending_payment`, `paid` or `written_off`; one that is still `generating` is refused. Sending the same invoice again delivers it again. ## Team members | Tool | What it does | | - | - | | [`ListTeamMembers`](/api/team-members/list) | Lists the organization's active team members. | | `GetTeamMember` | Returns a team member's details. | | [`CreateTeamMembers`](/api/team-members/add) | Invites one or more team members by email. | | [`UpdateTeamMember`](/api/team-members/update) | Updates a team member's profile or organization role. | | [`DeleteTeamMember`](/api/team-members/remove) | Deactivates a team member, removing their access. | ## PTO | Tool | What it does | | - | - | | `ListMonthlyPto` | Reads the monthly PTO report: per user, PTO earned, used, and net balance. | | `UpdatePtoEarned` | Sets PTO earned in hours for one or more users for a month. | ## Reports | Tool | What it does | | - | - | | `PayrollSummary` | Reports, per user, working days and loss-of-pay days for a month. | | `TimesheetSummary` | Reports hours per user, per day, and per project for a date range. | | `ListMissingTimesheetEntries` | Lists a user's working days in a range with no timesheet entry. | PTO and report tools have no REST API reference pages yet. They are also available from the command line: see [monthly-ptos](/cli-reference/monthly-ptos) and [reports](/cli-reference/reports). # Troubleshooting Source: https://apidocs.neetoinvoice.com/mcp/troubleshooting What to check when an assistant cannot reach NeetoInvoice. **Restart the client first.** Every client reads its MCP config at startup, and Cursor can also reload the window from the command palette. Then check the items for your kind of client. On Claude or ChatGPT, confirm that you added the connector and finished the sign-in. In ChatGPT, the plugin is created only after you tick **I understand and want to continue**. On Claude Code, Cursor, Gemini CLI, Codex, VS Code, Windsurf, or Antigravity, which read a config file: 1. **Check the config key.** Claude Code, Cursor, Gemini CLI, Windsurf, and Antigravity nest servers under `mcpServers`. VS Code uses `servers`, and Codex uses a `[mcp_servers.]` section in TOML. A server under the wrong key is ignored silently. 2. **Check the URL key.** Windsurf and Antigravity expect `serverUrl`, and Gemini CLI expects `httpUrl` because it reserves `url` for SSE. Claude Code, Codex, Cursor, and VS Code expect `url`. 3. **Check the endpoint.** It is `https://connect.neetoinvoice.com/mcp/messages`, with no trailing slash. 4. **Check the syntax.** In JSON a trailing comma or an unclosed brace makes the whole file unreadable, which takes out any other servers too. Full snippets for each client are on [Connect agent](/mcp/connect). Go to [chatgpt.com](https://chatgpt.com) and open **Settings → Security and login**. **Developer mode** is in that section. If it is not there, your ChatGPT workspace admin has turned it off. Ask them to allow it, then follow the ChatGPT steps in [Connect agent](/mcp/connect). On an API key connection, the `Authorization` header must read `Bearer YOUR_API_KEY`, with the word `Bearer` and a single space before the key. Confirm the key has not been revoked, and that it belongs to the workspace you expect: a key generated in one workspace does not work in another. Generate a new key from [workspace settings](https://help.neetoinvoice.com/articles/api-keys) if you are unsure. On an OAuth connection there is no key to check. Remove the connector and add it again to run the sign-in from the start. A client that finds a credential in its config never starts the OAuth flow. Remove the `headers` block, or the `bearer_token_env_var` line in Codex, and restart the client. It then answers the server's 401 by opening the sign-in. The opposite case: the credential is missing, so the client falls back to OAuth. Add the `headers` block with `"Authorization": "Bearer YOUR_API_KEY"`, or set `bearer_token_env_var = "NEETOINVOICE_API_KEY"` in Codex and export that variable, then restart the client. Codex takes the *name* of an environment variable, not the key itself. The first screen needs a workspace subdomain or a workspace URL, not an email address. For `acme.neetoinvoice.com`, enter `acme`. See [Workspace subdomain](/mcp/workspace-subdomain). That is the scoping working as intended. An OAuth connection acts as the person who approved it, so lists and searches come back filtered to your permissions, and asking for a specific client or project you cannot open is refused rather than answered. If the assistant genuinely needs to reach everything in the workspace, that is what an API key connection is for. See [Authentication](/mcp/authentication). The approval screen has two optional permissions, **Create and update** and **Delete**, and a tool that needs one you left unticked is refused with a message naming it. Nothing is broken and nothing half happened. To grant it, remove the connector and add it again, ticking the permission this time. See [Authentication](/mcp/authentication#what-you-approve). An API key connection carries every permission, so this cannot happen on one. An OAuth connection covers the workspace you entered and any additional workspaces you ticked while approving it. Name the workspace in your prompt, or ask the assistant to list the workspaces it can reach. To add another one, run the sign-in again and tick it under **Additional workspaces to connect**. An API key belongs to exactly one workspace, so a key connection reaching the wrong one means the wrong key. Add the server a second time, with the other key and a different server name. MCP needs VS Code 1.99 or later with GitHub Copilot running in **Agent** mode. It is not available in Ask or Edit mode. Check the version, switch Copilot to Agent mode, and confirm that `.vscode/mcp.json` is in the workspace you have open. On an API key connection, VS Code prompts for the key the first time the server is used, so answer that prompt. Enable the server after saving the config: **Settings → Cascade → MCP Servers** in Windsurf, **Settings → Customizations** in Antigravity. Windsurf also caps the total number of tools at 100 across every connected server, so turn off servers you are not using and reload. Open **[Customize > Connectors](https://claude.ai/customize/connectors)**, remove NeetoInvoice, and add it again as a custom connector. See [Connect agent](/mcp/connect). On a Team plan, an Owner must first add the server URL under **[Organization settings > Connectors](https://claude.ai/admin-settings/connectors)**. The server publishes its OAuth metadata without any credential, so one request tells you whether the problem is on the server or in your client: ```bash theme={"system"} curl -s https://connect.neetoinvoice.com/.well-known/oauth-authorization-server ``` A JSON document whose `issuer` is `https://connect.neetoinvoice.com` means the host is reachable and answering, so look at the client's setup next. It does not prove that every tool call succeeds. No answer, or an error page, means the server cannot be reached from your network. Try again in a few minutes, and if it persists, tell us. ## Still stuck Reach us through the [help center](https://help.neetoinvoice.com), or at [support@neetoinvoice.com](mailto:support@neetoinvoice.com). Tell us which client you are using and what the assistant reports when it tries a NeetoInvoice tool. # Workspace subdomain Source: https://apidocs.neetoinvoice.com/mcp/workspace-subdomain Find your workspace subdomain and use it to connect an assistant. Every NeetoInvoice workspace has its own subdomain. It is the part of your workspace URL before `neetoinvoice.com`. For `https://spinkart.neetoinvoice.com`, the subdomain is `spinkart`. The MCP server URL is the same for every workspace, `https://connect.neetoinvoice.com/mcp/messages`. The subdomain is how you tell NeetoInvoice which workspace the assistant can reach. ## Find your subdomain Sign in to NeetoInvoice in your browser and look at the address bar. For `https://green-earth.neetoinvoice.com`, the subdomain is `green-earth`. ## Where you use it * **OAuth.** The first sign-in screen asks you to connect your workspace. Enter the subdomain, such as `green-earth`. You can also paste the full workspace URL, and only the subdomain is kept. An email address does not work. The screen links to this page as **Find your workspace subdomain**. * **API key.** Create the key in the workspace you want the assistant to reach. One key reaches one workspace. See [Authentication](/mcp/authentication) for both routes.