External API Documentation
Integrate Your Systems with EasySolar API
API key–based integration grants You access to Calendar, Projects, Clients, and Components.
This gives you flexibility to integrate with your systems and automate processes.
External API Documentation
API key–based integration grants You access to Calendar, Projects, Clients, and Components. This gives you flexibility to integrate with your systems and automate processes.
Table of Contents
- Authentication
- Pagination
- Calendar API
- Projects API
- Clients API
- Components API
- Data Conventions
- Filtering Behavior
- Permission Model
- Error Handling
- Integration Patterns
- Stability & Versioning
1. Authentication
All requests must include an API key in the request header.
Authorization: Api-Key <raw_api_key>
Notes: - API keys are created and managed by company owners and admins. - Each key is scoped to specific resource permissions. - All requests are automatically scoped to the company attached to the API key.
Authentication Errors
| Status | Reason |
|---|---|
401 | Missing or invalid API key |
401 | Malformed authorization header |
401 | Inactive API key |
403 | Missing resource permission |
402 | Company inactive |
2. Pagination
List endpoints (Calendar, Projects, Clients) use limit/offset pagination.
Parameters
| Parameter | Description | Default | Max |
|---|---|---|---|
limit | Number of results to return | 100 | 500 |
offset | Pagination offset | 0 | — |
Response Envelope
{
"count": 123,
"next": null,
"previous": null,
"results": []
}
When next is null, you have reached the last page.
3. Calendar API
Represents scheduled events such as meetings, calls, and installations. Read-only.
Endpoints
GET https://api-production.easysolar-app.com/integrations/calendar/
GET https://api-production.easysolar-app.com/integrations/calendar/{id}/
Required permission: calendar_read
Response Example
{
"id": "7d0f4d55-3b66-4c71-a86d-2b0ef2fca6d5",
"category": "meeting",
"subject": "Initial Site Visit",
"description": "Discuss installation requirements and roof inspection.",
"client": {
"id": "4ab8e7cb-0a27-48f1-a0f6-6d6ecf5d8c6a",
"name": "Solar Corp",
"address": "Main Street 10, Warsaw",
"phone": "+48123456789",
"is_open": true
},
"participants": [
{
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@example.com"
}
],
"start_at": "2026-06-15T09:00:00Z",
"end_at": "2026-06-15T10:00:00Z",
"full_day": false,
"created_at": "2026-06-01T12:30:45Z"
}
Field Reference
| Field | Type | Description |
|---|---|---|
id | UUID | Event identifier |
category | string | Event category (see values below) |
subject | string | Event title |
description | string | Additional event notes |
client | object | null | Linked client |
participants | array | Employees assigned to the event |
start_at | datetime | Event start time (UTC) |
end_at | datetime | Event end time (UTC) |
full_day | boolean | Whether the event spans the entire day |
created_at | datetime | Event creation timestamp |
Category Values
| Value | Description |
|---|---|
meeting | Meeting |
call | Phone call |
installation | Installation appointment |
contract | Contract signing |
quotation | Quotation presentation |
Nested Objects
Client object:
| Field | Type | Description |
|---|---|---|
id | UUID | Client identifier |
name | string | Client name |
address | string | Client address |
phone | string | Client phone number |
is_open | boolean | Client active status |
Participant object:
| Field | Type | Description |
|---|---|---|
first_name | string | Employee first name |
last_name | string | Employee last name |
email | string | Employee email address |
Filters
| Parameter | Type | Description |
|---|---|---|
start_at_after | datetime | Filter events starting after this time |
start_at_before | datetime | Filter events starting before this time |
end_at_after | datetime | Filter events ending after this time |
end_at_before | datetime | Filter events ending before this time |
category | string (multi) | Filter by category; repeat for multiple values |
client | UUID | Filter by client ID |
Example:
GET https://api-production.easysolar-app.com/integrations/calendar/?start_at_after=2026-01-01T00:00:00Z&category=meeting&category=call
Authorization: Api-Key <key>
4. Projects API
Represents client-related project records (e.g. solar installations). Read-only.
Endpoints
GET https://api-production.easysolar-app.com/integrations/projects/
GET https://api-production.easysolar-app.com/integrations/projects/{id}/
Required permission: projects_read
Response Example
{
"id": "d8e22cb9-1d88-4a3d-a3fd-f954d1f23d59",
"name": "Solar Installation - Warsaw Office",
"address": "Aleje Jerozolimskie 120, Warsaw",
"latitude": 52.2297,
"longitude": 21.0122,
"client": {
"id": "4ab8e7cb-0a27-48f1-a0f6-6d6ecf5d8c6a",
"name": "Solar Corp",
"address": "Main Street 10, Warsaw",
"phone": "+48123456789",
"is_open": true
},
"status": {
"name": "In Progress",
"order": 2
},
"currency": {
"code": "PLN",
"name": "Polish Złoty"
},
"total_price": "42500.00",
"payback_period": 8,
"created": "2026-05-01T09:00:00Z",
"updated": "2026-06-01T15:30:00Z"
}
Field Reference
| Field | Type | Description |
|---|---|---|
id | UUID | Project identifier |
name | string | Project name |
address | string | Project address |
latitude | decimal | null | Project latitude |
longitude | decimal | null | Project longitude |
client | object | Linked client (see Client object) |
status | object | Project status |
currency | object | Currency used for financial values |
total_price | decimal string | Current project total price |
payback_period | integer | null | Estimated payback period in years |
created | datetime | Creation timestamp |
updated | datetime | Last update timestamp |
total_priceis returned as a decimal string to preserve precision.payback_periodisnullif not yet calculated.latitude/longitudearenullif no location is set.
Nested Objects
Status object:
| Field | Type | Description |
|---|---|---|
name | string | Status display name |
order | integer | Status ordering value |
Currency object:
| Field | Type | Description |
|---|---|---|
code | string | ISO currency code |
name | string | Currency name |
Filters
| Parameter | Type | Description |
|---|---|---|
created_after | datetime | Filter by creation date (lower bound) |
created_before | datetime | Filter by creation date (upper bound) |
updated_after | datetime | Filter by update date (lower bound) |
updated_before | datetime | Filter by update date (upper bound) |
client | UUID | Filter by client ID |
status | UUID | Filter by status ID |
name | string | Case-insensitive partial name match |
Example:
GET https://api-production.easysolar-app.com/integrations/projects/?client=<id>&name=solar
Authorization: Api-Key <key>
5. Clients API
Represents customer entities. Supports read and write operations.
Endpoints
GET https://api-production.easysolar-app.com/integrations/clients/
POST https://api-production.easysolar-app.com/integrations/clients/
GET https://api-production.easysolar-app.com/integrations/clients/{id}/
PATCH https://api-production.easysolar-app.com/integrations/clients/{id}/
Required permissions: clients_read (read), clients_write (write)
Response Example
{
"id": "4ab8e7cb-0a27-48f1-a0f6-6d6ecf5d8c6a",
"name": "Solar Corp",
"description": "Commercial customer interested in a rooftop PV installation.",
"address": "Main Street 10, Warsaw",
"latitude": 52.2297,
"longitude": 21.0122,
"phone": "+48123456789",
"is_open": true,
"created": "2026-05-01T10:15:00Z",
"updated": "2026-06-01T08:45:30Z"
}
Field Reference
| Field | Type | Description |
|---|---|---|
id | UUID | Client identifier |
name | string | Client name |
description | string | Additional notes |
address | string | Client address |
latitude | decimal | null | Client latitude |
longitude | decimal | null | Client longitude |
phone | string | null | Client phone number |
is_open | boolean | Whether the client is currently active |
created | datetime | Creation timestamp |
updated | datetime | Last update timestamp |
Create Client
POST https://api-production.easysolar-app.com/integrations/clients/
{
"name": "Client Name",
"description": "Commercial customer",
"address": "Address",
"phone": "+48123456789",
"latitude": 52.2297,
"longitude": 21.0122
}
Update Client
PATCH https://api-production.easysolar-app.com/integrations/clients/{id}/
Only include the fields you want to update:
{
"address": "New Address 15, Warsaw",
"phone": "+48987654321"
}
Coordinate Rules
latitudeandlongitudemust always be provided together.- Supplying only one coordinate results in a validation error.
- If no location is set, both fields are returned as
null.
Filters
| Parameter | Type | Description |
|---|---|---|
created_after | datetime | Filter by creation date (lower bound) |
created_before | datetime | Filter by creation date (upper bound) |
updated_after | datetime | Filter by update date (lower bound) |
updated_before | datetime | Filter by update date (upper bound) |
is_open | boolean | Filter by active status (true or false) |
name | string | Case-insensitive partial name match |
phone | string | Case-insensitive partial phone match |
6. Components API
Creates components for use in projects. Write-only.
Endpoint
POST https://api-production.easysolar-app.com/integrations/components/
Required permission: components_write
Component Types
Three component types are supported: panel, inverter, and other.
Panel
{
"type": "panel",
"manufacturer_name": "Longi",
"name": "LR5-54HPH",
"net_unit_price": "120.00",
"nominal_power": "430.000",
"length": "1.7220",
"width": "1.1340",
"weight": "21.500",
"efficiency": "0.2100000",
"short_circuit_current": "13.52000",
"open_circuit_voltage": "37.85000",
"current_temperature_coefficient": "0.045000",
"voltage_temperature_coefficient": "-0.280000",
"power_temperature_coefficient": "-0.350000"
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "panel" |
manufacturer_name | string | Yes | Manufacturer name |
name | string | Yes | Panel model name |
net_unit_price | decimal | No | Net unit price |
nominal_power | decimal | Yes | Rated power (W) |
length | decimal | Yes | Panel length (m) |
width | decimal | Yes | Panel width (m) |
weight | decimal | null | No | Weight (kg) |
efficiency | decimal | Yes | Conversion efficiency |
short_circuit_current | decimal | Yes | Short-circuit current (A) |
open_circuit_voltage | decimal | Yes | Open-circuit voltage (V) |
current_temperature_coefficient | decimal | null | No | Current temperature coefficient |
voltage_temperature_coefficient | decimal | null | No | Voltage temperature coefficient |
power_temperature_coefficient | decimal | null | No | Power temperature coefficient |
Inverter
{
"type": "inverter",
"manufacturer_name": "SMA",
"name": "Sunny Tripower 5.0",
"net_unit_price": "900.00",
"nominal_power": "5000.000",
"number_of_dc_inputs": 2
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "inverter" |
manufacturer_name | string | Yes | Manufacturer name |
name | string | Yes | Inverter model name |
net_unit_price | decimal | No | Net unit price |
nominal_power | decimal | Yes | Rated power (W) |
number_of_dc_inputs | integer | Yes | Number of DC inputs |
Other
{
"type": "other",
"name": "Mounting System",
"unit": "pcs",
"net_unit_price": "50.00"
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "other" |
name | string | Yes | Component name |
unit | string | No | Unit of measurement |
net_unit_price | decimal | No | Net unit price |
Response
{
"id": "uuid",
"type": "panel | inverter | other",
"name": "string"
}
Notes
- Manufacturers are automatically created if they don't exist.
- Manufacturer uniqueness is scoped per company.
- All panel-specific fields are validated before creation.
7. Data Conventions
IDs
All resource identifiers are UUID strings, stable and globally unique within a company:
"id": "550e8400-e29b-41d4-a716-446655440000"
Timestamps
All datetime fields are returned in ISO 8601 format, always in UTC:
"created": "2026-06-09T12:34:56Z"
Geolocation
Coordinates apply to Clients and Projects. They are stored as a geographic point and returned as separate fields:
"latitude": 52.2297,
"longitude": 21.0122
Null Handling
Fields that are not set are returned as null — they are never omitted from the response.
8. Filtering Behavior
General Rules
- All filters are optional unless stated otherwise.
- Multiple filters are combined with AND logic.
- Multi-select filter values (e.g.
category) use OR logic internally. - Invalid filter values return empty results or a validation error depending on field type.
Date Range Filters
Available across endpoints:
| Filter fields | Behavior |
|---|---|
created_after / created_before | Range filter on creation timestamp |
updated_after / updated_before | Range filter on last-update timestamp |
start_at_after / start_at_before | Range filter on event start time |
end_at_after / end_at_before | Range filter on event end time |
Text Search Filters
Case-insensitive partial matching on name and phone:
?name=solar
Matches: "Solar Corp", "My Solar Project", etc.
9. Permission Model
API key permissions are configured independently per resource:
| Resource | Read Permission | Write Permission |
|---|---|---|
| Calendar | calendar_read | (not supported) |
| Projects | projects_read | (not supported) |
| Clients | clients_read | clients_write |
| Components | (not supported) | components_write |
10. Error Handling
Error Format
General error:
{
"detail": "Error message"
}
Field-level validation error:
{
"field_name": ["Error message"]
}
Error Reference
| Status | Category | Meaning |
|---|---|---|
401 | Authentication | Invalid, missing, or inactive API key; malformed header |
402 | Business | Company is inactive |
403 | Authorization | API key lacks the required resource permission |
4xx | Validation | Field-level errors returned as an object |
Integration Checklist
If you encounter errors, verify:
- The API key has the correct resource permissions.
- The company account is active.
- All filter values (IDs, etc.) belong to the same company scope.
11. Integration Patterns
Sync Strategy
The recommended approach for syncing data:
- Fetch the list endpoint (paginated).
- Store the
idas an external reference. - Use the
updatedfield for incremental syncs.
Pagination Handling
Iterate through pages by incrementing the offset until next is null:
GET https://api-production.easysolar-app.com/integrations/clients/?limit=100&offset=0
GET https://api-production.easysolar-app.com/integrations/clients/?limit=100&offset=100
Incremental Sync
Use date filters to fetch only records changed since your last sync:
GET https://api-production.easysolar-app.com/integrations/projects/?updated_after=2026-01-01T00:00:00Z
Filtering Best Practices
- Prefer ID-based filters (
client,status) over text searches for high-volume syncs. - Combine multiple filters to reduce result set size.
- Avoid broad text searches on large datasets.
12. Stability & Versioning
Stable Guarantees
The following will not change without a versioned migration:
- Endpoint URLs
- Field names
- UUID format
- Pagination structure
- Authentication scheme
Subject to Change (Non-Breaking)
- Optional filters (new filters may be added)
- Response enrichment (new fields may be added)
Versioning Policy
No explicit version is currently exposed in the URL. Breaking changes will introduce a new endpoint namespace:
https://api-production.easysolar-app.com/integrations/v2/...
Additive changes are considered non-breaking and may be deployed without a version bump.
End of Documentation
Contact us
Need help?
Feel free to reach out and our dedicated team will respond to your inquiries promptly.
Sell automatically with AI
Create an Automated AI Salesperson in 2 minutes
Add the AI photovoltaic proposals generator to your current website. Set your prices, choose your products, and customize your company’s branding. Your customers will receive an instant offer, and you’ll get an immediate email notification for every proposal and interested client.



