opportunities
Opportunities API Documentation
Base URL
/api/sales/opportunities
Authentication
All endpoints require JWT authentication. Include the JWT token in the Authorization header:
Authorization: Bearer <your-jwt-token>
Rate Limiting
All endpoints are limited to 10 requests per second.
Endpoints
1. Get Opportunity by UUID
Retrieve a specific opportunity by its UUID with full details.
Endpoint: GET /api/sales/opportunities/
Request:
- Query Parameters:
uuid: Opportunity UUID (string, required, UUID format)
Response:
{
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Sale Opportunity",
"uuid_account": "456e7890-e89b-12d3-a456-426614174001",
"account_name": "Example Corp",
"owner_id": 123,
"owner_name": "John",
"owner_lastname": "Doe",
"id_opportunity_type": 1,
"id_opportunity_state": 1,
"uuid_stage": "789e0123-e89b-12d3-a456-426614174002",
"order": 1.5,
"tags": [1, 2, 3],
"start_date": "2024-01-15T10:30:00",
"updated_at": "2024-01-20T15:45:00",
"deleted_at": null,
"comment": "Important client",
"id_loss_reason": null,
"loss_reason_description": null,
"fields": [
{
"uuid_field": "abc12345-e89b-12d3-a456-426614174003",
"nombre": "Field 1",
"farm_name": "Farm A"
}
],
"notes": [],
"attachments": [],
"contacts": [
{
"uuid": "def67890-e89b-12d3-a456-426614174004",
"first_name": "Jane",
"last_name": "Smith",
"phone": "+1234567890",
"email": "jane@example.com"
}
],
"operations": []
}
Error Codes:
- Code 2: "UUID required" - Missing uuid parameter
- Code 7: "Opportunity not found" - The specified opportunity UUID doesn't exist
2. List Opportunities
List opportunities with filters and pagination. Supports three view modes: Kanban (all stages), Single Column (one stage), or Flat List (no stage grouping).
Endpoint: POST /api/sales/opportunities/
Request (Kanban View - All Stages):
{
"action": "get",
"limit": 15,
"uuid_accounts": ["123e4567-e89b-12d3-a456-426614174000"],
"owner_ids": [123, 456],
"id_opportunity_types": [1, 2],
"id_opportunity_states": [1],
"start_date": "2024-01-01",
"end_date": "2024-12-31"
}
Request (Single Column View):
{
"action": "get",
"uuid_stage": "789e0123-e89b-12d3-a456-426614174002",
"page": "MTIz",
"limit": 15
}
Request (Flat List View):
{
"action": "get",
"no_stages": true,
"page": "MTIz",
"limit": 15
}
Request Fields:
action: Must be "get" (string, required)page: Pagination cursor (string, optional, base64 encoded)limit: Number of results per page (integer, default: 15)uuid_accounts: Filter by account UUIDs (array of strings, optional)uuid_contacts: Filter by contact UUIDs (array of strings, optional)owner_ids: Filter by owner user IDs (array of integers, optional)id_opportunity_types: Filter by opportunity types (array of integers, optional)id_opportunity_states: Filter by states (array of integers, optional)uuid_stage: Filter by specific stage UUID (string, optional, use "null" or "0" for opportunities without stage)start_date: Filter by start date (string, optional, ISO format)end_date: Filter by end date (string, optional, ISO format)no_stages: Flat list without stage grouping (boolean, default: false)
Response (Kanban View):
{
"stages": [
{
"uuid_stage": "789e0123-e89b-12d3-a456-426614174002",
"name": "Prospecting",
"order": 1,
"opportunity_count": 25,
"opportunities": [...],
"next_page": "MTIz"
}
]
}
Response (Single Column / Flat List):
{
"data": [...],
"next_page": "MTIz"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
3. Create Opportunity
Create a new opportunity.
Endpoint: POST /api/sales/opportunities/
Request:
{
"action": "create",
"name": "New Sale Opportunity",
"uuid_account": "456e7890-e89b-12d3-a456-426614174001",
"id_opportunity_type": 1,
"uuid_stage": "789e0123-e89b-12d3-a456-426614174002",
"tags": [1, 2],
"comment": "High priority",
"fields": ["abc12345-e89b-12d3-a456-426614174003"],
"uuid_contacts": ["def67890-e89b-12d3-a456-426614174004"],
"operations": [
{
"id_opportunity_type": 1,
"comment": "Initial operation",
"items": [
{
"item_type": "crop",
"id_crop": 1,
"id_crop_variety": 2,
"quantity": 100,
"id_unit": 1,
"unit_value": 50.5,
"id_currency": 1
}
]
}
]
}
Request Fields:
action: Must be "create" (string, required)uuid: Optional custom UUID for mobile sync (string, optional, UUID format)name: Opportunity name (string, required, minimum 1 character)uuid_account: Account UUID (string, optional, UUID format)id_opportunity_type: Opportunity type ID (integer, required)uuid_stage: Stage UUID (string, optional, UUID format)tags: Array of tag IDs (array of integers, optional)comment: Additional comments (string, optional)fields: Array of field UUIDs (array of strings, optional)uuid_contacts: Array of contact UUIDs (array of strings, optional)operations: Array of operation objects (array, optional)
Response:
{
"code": 0,
"info": "Opportunity created",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"order": 1.5
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
- Code 4: "Field does not exist" - Invalid field UUID provided
- Code 5: "Stage not valid" - Invalid stage UUID or stage is inactive
- Code 6: "Opportunity type not valid" - Invalid opportunity type ID
4. Update Opportunity
Update an existing opportunity.
Endpoint: POST /api/sales/opportunities/
Request:
{
"action": "update",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated Opportunity Name",
"stage_uuid": "789e0123-e89b-12d3-a456-426614174002",
"after_uuid": "abc12345-e89b-12d3-a456-426614174005",
"id_opportunity_state": 2,
"tags": [1, 3, 5],
"comment": "Updated comment",
"uuid_contacts": ["def67890-e89b-12d3-a456-426614174004"],
"operations": []
}
Request Fields:
action: Must be "update" (string, required)uuid: Opportunity UUID (string, required, UUID format)stage_uuid: New stage UUID (string, optional, UUID format)after_uuid: UUID of opportunity to insert after (string, optional, null means first position)name: New name (string, optional)uuid_account: New account UUID (string, optional)id_opportunity_type: New type ID (integer, optional)id_opportunity_state: New state ID (integer, optional)order: New order value (number, optional)tags: New tags array (array of integers, optional)id_loss_reason: Loss reason ID (integer, optional)comment: New comment (string, optional)fields: New fields array (array of strings, optional)uuid_contacts: New contacts array (array of strings, optional)operations: New operations array (array, optional, null deletes all)
Response:
{
"code": 0,
"info": "Opportunity updated",
"order": 2.5
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 2: "No fields to update" - No valid fields provided for update
- Code 3: "Action required" - Missing action field
- Code 4: "Field does not exist" - Invalid field UUID provided
- Code 5: "Stage not valid" - Invalid stage UUID or stage is inactive
- Code 6: "Opportunity type not valid" - Invalid opportunity type ID
- Code 7: "Opportunity not found" - The specified opportunity UUID doesn't exist
5. Delete Opportunity
Delete an opportunity (soft delete). Only the owner can delete their opportunities.
Endpoint: POST /api/sales/opportunities/
Request:
{
"action": "delete",
"uuid": "123e4567-e89b-12d3-a456-426614174000"
}
Request Fields:
action: Must be "delete" (string, required)uuid: Opportunity UUID (string, required, UUID format)
Response:
{
"code": 0,
"info": "Opportunity deleted"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field or invalid action
- Code 7: "Opportunity not found" - The specified opportunity UUID doesn't exist
- Code 3: "Only the owner can delete the opportunity" - User is not the owner
6. Get Opportunity Owners
Get all users in the workspace that can be opportunity owners.
Endpoint: GET /api/sales/opportunities/owners
Request:
- No parameters required
Response:
{
"code": 0,
"data": [
{
"id": 123,
"first_name": "John",
"last_name": "Doe"
}
]
}
Operations Endpoints
7. Get Operations for Opportunity
Get all operations associated with an opportunity.
Endpoint: GET /api/sales/opportunities/operations
Request:
- Query Parameters:
uuid_opportunity: Opportunity UUID (string, required)page: Pagination cursor (string, optional)limit: Number of results (integer, default: 15)
Response:
{
"data": [
{
"uuid": "op123456-e89b-12d3-a456-426614174000",
"id_opportunity_type": 1,
"comment": "Operation comment",
"creation_date": "2024-01-15T10:30:00",
"last_modified": "2024-01-20T15:45:00",
"items": [
{
"uuid": "item1234-e89b-12d3-a456-426614174001",
"item_type": "crop",
"id_crop": 1,
"crop_name": "Wheat",
"id_crop_variety": 2,
"crop_variety_name": "Winter Wheat",
"quantity": 100,
"id_unit": 1,
"unit_name": "kg",
"unit_value": 50.5,
"id_currency": 1
}
]
}
],
"next_page": "MTIz"
}
Error Codes:
- Code 2: "uuid_opportunity required" - Missing uuid_opportunity parameter
8. Create Operation
Create a new operation for an opportunity.
Endpoint: POST /api/sales/opportunities/operations
Request:
{
"action": "create",
"uuid_opportunity": "123e4567-e89b-12d3-a456-426614174000",
"id_opportunity_type": 1,
"comment": "New operation",
"items": [
{
"item_type": "input",
"id_input": 5,
"quantity": 50,
"id_unit": 2,
"unit_value": 25.0,
"id_currency": 1
}
]
}
Response:
{
"code": 0,
"info": "Operation created",
"uuid": "op123456-e89b-12d3-a456-426614174000"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
9. Update Operation
Update an existing operation.
Endpoint: POST /api/sales/opportunities/operations
Request:
{
"action": "update",
"uuid_opportunity": "123e4567-e89b-12d3-a456-426614174000",
"uuid_operation": "op123456-e89b-12d3-a456-426614174000",
"data": {
"id_opportunity_type": 2,
"comment": "Updated comment",
"items": []
}
}
Response:
{
"code": 0,
"info": "Operation updated"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
10. Delete Operation
Delete an operation (soft delete).
Endpoint: POST /api/sales/opportunities/operations
Request:
{
"action": "delete",
"uuid_operation": "op123456-e89b-12d3-a456-426614174000"
}
Response:
{
"code": 0,
"info": "Operation deleted"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
Notes Endpoints
11. Get Notes
Get all notes for an opportunity or account.
Endpoint: GET /api/sales/notes
Request:
- Query Parameters:
entity_uuid: UUID of the entity (string, required)entity_type: Type of entity - "opportunity" or "account" (string, required)
Response:
{
"notes": [
{
"uuid": "note1234-e89b-12d3-a456-426614174000",
"text": "Important note",
"creation_date": "2024-01-15T10:30:00",
"last_modified": "2024-01-20T15:45:00",
"owner": "John Doe"
}
]
}
Error Codes:
- Code 2: "entity_uuid required" - Missing entity_uuid parameter
- Code 2: "entity_type required" - Missing entity_type parameter
- Code 3: "entity_type must be 'opportunity', or 'account'" - Invalid entity_type value
12. Create Note
Create a new note for an opportunity or account.
Endpoint: POST /api/sales/notes
Request:
{
"action": "create",
"entity_uuid": "123e4567-e89b-12d3-a456-426614174000",
"entity_type": "opportunity",
"text": "This is a new note"
}
Response:
{
"code": 0,
"info": "note created",
"uuid": "note1234-e89b-12d3-a456-426614174000"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
13. Update Note
Update an existing note.
Endpoint: POST /api/sales/notes
Request:
{
"action": "update",
"note_uuid": "note1234-e89b-12d3-a456-426614174000",
"text": "Updated note text"
}
Response:
{
"code": 0,
"info": "note updated",
"uuid": "note1234-e89b-12d3-a456-426614174000"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
14. Delete Note
Delete a note (soft delete).
Endpoint: POST /api/sales/notes
Request:
{
"action": "delete",
"note_uuid": "note1234-e89b-12d3-a456-426614174000"
}
Response:
{
"code": 0,
"info": "note deleted",
"uuid": "note1234-e89b-12d3-a456-426614174000"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
Attachments Endpoints
15. Initialize Attachment
Initialize an attachment upload (calls internal API backend).
Endpoint: PUT /api/sales/attachments
Request:
{
"uuid": "attach123-e89b-12d3-a456-426614174000"
}
Response:
{
"url": "https://upload.url/...",
"data": {
"uuid": "attach123-e89b-12d3-a456-426614174000"
}
}
Error Codes:
- Code 2: "uuid required" - Missing uuid field
16. Get Attachments
Get all attachments for an opportunity.
Endpoint: GET /api/sales/attachments
Request:
- Query Parameters:
uuid_opportunity: Opportunity UUID (string, required)
Response:
{
"attachments": [
{
"uuid": "attach123-e89b-12d3-a456-426614174000",
"filename": "document.pdf",
"size_kb": 1024,
"user_id": 123,
"fecha_ini": "2024-01-15T10:30:00",
"uploaded": true
}
]
}
Error Codes:
- Code 2: "uuid_opportunity required" - Missing uuid_opportunity parameter
17. Associate Attachment
Associate an attachment to an opportunity.
Endpoint: POST /api/sales/attachments
Request:
{
"action": "associate",
"uuid_opportunity": "123e4567-e89b-12d3-a456-426614174000",
"uuid_attachment": "attach123-e89b-12d3-a456-426614174000"
}
Response:
{
"code": 0,
"info": "attachment associated"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
18. Dissociate Attachment
Remove an attachment from an opportunity.
Endpoint: POST /api/sales/attachments
Request:
{
"action": "dissociate",
"uuid_opportunity": "123e4567-e89b-12d3-a456-426614174000",
"uuid_attachment": "attach123-e89b-12d3-a456-426614174000"
}
Response:
{
"code": 0,
"info": "attachment dissociated"
}
Error Codes:
- Code 1: "JSON required" - Missing request body
- Code 3: "Action required" - Missing action field
Error Response Format
All error responses follow this format:
{
"res": "error",
"code": <error_code>,
"info": "<error_description>"
}
HTTP Status Codes:
- 200: Success
- 400: Bad Request (validation errors)
- 401: Unauthorized (missing or invalid JWT token)
- 403: Forbidden (insufficient permissions)
- 429: Too Many Requests (rate limit exceeded)
- 500: Internal Server Error
Permission Codes
All opportunities endpoints require specific permissions:
| Permission Code | Description |
|---|---|
| 2020 | Create opportunities |
| 2021 | Read/list opportunities and owners |
| 2022 | Update opportunities |
| 2023 | Delete opportunities |
| 2040 | Create notes |
| 2041 | Read notes |
| 2042 | Update notes |
| 2043 | Delete notes |
| 2050 | Create/associate attachments |
| 2051 | Read attachments |
| 2053 | Delete/dissociate attachments |
Business Rules
Opportunity States
- 1: Open (Abierta) - Default state when creating
- 2: Won (Ganada)
- 3: Lost (Perdida)
Opportunity Types
- 1: Purchase (Compra)
- 2: Sale (Venta)
- 3: Exchange (Canje)
Stage Management
- Opportunities can be assigned to stages or left without stage ("Sin Etapa")
- Use
uuid_stage="null"oruuid_stage="0"to filter opportunities without stage - Moving opportunities between stages updates the order automatically
- Order is managed using float-based system for efficient reordering
Ownership and Permissions
- Only the owner can delete their opportunities
- Users can see opportunities they own, opportunities from supervised users, and opportunities from collaborators
- Permission validation is performed before all operations
Soft Delete
- Opportunities, operations, notes, and attachments use soft delete (deleted_at timestamp)
- Deleted items won't appear in list or get operations
Field Mapping
| API Field | Database Field | Description |
|---|---|---|
uuid | uuid | Opportunity UUID |
name | name | Opportunity name |
uuid_account | id_account | Account reference |
id_opportunity_type | id_opportunity_type | Type ID |
id_opportunity_state | id_opportunity_state | State ID |
uuid_stage | id_stage_opportunity | Stage reference |
order | order | Position order |
start_date | start_date | Creation date |
updated_at | updated_at | Last update |
deleted_at | deleted_at | Deletion timestamp |
Usage Examples
JavaScript/Fetch Example:
// List opportunities (Kanban view)
const response = await fetch('/api/sales/opportunities/', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify({
action: 'get',
limit: 15
})
});
// Create opportunity
const createResponse = await fetch('/api/sales/opportunities/', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify({
action: 'create',
name: 'New Opportunity',
id_opportunity_type: 1,
uuid_account: '123e4567-e89b-12d3-a456-426614174000'
})
});
// Update opportunity
const updateResponse = await fetch('/api/sales/opportunities/', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify({
action: 'update',
uuid: '123e4567-e89b-12d3-a456-426614174000',
name: 'Updated Name',
id_opportunity_state: 2
})
});