https://api.salesgoat.appAPI Version: v1
Authentication: Bearer Token (Firebase ID Token)
Content-Type: application/json
Multi-Tenant: All endpoints are scoped to tenant ID for data isolation
Field Naming: All fields use snake_case convention
Date Fields: Enhanced support for multiple formats (YYYY-MM-DD, ISO strings, Firestore Timestamps, Unix timestamps), stored as Firestore Timestamps
ID Generation: Sequential 6-digit zero-padded IDs (000001, 000002, etc.) with optional custom IDs
Overview
The SalesGOAT API provides comprehensive endpoints for managing teams, users, projects, paystubs, and related data within a multi-tenant architecture. All operations are scoped to the authenticated user’s tenant, ensuring complete data isolation and security.
Field Validation & Data Types
All API endpoints enforce strict field validation:
- Field Naming: All fields must use snake_case convention (e.g.,
user_id,created_at) - Date Fields: Input as YYYY-MM-DD strings, stored as Firestore Timestamps
- ID Fields: Optional custom IDs or auto-generated sequential 6-digit zero-padded IDs
- Required Fields: Must be present and non-empty
- Field Types: Strictly validated (string, number, boolean, array)
- Enum Values: Validated against predefined options
- Unknown Fields: Rejected with 400 error to prevent data corruption
Enhanced Date Handling
The API provides flexible date input support while maintaining data consistency. All date fields are automatically converted to Firestore Timestamps for optimal database storage and querying.
Supported Date Formats
| Format | Example | Description |
|---|---|---|
| YYYY-MM-DD | "2024-12-31" |
Simple date format (most common) |
| ISO String | "2024-12-31T14:30:00.000Z" |
Full ISO 8601 with time |
| Firestore Timestamp | {"_seconds": 1735689600, "_nanoseconds": 0} |
Firestore Timestamp object |
| Unix Timestamp | 1735689600 |
Unix timestamp in seconds |
| Unix Timestamp (ms) | 1735689600000 |
Unix timestamp in milliseconds |
Date Field Examples
{
“closed_date”: “2024-12-31”, // Simple format
“date_paid”: “2024-12-31T14:30:00.000Z”, // ISO string
“install_date”: {“_seconds”: 1735689600, “_nanoseconds”: 0}, // Firestore Timestamp
“m2_date”: 1735689600 // Unix timestamp
}
Authentication
The API uses a secure token system with clear separation of concerns.
Token Types
- API User Tokens: Long-lived tokens for API access (no expiration)
- Session Tokens: Short-lived tokens for general API access (1 hour expiration)
Token System
Generate API User Token
POST Generate API User Token
Generate a long-lived API user token for API access. This token can only be used to generate session tokens.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | API user email address | |
| password | string | Yes* | API user password (required if googleIdToken not provided) |
| tenantId | string | Yes | Tenant ID |
| googleIdToken | string | Yes* | Google OAuth ID token (required if password not provided) |
Response
200 OK
“success”: true,
“message”: “API user token generated successfully”,
“data”: {
“customToken”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“userId”: “user-id”,
“tenantId”: “tenant-id”,
“expiresIn”: null,
“tokenType”: “api_user”
},
“timestamp”: “2025-10-14T22:17:27.454Z”
}
Example Request
-H “Content-Type: application/json” \
-d ‘{
“email”: “admin@example.com”,
“password”: “your-password”,
“tenantId”: “your-tenant-id”
}’
Generate Session Token
POST Generate Session Token
Generate a short-lived session token using an API user token. This token can be used for all API operations.
Headers
Content-Type: application/json
Request Body
Response
200 OK
“success”: true,
“message”: “Session token generated successfully”,
“data”: {
“customToken”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“userId”: “user-id”,
“tenantId”: “tenant-id”,
“expiresIn”: 3600,
“tokenType”: “session”
},
“timestamp”: “2025-10-14T22:17:27.454Z”
}
Example Request
-H “Authorization: Bearer YOUR_API_USER_TOKEN” \
-H “Content-Type: application/json” \
-d ‘{}’
Refresh Token
POST Refresh Token
Refresh an existing token to get a new session token.
Headers
Content-Type: application/json
Response
200 OK
“success”: true,
“message”: “Token refreshed successfully”,
“data”: {
“customToken”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“userId”: “user-id”,
“tenantId”: “tenant-id”,
“expiresIn”: 3600
},
“timestamp”: “2025-10-14T22:17:27.454Z”
}
Revoke Token
POST Revoke Token
Revoke a token to invalidate it immediately.
Headers
Content-Type: application/json
Response
200 OK
“success”: true,
“message”: “Token has been revoked”,
“data”: {
“message”: “Token revoked successfully”
},
“timestamp”: “2025-10-14T22:17:27.454Z”
}
Using Tokens
Include the appropriate token in the Authorization header for all requests:
Token Restrictions
- API User Tokens: Can ONLY be used with
/api/v1/auth/session-tokenendpoint - Session Tokens: Required for all other API operations
- Expiration: Session tokens expire after 1 hour and must be refreshed
Error Responses
{
“error”: “Forbidden: API user tokens can only be used with /api/v1/auth/session-token endpoint”
}
// Expired token
{
“error”: “Unauthorized: Token has expired”
}
// Invalid token
{
“error”: “Unauthorized: Invalid token”
}
Health Check
GET
Health Check
Check the health status of the API service.
Response
200 OK
“success”: true,
“message”: “Success”,
“data”: {
“status”: “healthy”,
“environment”: “production”,
“projectId”: “reps-e6cf4”,
“timestamp”: “2025-10-10T19:24:56.419Z”
},
“timestamp”: “2025-10-10T19:24:56.419Z”
}
Teams API
GET
List Teams
Retrieve a list of all teams for the specified tenant.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of teams to return (default: 50) |
| offset | integer | No | Number of teams to skip (default: 0) |
| is_active | boolean | No | Filter by active status |
Response
200 OK
“success”: true,
“message”: “Teams retrieved successfully”,
“data”: [
{
“id”: “D4u5UDhoRLhoTxAO6O1u”,
“name”: “Sales Team Alpha”,
“is_active”: true,
“team_type”: “Office”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“parent_id”: null,
“created_by”: “s4qmQCYqXrVNsQUMgOvr7yuXkQq1”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Team
Retrieve a specific team by its ID.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| teamId | string | Yes | The unique identifier of the team |
Response
200 OK
“success”: true,
“message”: “Team retrieved successfully”,
“data”: {
“id”: “D4u5UDhoRLhoTxAO6O1u”,
“name”: “Sales Team Alpha”,
“is_active”: true,
“team_type”: “Office”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“parent_id”: null,
“created_by”: “s4qmQCYqXrVNsQUMgOvr7yuXkQq1”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Team
Create a new team for the specified tenant.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | The name of the team (non-empty string) |
| is_active | boolean | Yes | Whether the team is active |
| team_type | string | Yes | Type of team: “Office”, “Region”, or “Division” |
| tenant_id | string | Yes | The tenant ID (must match URL parameter) |
| parent_id | string | No | ID of the parent team (optional) |
Request Example
“name”: “Sales Team Alpha”,
“is_active”: true,
“team_type”: “Office”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“parent_id”: “parent-team-id”
}
Response
201 Created
“success”: true,
“message”: “Team created successfully”,
“data”: {
“id”: “D4u5UDhoRLhoTxAO6O1u”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
400 Bad Request
“success”: false,
“error”: “team_type must be one of: Office, Region, Division”,
“statusCode”: 400,
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Team
Update an existing team.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| teamId | string | Yes | The unique identifier of the team |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | The name of the team (non-empty string) |
| is_active | boolean | No | Whether the team is active |
| team_type | string | No | Type of team: “Office”, “Region”, or “Division” |
| tenant_id | string | No | The tenant ID (must match URL parameter) |
| parent_id | string | No | ID of the parent team (optional) |
Request Example
“name”: “Updated Team Name”,
“is_active”: false,
“team_type”: “Region”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“parent_id”: “parent-team-id”
}
Response
200 OK
“success”: true,
“message”: “Team updated successfully”,
“data”: {
“id”: “D4u5UDhoRLhoTxAO6O1u”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Team
Delete a team permanently.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| teamId | string | Yes | The unique identifier of the team |
Response
200 OK
“success”: true,
“message”: “Team deleted successfully”,
“data”: {
“id”: “D4u5UDhoRLhoTxAO6O1u”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Users API
GET
List Users
Retrieve a list of all users for the specified tenant.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of users to return (default: 50) |
| offset | integer | No | Number of users to skip (default: 0) |
| role | string | No | Filter by user role |
| is_active | boolean | No | Filter by active status |
Response
200 OK
“success”: true,
“message”: “Users retrieved successfully”,
“data”: [
{
“id”: “user-id-123”,
“email”: “user@example.com”,
“first_name”: “John”,
“last_name”: “Doe”,
“roles”: [“admin”],
“is_active”: true,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get User
Retrieve a specific user by their ID.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| userId | string | Yes | The unique identifier of the user |
Response
200 OK
“success”: true,
“message”: “User retrieved successfully”,
“data”: {
“id”: “user-id-123”,
“email”: “user@example.com”,
“first_name”: “John”,
“last_name”: “Doe”,
“roles”: [“admin”],
“is_active”: true,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create User
Create a new user for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | User’s email address | |
| first_name | string | Yes | User’s first name |
| last_name | string | Yes | User’s last name |
| roles | array | Yes | Array of user roles |
| is_active | boolean | No | Whether the user is active (default: true) |
Request Example
“email”: “newuser@example.com”,
“first_name”: “Jane”,
“last_name”: “Smith”,
“roles”: [“user”],
“is_active”: true
}
Response
201 Created
“success”: true,
“message”: “User created successfully”,
“data”: {
“id”: “new-user-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update User
Update an existing user.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | No | User’s email address | |
| first_name | string | No | User’s first name |
| last_name | string | No | User’s last name |
| roles | array | No | Array of user roles |
| is_active | boolean | No | Whether the user is active |
Response
200 OK
“success”: true,
“message”: “User updated successfully”,
“data”: {
“id”: “user-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete User
Delete a user permanently.
Response
200 OK
“success”: true,
“message”: “User deleted successfully”,
“data”: {
“id”: “user-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Projects API
GET
List Projects
Retrieve a list of all projects for the specified tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of projects to return (default: 50) |
| offset | integer | No | Number of projects to skip (default: 0) |
| status | string | No | Filter by project status |
| teamId | string | No | Filter by team ID |
Response
200 OK
“success”: true,
“message”: “Projects retrieved successfully”,
“data”: [
{
“id”: “project-id-123”,
“name”: “Project Alpha”,
“description”: “A sample project”,
“status”: “active”,
“team_id”: “team-id-123”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Project
Retrieve a specific project by its ID.
Response
200 OK
“success”: true,
“message”: “Project retrieved successfully”,
“data”: {
“id”: “project-id-123”,
“name”: “Project Alpha”,
“description”: “A sample project”,
“status”: “active”,
“team_id”: “team-id-123”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Project
Create a new project for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | Yes | Tenant ID (must match URL parameter) |
| address | string | Yes | Project address |
| closed_date | string | Yes | Project close date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| closer | string | Yes | Closer name |
| customer_name | string | Yes | Customer name |
| string | Yes | Customer email | |
| lead_token | string | Yes | Lead token |
| phone | string | Yes | Customer phone number |
| project_status | string | Yes | Project status |
| project_type | string | Yes | Project type |
| self_gen | string | Yes | Self-generated flag |
| state | string | Yes | State (2-character format) |
| rep_ids | array | Yes | Array of representative IDs |
| date_paid | string | No | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| install_date | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| m2_date | string | No | M2 date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| installation_details | array | No | Installation details array |
| manager_ids | array | No | Array of manager IDs |
Request Example
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“address”: “123 Main St, Anytown, ST 12345”,
“closed_date”: “2025-07-07”,
“closer”: “John Smith”,
“customer_name”: “Martha Johnson”,
“email”: “martha@example.com”,
“lead_token”: “ABC123”,
“phone”: “+12345678909”,
“project_status”: “M3 Paid”,
“project_type”: “Solar Only”,
“self_gen”: “No”,
“state”: “CA”,
“rep_ids”: [“40”, “2494”],
“date_paid”: “2025-10-01”,
“install_date”: “2025-09-15”,
“m2_date”: “2025-10-01”,
“installation_details”: [“Detail 1”, “Detail 2”],
“manager_ids”: [“manager1”, “manager2”]
}
Response
201 Created
“success”: true,
“message”: “Project created successfully”,
“data”: {
“id”: “new-project-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Project
Update an existing project.
Response
200 OK
“success”: true,
“message”: “Project updated successfully”,
“data”: {
“id”: “project-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Project
Delete a project permanently.
Response
200 OK
“success”: true,
“message”: “Project deleted successfully”,
“data”: {
“id”: “project-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Project Overviews API
GET
List Project Overviews
Retrieve a list of all project overviews for the specified tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of overviews to return (default: 50) |
| offset | integer | No | Number of overviews to skip (default: 0) |
| salesProfessionalId | string | No | Filter by sales professional ID |
Response
200 OK
“success”: true,
“message”: “Project overviews retrieved successfully”,
“data”: [
{
“id”: “overview-id-123”,
“project_id”: “project-id-123”,
“sales_professional_id”: “user-id-123”,
“total_sales”: 50000.00,
“commission”: 5000.00,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Project Overview
Retrieve a specific project overview by its ID.
Response
200 OK
“success”: true,
“message”: “Project overview retrieved successfully”,
“data”: {
“id”: “overview-id-123”,
“project_id”: “project-id-123”,
“sales_professional_id”: “user-id-123”,
“total_sales”: 50000.00,
“commission”: 5000.00,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Project Overview
Create a new project overview for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| project_id | string | Yes | Associated project ID |
| sales_professional_id | string | Yes | Sales professional user ID |
| total_sales | number | No | Total sales amount |
| commission | number | No | Commission amount |
Request Example
“project_id”: “project-id-123”,
“sales_professional_id”: “user-id-123”,
“total_sales”: 50000.00,
“commission”: 5000.00
}
Response
201 Created
“success”: true,
“message”: “Project overview created successfully”,
“data”: {
“id”: “new-overview-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Project Overview
Update an existing project overview.
Response
200 OK
“success”: true,
“message”: “Project overview updated successfully”,
“data”: {
“id”: “overview-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Project Overview
Delete a project overview permanently.
Response
200 OK
“success”: true,
“message”: “Project overview deleted successfully”,
“data”: {
“id”: “overview-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Paystubs API
GET
List Paystubs
Retrieve a list of all paystubs for the specified tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of paystubs to return (default: 50) |
| offset | integer | No | Number of paystubs to skip (default: 0) |
| salesProfessionalId | string | No | Filter by sales professional ID |
| startDate | string | No | Filter by start date (ISO format) |
| endDate | string | No | Filter by end date (ISO format) |
Response
200 OK
“success”: true,
“message”: “Paystubs retrieved successfully”,
“data”: [
{
“id”: “paystub-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“sales_professional_id”: “40”,
“total_this_period”: 6777.00,
“scpfs”: {
“1”: {
“customer_name”: “George Harper”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77133”,
“sales_professional_id”: “40”,
“total_this_period”: 830.00
},
“2”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77132”,
“sales_professional_id”: “40”,
“total_this_period”: 820.00
},
“3”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “M2 & M3”,
“related_scpf_id”: “77125”,
“sales_professional_id”: “40”,
“total_this_period”: 5127.00
}
},
“period_start_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“period_end_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“gross_pay”: 5000.00,
“net_pay”: 4000.00,
“deductions”: 1000.00,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Paystub
Retrieve a specific paystub by its ID.
Response
200 OK
“success”: true,
“message”: “Paystub retrieved successfully”,
“data”: {
“id”: “paystub-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“sales_professional_id”: “40”,
“total_this_period”: 6777.00,
“scpfs”: {
“1”: {
“customer_name”: “George Harper”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77133”,
“sales_professional_id”: “40”,
“total_this_period”: 830.00
},
“2”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77132”,
“sales_professional_id”: “40”,
“total_this_period”: 820.00
},
“3”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “M2 & M3”,
“related_scpf_id”: “77125”,
“sales_professional_id”: “40”,
“total_this_period”: 5127.00
}
},
“period_start_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“period_end_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“gross_pay”: 5000.00,
“net_pay”: 4000.00,
“deductions”: 1000.00,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Paystub
Create a new paystub for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | Yes | Tenant ID (must match URL parameter) |
| pay_date | string | Yes | Pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| sales_professional_id | string | Yes | Sales professional user ID |
| total_this_period | number | Yes | Total amount for this period (stored as cents, e.g., 677700 for $6,777.00) |
| scpfs | object | Yes | Nested object containing SCPF entries (at least one required) |
| period_start_date | string | No | Pay period start date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| period_end_date | string | No | Pay period end date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| gross_pay | number | No | Gross pay amount (stored as dollar amount) |
| net_pay | number | No | Net pay amount (stored as dollar amount) |
| deductions | number | No | Total deductions (stored as dollar amount) |
SCPFs Object Structure
The scpfs field is a nested object where each key represents an SCPF entry. Each SCPF entry must contain the following required fields:
| Field | Type | Required | Description |
|---|---|---|---|
| customer_name | string | Yes | Customer name for this SCPF entry |
| pay_type | string | Yes | Type of payment (e.g., “Closer Override”, “M2 & M3”) |
| related_scpf_id | string | Yes | Related SCPF ID |
| sales_professional_id | string | Yes | Sales professional user ID |
| total_this_period | number | Yes | Total amount for this SCPF entry (stored as dollar amount) |
Request Example
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: “2025-10-15”,
“sales_professional_id”: “40”,
“total_this_period”: 6777.00,
“scpfs”: {
“1”: {
“customer_name”: “George Harper”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77133”,
“sales_professional_id”: “40”,
“total_this_period”: 830.00
},
“2”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “Closer Override”,
“related_scpf_id”: “77132”,
“sales_professional_id”: “40”,
“total_this_period”: 820.00
},
“3”: {
“customer_name”: “Kenneth Bowman”,
“pay_type”: “M2 & M3”,
“related_scpf_id”: “77125”,
“sales_professional_id”: “40”,
“total_this_period”: 5127.00
}
},
“period_start_date”: “2025-10-01”,
“period_end_date”: “2025-10-15”,
“gross_pay”: 5000.00,
“net_pay”: 4000.00,
“deductions”: 100000
}
Response
201 Created
“success”: true,
“message”: “Paystub created successfully”,
“data”: {
“id”: “new-paystub-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Paystub
Update an existing paystub.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | No | Tenant ID (must match URL parameter if provided) |
| pay_date | string | No | Pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| sales_professional_id | string | No | Sales professional user ID |
| total_this_period | number | No | Total amount for this period (stored as cents, e.g., 677700 for $6,777.00) |
| scpfs | object | No | Nested object containing SCPF entries (at least one required if provided) |
| period_start_date | string | No | Pay period start date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| period_end_date | string | No | Pay period end date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| gross_pay | number | No | Gross pay amount (stored as dollar amount) |
| net_pay | number | No | Net pay amount (stored as dollar amount) |
| deductions | number | No | Total deductions (stored as dollar amount) |
Request Example
“pay_date”: “2025-10-20”,
“total_this_period”: 750000,
“scpfs”: {
“1”: {
“customer_name”: “Updated Customer”,
“pay_type”: “Updated Payment”,
“related_scpf_id”: “77134”,
“sales_professional_id”: “40”,
“total_this_period”: 90000
}
}
}
Response
200 OK
“success”: true,
“message”: “Paystub updated successfully”,
“data”: {
“id”: “paystub-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Paystub
Delete a paystub permanently.
Response
200 OK
“success”: true,
“message”: “Paystub deleted successfully”,
“data”: {
“id”: “paystub-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Paystub Overviews API
GET
List Paystub Overviews
Retrieve a list of all paystub overviews for the specified tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of overviews to return (default: 50) |
| offset | integer | No | Number of overviews to skip (default: 0) |
| salesProfessionalId | string | No | Filter by sales professional ID |
Response
200 OK
“success”: true,
“message”: “Paystub overviews retrieved successfully”,
“data”: [
{
“id”: “overview-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“sales_professional_id”: “user-id-123”,
“total_this_period”: 1500.00,
“assist_pay_pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“build_partner”: “SolarCorp”,
“customer_name”: “John Smith”,
“lead_token”: “ABC123”,
“project_status”: “M3 Paid”,
“project_type”: “Solar Only”,
“self_gen”: “No”,
“rep_ids”: [“40”, “2494”],
“manager_ids”: [“manager1”, “manager2”],
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Paystub Overview
Retrieve a specific paystub overview by its ID.
Response
200 OK
“success”: true,
“message”: “Paystub overview retrieved successfully”,
“data”: {
“id”: “overview-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“sales_professional_id”: “user-id-123”,
“total_this_period”: 1500.00,
“assist_pay_pay_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“build_partner”: “SolarCorp”,
“customer_name”: “John Smith”,
“lead_token”: “ABC123”,
“project_status”: “M3 Paid”,
“project_type”: “Solar Only”,
“self_gen”: “No”,
“rep_ids”: [“40”, “2494”],
“manager_ids”: [“manager1”, “manager2”],
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Paystub Overview
Create a new paystub overview for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | Yes | Tenant ID (must match URL parameter) |
| pay_date | string | Yes | Pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| sales_professional_id | string | Yes | Sales professional user ID |
| total_this_period | number | Yes | Total amount for this period (stored as dollar amount, e.g., 1500.00 for $1,500.00) |
| assist_pay_pay_date | string | No | Assist pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| assist_pay_period_start_date | string | No | Assist pay period start date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| date_paid | string | No | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| install_date | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| m2_date | string | No | M2 date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| build_partner | string | No | Build partner name |
| customer_name | string | No | Customer name |
| lead_token | string | No | Lead token |
| project_status | string | No | Project status |
| project_type | string | No | Project type |
| self_gen | string | No | Self-generated flag |
| rep_ids | array | No | Array of representative IDs |
| manager_ids | array | No | Array of manager IDs |
Request Example
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“pay_date”: “2025-01-15”,
“sales_professional_id”: “user-id-123”,
“total_this_period”: 1500.00,
“assist_pay_pay_date”: “2025-01-10”,
“assist_pay_period_start_date”: “2025-01-01”,
“date_paid”: “2025-01-15”,
“install_date”: “2025-01-05”,
“m2_date”: “2025-01-20”,
“build_partner”: “SolarCorp”,
“customer_name”: “John Smith”,
“lead_token”: “ABC123”,
“project_status”: “M3 Paid”,
“project_type”: “Solar Only”,
“self_gen”: “No”,
“rep_ids”: [“40”, “2494”],
“manager_ids”: [“manager1”, “manager2”]
}
Response
201 Created
“success”: true,
“message”: “Paystub overview created successfully”,
“data”: {
“id”: “new-overview-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Paystub Overview
Update an existing paystub overview.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | No | Tenant ID (must match URL parameter if provided) |
| pay_date | string | No | Pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| sales_professional_id | string | No | Sales professional user ID |
| total_this_period | number | No | Total amount for this period (stored as dollar amount, e.g., 1500.00 for $1,500.00) |
| assist_pay_pay_date | string | No | Assist pay date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| assist_pay_period_start_date | string | No | Assist pay period start date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| date_paid | string | No | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| install_date | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| m2_date | string | No | M2 date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| build_partner | string | No | Build partner name |
| customer_name | string | No | Customer name |
| lead_token | string | No | Lead token |
| project_status | string | No | Project status |
| project_type | string | No | Project type |
| self_gen | string | No | Self-generated flag |
| rep_ids | array | No | Array of representative IDs |
| manager_ids | array | No | Array of manager IDs |
Request Example
“pay_date”: “2025-01-20”,
“total_this_period”: 1750.00,
“project_status”: “M4 Paid”,
“customer_name”: “Jane Doe”
}
Response
200 OK
“success”: true,
“message”: “Paystub overview updated successfully”,
“data”: {
“id”: “overview-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Paystub Overview
Delete a paystub overview permanently.
Response
200 OK
“success”: true,
“message”: “Paystub overview deleted successfully”,
“data”: {
“id”: “overview-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
SCPFs API
GET
List SCPFs
Retrieve a list of all SCPFs (Sales Commission Prep Files) for the specified tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of SCPFs to return (default: 50) |
| offset | integer | No | Number of SCPFs to skip (default: 0) |
| salesProfessionalId | string | No | Filter by sales professional ID |
| status | string | No | Filter by SCPF status |
Response
200 OK
“success”: true,
“message”: “SCPFs retrieved successfully”,
“data”: [
{
“id”: “scpf-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“closed_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“closer”: “John Smith”,
“closer_id”: “closer-123”,
“customer_name”: “Jane Doe”,
“install”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“lead_name”: “Lead Source ABC”,
“lead_rep_id”: “rep-456”,
“pay_type”: “M2 & M3”,
“paystubId”: “paystub-789”,
“sales_professional_id”: “user-123”,
“scpf_id”: “scpf-001”,
“total_this_period”: 1500.00,
“build_partner”: “SolarCorp”,
“customer_ppw”: 3.25,
“dealer_fee”: 50.00,
“lead_deduction”: 20.00,
“lead_pay”: 80.00,
“lead_pkw”: 3.50,
“manager_override”: 10.00,
“net_commission_ppw”: 2.75,
“notes”: “Special installation requirements”,
“opportunity_id”: “opp-12345”,
“redline”: 15.00,
“paystub_name_alpha”: “Doe_Jane”,
“sentinel_fee”: 3.00,
“sow_adder”: 5.00,
“system_size”: 8.5,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get SCPF
Retrieve a specific SCPF by its ID.
Response
200 OK
“success”: true,
“message”: “SCPF retrieved successfully”,
“data”: {
“id”: “scpf-id-123”,
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“closed_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“closer”: “John Smith”,
“closer_id”: “closer-123”,
“customer_name”: “Jane Doe”,
“install”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“lead_name”: “Lead Source ABC”,
“lead_rep_id”: “rep-456”,
“pay_type”: “M2 & M3”,
“paystubId”: “paystub-789”,
“sales_professional_id”: “user-123”,
“scpf_id”: “scpf-001”,
“total_this_period”: 1500.00,
“build_partner”: “SolarCorp”,
“customer_ppw”: 3.25,
“dealer_fee”: 50.00,
“lead_deduction”: 20.00,
“lead_pay”: 80.00,
“lead_pkw”: 3.50,
“manager_override”: 10.00,
“net_commission_ppw”: 2.75,
“notes”: “Special installation requirements”,
“opportunity_id”: “opp-12345”,
“redline”: 15.00,
“paystub_name_alpha”: “Doe_Jane”,
“sentinel_fee”: 3.00,
“sow_adder”: 5.00,
“system_size”: 8.5,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create SCPF
Create a new SCPF (Solar Commission Prep File) for the specified tenant.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | Yes | Tenant ID (must match URL parameter) |
| closed_date | string | Yes | Closed date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| closer | string | Yes | Closer name |
| closer_id | string | Yes | Closer ID |
| customer_name | string | Yes | Customer name |
| install | string | Yes | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| lead_name | string | Yes | Lead name |
| lead_rep_id | string | Yes | Lead representative ID |
| pay_type | string | Yes | Payment type |
| paystubId | string | Yes | Associated paystub ID |
| sales_professional_id | string | Yes | Sales professional user ID |
| scpf_id | string | Yes | SCPF identifier |
| total_this_period | number | Yes | Total amount for this period (stored as dollar amount, e.g., 1500.00 for $1,500.00) |
| build_partner | string | No | Build partner name |
| customer_ppw | number | No | Customer price per watt |
| dealer_fee | number | No | Dealer fee amount (stored as dollar amount) |
| lead_deduction | number | No | Lead deduction amount (stored as dollar amount) |
| lead_pay | number | No | Lead pay amount (stored as dollar amount) |
| lead_pkw | number | No | Lead price per kilowatt |
| manager_override | number | No | Manager override amount (stored as dollar amount) |
| net_commission_ppw | number | No | Net commission price per watt |
| notes | string | No | Additional notes |
| opportunity_id | string | No | Opportunity identifier |
| redline | number | No | Redline amount (stored as dollar amount) |
| paystub_name_alpha | string | No | Paystub name in alphabetical format |
| sentinel_fee | number | No | Sentinel fee amount (stored as dollar amount) |
| sow_adder | number | No | SOW adder amount (stored as dollar amount) |
| system_size | number | No | System size in kilowatts |
Request Example
“tenant_id”: “1A2B3C4D-5E6F7G8H-9I0J1K2L-3M4N5O6P-7Q8R9S0T”,
“closed_date”: “2025-01-15”,
“closer”: “John Smith”,
“closer_id”: “closer-123”,
“customer_name”: “Jane Doe”,
“install”: “2025-01-20”,
“lead_name”: “Lead Source ABC”,
“lead_rep_id”: “rep-456”,
“pay_type”: “M2 & M3”,
“paystubId”: “paystub-789”,
“sales_professional_id”: “user-123”,
“scpf_id”: “scpf-001”,
“total_this_period”: 1500.00,
“build_partner”: “SolarCorp”,
“customer_ppw”: 3.25,
“dealer_fee”: 50.00,
“lead_deduction”: 20.00,
“lead_pay”: 80.00,
“lead_pkw”: 3.50,
“manager_override”: 10.00,
“net_commission_ppw”: 2.75,
“notes”: “Special installation requirements”,
“opportunity_id”: “opp-12345”,
“redline”: 15.00,
“paystub_name_alpha”: “Doe_Jane”,
“sentinel_fee”: 3.00,
“sow_adder”: 5.00,
“system_size”: 8.5
}
Response
201 Created
“success”: true,
“message”: “SCPF created successfully”,
“data”: {
“id”: “new-scpf-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update SCPF
Update an existing SCPF.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | No | Tenant ID (must match URL parameter if provided) |
| closed_date | string | No | Closed date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| closer | string | No | Closer name |
| closer_id | string | No | Closer ID |
| customer_name | string | No | Customer name |
| install | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| lead_name | string | No | Lead name |
| lead_rep_id | string | No | Lead representative ID |
| pay_type | string | No | Payment type |
| paystubId | string | No | Associated paystub ID |
| sales_professional_id | string | No | Sales professional user ID |
| scpf_id | string | No | SCPF identifier |
| total_this_period | number | No | Total amount for this period (stored as dollar amount, e.g., 1500.00 for $1,500.00) |
| build_partner | string | No | Build partner name |
| customer_ppw | number | No | Customer price per watt |
| dealer_fee | number | No | Dealer fee amount (stored as dollar amount) |
| lead_deduction | number | No | Lead deduction amount (stored as dollar amount) |
| lead_pay | number | No | Lead pay amount (stored as dollar amount) |
| lead_pkw | number | No | Lead price per kilowatt |
| manager_override | number | No | Manager override amount (stored as dollar amount) |
| net_commission_ppw | number | No | Net commission price per watt |
| notes | string | No | Additional notes |
| opportunity_id | string | No | Opportunity identifier |
| redline | number | No | Redline amount (stored as dollar amount) |
| paystub_name_alpha | string | No | Paystub name in alphabetical format |
| sentinel_fee | number | No | Sentinel fee amount (stored as dollar amount) |
| sow_adder | number | No | SOW adder amount (stored as dollar amount) |
| system_size | number | No | System size in kilowatts |
Request Example
“customer_name”: “Updated Customer Name”,
“total_this_period”: 1750.00,
“notes”: “Updated installation notes”,
“system_size”: 9.2
}
Response
200 OK
“success”: true,
“message”: “SCPF updated successfully”,
“data”: {
“id”: “scpf-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete SCPF
Delete a SCPF permanently.
Response
200 OK
“success”: true,
“message”: “SCPF deleted successfully”,
“data”: {
“id”: “scpf-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Overrides API
GET
List Overrides
Retrieve a list of all overrides for the specified manager.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| managerId | string | Yes | The sales_professional_uid of the manager |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of overrides to return (default: 50) |
| offset | integer | No | Number of overrides to skip (default: 0) |
| repId | string | No | Filter by rep’s sales_professional_uid |
| startDate | string | No | Filter by start date (YYYY-MM-DD format) |
| endDate | string | No | Filter by end date (YYYY-MM-DD format) |
Response
200 OK
“success”: true,
“message”: “Overrides retrieved successfully”,
“data”: [
{
“id”: “override-id-123”,
“amount”: 1500.00,
“customer_name”: “John Smith”,
“date_paid”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“manager_id”: “manager-123”,
“rep_id”: “rep-456”,
“rep_name”: “Jane Doe”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Override
Retrieve a specific override by its ID.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| managerId | string | Yes | The sales_professional_uid of the manager |
| overrideId | string | Yes | The unique identifier of the override |
Response
200 OK
“success”: true,
“message”: “Override retrieved successfully”,
“data”: {
“id”: “override-id-123”,
“amount”: 1500.00,
“customer_name”: “John Smith”,
“date_paid”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“manager_id”: “manager-123”,
“rep_id”: “rep-456”,
“rep_name”: “Jane Doe”,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Override
Create a new override for the specified manager.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| managerId | string | Yes | The sales_professional_uid of the manager |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount | number | Yes | Override amount (stored as dollar amount, e.g., 1500.00 for $1,500.00) |
| customer_name | string | Yes | Customer name |
| date_paid | string | Yes | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| manager_id | string | Yes | Manager’s sales_professional_uid (must match URL parameter) |
| rep_id | string | Yes | Rep’s sales_professional_uid |
| rep_name | string | Yes | Rep’s name |
Request Example
“amount”: 1500.00,
“customer_name”: “John Smith”,
“date_paid”: “2025-01-15”,
“manager_id”: “manager-123”,
“rep_id”: “rep-456”,
“rep_name”: “Jane Doe”
}
Response
201 Created
“success”: true,
“message”: “Override created successfully”,
“data”: {
“id”: “new-override-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Override
Update an existing override.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount | number | No | Override amount (stored as dollar amount) |
| customer_name | string | No | Customer name |
| date_paid | string | No | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| manager_id | string | No | Manager’s sales_professional_uid (must match URL parameter if provided) |
| rep_id | string | No | Rep’s sales_professional_uid |
| rep_name | string | No | Rep’s name |
Request Example
“amount”: 1750.00,
“customer_name”: “Updated Customer Name”
}
Response
200 OK
“success”: true,
“message”: “Override updated successfully”,
“data”: {
“id”: “override-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Override
Delete an override permanently.
Response
200 OK
“success”: true,
“message”: “Override deleted successfully”,
“data”: {
“id”: “override-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Override Details API
GET
List Override Details
Retrieve a list of all override details for the specified override.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tenantId | string | Yes | The unique identifier of the tenant |
| managerId | string | Yes | The sales_professional_uid of the manager |
| overrideId | string | Yes | The unique identifier of the override |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of details to return (default: 50) |
| offset | integer | No | Number of details to skip (default: 0) |
Response
200 OK
“success”: true,
“message”: “Override details retrieved successfully”,
“data”: [
{
“id”: “detail-id-123”,
“closed_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“closer”: “John Smith”,
“customer_name”: “Jane Doe”,
“date_paid”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“total_this_period”: 2500.00,
“build_partner”: “SolarCorp”,
“install_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“lead_rep”: “Lead Rep Name”,
“manager_override”: 500.00,
“system_size”: 8.5,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
}
],
“timestamp”: “2025-10-10T18:52:56.419Z”
}
GET
Get Override Detail
Retrieve a specific override detail by its ID.
Response
200 OK
“success”: true,
“message”: “Override detail retrieved successfully”,
“data”: {
“id”: “detail-id-123”,
“closed_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“closer”: “John Smith”,
“customer_name”: “Jane Doe”,
“date_paid”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“total_this_period”: 2500.00,
“build_partner”: “SolarCorp”,
“install_date”: {
“_seconds”: 1735689600,
“_nanoseconds”: 0
},
“lead_rep”: “Lead Rep Name”,
“manager_override”: 500.00,
“system_size”: 8.5,
“created_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
},
“updated_at”: {
“_seconds”: 1760122266,
“_nanoseconds”: 975000000
}
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
POST
Create Override Detail
Create a new override detail for the specified override.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| closed_date | string | Yes | Closed date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| closer | string | Yes | Closer name |
| customer_name | string | Yes | Customer name |
| date_paid | string | Yes | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| total_this_period | number | Yes | Total amount for this period (stored as dollar amount) |
| build_partner | string | No | Build partner name |
| install_date | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| lead_rep | string | No | Lead representative name |
| manager_override | number | No | Manager override amount (stored as dollar amount) |
| system_size | number | No | System size in kilowatts |
Request Example
“closed_date”: “2025-01-15”,
“closer”: “John Smith”,
“customer_name”: “Jane Doe”,
“date_paid”: “2025-01-20”,
“total_this_period”: 2500.00,
“build_partner”: “SolarCorp”,
“install_date”: “2025-01-18”,
“lead_rep”: “Lead Rep Name”,
“manager_override”: 500.00,
“system_size”: 8.5
}
Response
201 Created
“success”: true,
“message”: “Override detail created successfully”,
“data”: {
“id”: “new-detail-id”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
PUT
Update Override Detail
Update an existing override detail.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| closed_date | string | No | Closed date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| closer | string | No | Closer name |
| customer_name | string | No | Customer name |
| date_paid | string | No | Date paid (YYYY-MM-DD format, converted to Firestore Timestamp) |
| total_this_period | number | No | Total amount for this period (stored as dollar amount) |
| build_partner | string | No | Build partner name |
| install_date | string | No | Installation date (YYYY-MM-DD format, converted to Firestore Timestamp) |
| lead_rep | string | No | Lead representative name |
| manager_override | number | No | Manager override amount (stored as dollar amount) |
| system_size | number | No | System size in kilowatts |
Request Example
“total_this_period”: 2750.00,
“manager_override”: 600.00,
“system_size”: 9.2
}
Response
200 OK
“success”: true,
“message”: “Override detail updated successfully”,
“data”: {
“id”: “detail-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
DELETE
Delete Override Detail
Delete an override detail permanently.
Response
200 OK
“success”: true,
“message”: “Override detail deleted successfully”,
“data”: {
“id”: “detail-id-123”
},
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Error Responses
“success”: false,
“error”: “Unauthorized: Invalid token”,
“statusCode”: 401,
“timestamp”: “2025-10-10T18:52:56.419Z”
}
“success”: false,
“error”: “Forbidden: No access to this tenant”,
“statusCode”: 403,
“timestamp”: “2025-10-10T18:52:56.419Z”
}
“success”: false,
“error”: “Resource not found”,
“statusCode”: 404,
“timestamp”: “2025-10-10T18:52:56.419Z”
}
“success”: false,
“error”: “Internal server error”,
“statusCode”: 500,
“timestamp”: “2025-10-10T18:52:56.419Z”
}
Status Codes
| Code | Description |
|---|---|
| 200 | Success (GET, PUT, DELETE) |
| 201 | Created (POST) |
| 400 | Bad Request |
| 401 | Unauthorized (invalid/missing token) |
| 403 | Forbidden (no access to tenant) |
| 404 | Not Found |
| 500 | Internal Server Error |
Rate Limiting
API requests are subject to rate limiting. If you exceed the rate limit, you will receive a 429 Too Many Requests response.
Support
For technical support or questions about the API, please contact your system administrator.
API Version: v1
Documentation Version: 1.0
Total Endpoints: 39
