Deals API
The Deals API allows you to manage sales opportunities and pipeline in your ISAO system. You can list, create, update deals and track their progress through your sales process.
📋 Table of Contents
- Authentication
- Endpoints Overview
- Deal Object Structure
- List Deals
- Get Deal by ID
- Create Deal
- Update Deal Status
- Filtering and Search
- Error Handling
- Code Examples
🔐 Authentication
All deals endpoints require the deals:read or deals:write permissions:
- Read operations:
deals:readpermission - Write operations:
deals:writepermission
Authorization: Bearer YOUR_API_KEY
🔗 Endpoints Overview
| Method | Endpoint | Permission | Description |
|---|---|---|---|
GET | /deals | deals:read | List all deals with pagination and filtering |
GET | /deals/:id | deals:read | Get specific deal by ID |
POST | /deals | deals:write | Create new deal |
PUT | /deals/:id/status | deals:write | Update deal status and stage |
Base URL: https://staging.isao.io/api/external
📊 Deal Object Structure
{
"id": "deal_123",
"title": "Enterprise Software License",
"description": "Annual software license for 500 users",
"value": 50000.00,
"currency": "EUR",
"stage": "negotiation",
"priority": "high",
"probability": 75,
"status": "open",
"expectedCloseDate": "2024-12-15T00:00:00.000Z",
"actualCloseDate": null,
"source": "website",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com",
"phoneNumber": "+33123456789",
"currentCompany": "Tech Corp"
},
"assignedTo": {
"id": "user_789",
"name": "Sales Rep",
"email": "sales@isao.io"
},
"createdAt": "2024-11-01T10:30:00.000Z",
"updatedAt": "2024-11-08T09:15:00.000Z"
}
Deal Status Values
open: Deal is active and in progresswon: Deal was successfully closedlost: Deal was lost or abandoned
Priority Values
low: Low priority dealmedium: Medium priority deal (default)high: High priority deal
📑 List Deals
Retrieve a paginated list of deals from your company.
Request
GET /deals
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (minimum: 1) |
limit | integer | 50 | Items per page (maximum: 200) |
status | string | - | Filter by status: open, won, lost |
stage | string | - | Filter by deal stage |
createdSince | string | - | ISO 8601 date, deals created after this date |
updatedSince | string | - | ISO 8601 date, deals updated after this date |
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?status=open&stage=negotiation&limit=10"
Response
{
"success": true,
"data": [
{
"id": "deal_123",
"title": "Enterprise Software License",
"value": 50000.00,
"currency": "EUR",
"stage": "negotiation",
"priority": "high",
"probability": 75,
"status": "open",
"expectedCloseDate": "2024-12-15T00:00:00.000Z",
"actualCloseDate": null,
"description": "Annual software license for 500 users",
"source": "website",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com",
"phoneNumber": "+33123456789",
"currentCompany": "Tech Corp"
},
"assignedTo": {
"id": "user_789",
"name": "Sales Rep",
"email": "sales@isao.io"
},
"createdAt": "2024-11-01T10:30:00.000Z",
"updatedAt": "2024-11-08T09:15:00.000Z"
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 1,
"totalPages": 1
}
}
💰 Get Deal by ID
Retrieve a specific deal by its ID.
Request
GET /deals/:id
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://staging.isao.io/api/external/deals/deal_123
Response
{
"success": true,
"data": {
"id": "deal_123",
"title": "Enterprise Software License",
"value": 50000.00,
"currency": "EUR",
"stage": "negotiation",
"priority": "high",
"probability": 75,
"status": "open",
"expectedCloseDate": "2024-12-15T00:00:00.000Z",
"actualCloseDate": null,
"description": "Annual software license for 500 users",
"source": "website",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com",
"phoneNumber": "+33123456789",
"currentCompany": "Tech Corp"
},
"assignedTo": {
"id": "user_789",
"name": "Sales Rep",
"email": "sales@isao.io"
},
"createdAt": "2024-11-01T10:30:00.000Z",
"updatedAt": "2024-11-08T09:15:00.000Z"
}
}
➕ Create Deal
Create a new deal in your sales pipeline.
Request
POST /deals
Content-Type: application/json
Required Fields
| Field | Type | Description |
|---|---|---|
title | string | Deal title (max 255 chars) |
value | number | Deal value (minimum: 0) |
Optional Fields
| Field | Type | Description |
|---|---|---|
description | string | Deal description |
currency | string | Currency code (default: "EUR") |
stage | string | Deal stage in your pipeline |
priority | string | low, medium (default), high |
probability | number | Success probability 0-100% |
expectedCloseDate | string | Expected close date (ISO 8601 format) |
source | string | Deal source (e.g., "website", "referral") |
contactId | string | Associated contact ID |
assignedToId | string | Assigned user ID |
Example Request
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Website Redesign Project",
"description": "Complete website redesign and development",
"value": 25000,
"currency": "EUR",
"stage": "proposal",
"priority": "medium",
"probability": 60,
"expectedCloseDate": "2024-12-30",
"source": "website",
"contactId": "contact_456"
}' \
https://staging.isao.io/api/external/deals
Success Response (201 Created)
{
"success": true,
"data": {
"id": "deal_789",
"title": "Website Redesign Project",
"value": 25000,
"currency": "EUR",
"stage": "proposal",
"priority": "medium",
"probability": 60,
"status": "open",
"expectedCloseDate": "2024-12-30T00:00:00.000Z",
"description": "Complete website redesign and development",
"source": "website",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com",
"phoneNumber": "+33123456789",
"currentCompany": "Tech Corp"
},
"assignedTo": null,
"createdAt": "2024-11-08T10:30:00.000Z",
"updatedAt": "2024-11-08T10:30:00.000Z"
}
}
Error Response (400 Bad Request)
If the associated contact doesn't exist:
{
"success": false,
"error": "Contact not found or does not belong to your company"
}
📈 Update Deal Status
Update a deal's status, stage, or close date.
Request
PUT /deals/:id/status
Content-Type: application/json
Fields
| Field | Type | Description |
|---|---|---|
status | string | New status: open, won, lost |
stage | string | New stage in your pipeline |
actualCloseDate | string | Actual close date (ISO 8601) for won/lost deals |
Example Request - Mark Deal as Won
curl -X PUT \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "won",
"stage": "closed-won",
"actualCloseDate": "2024-11-08T15:30:00.000Z"
}' \
https://staging.isao.io/api/external/deals/deal_789/status
Example Request - Update Stage
curl -X PUT \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage": "contract-review"
}' \
https://staging.isao.io/api/external/deals/deal_789/status
Response
{
"success": true,
"data": {
"id": "deal_789",
"title": "Website Redesign Project",
"value": 25000,
"currency": "EUR",
"stage": "closed-won",
"priority": "medium",
"probability": 60,
"status": "won",
"expectedCloseDate": "2024-12-30T00:00:00.000Z",
"actualCloseDate": "2024-11-08T15:30:00.000Z",
"description": "Complete website redesign and development",
"source": "website",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com",
"phoneNumber": "+33123456789",
"currentCompany": "Tech Corp"
},
"assignedTo": null,
"createdAt": "2024-11-08T10:30:00.000Z",
"updatedAt": "2024-11-08T15:30:00.000Z"
}
}
🔍 Filtering and Search
The deals API provides powerful filtering capabilities.
Filter by Status
Get only open deals:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?status=open"
Filter by Stage
Get deals in specific stage:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?stage=negotiation"
Filter by Date Range
Get deals created since a specific date:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?createdSince=2024-11-01T00:00:00.000Z"
Get deals updated in the last week:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?updatedSince=2024-11-01T00:00:00.000Z"
Combined Filtering
Combine multiple filters:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/deals?status=open&stage=proposal&createdSince=2024-11-01T00:00:00.000Z"
❌ Error Handling
Common Error Responses
401 Unauthorized
{
"success": false,
"error": "API key required in Authorization header",
"message": "Please provide a valid API key in the format: Authorization: Bearer YOUR_API_KEY"
}
403 Forbidden
{
"success": false,
"error": "Permission denied: deals:read required",
"message": "This API key does not have the required permission: deals:read",
"requiredPermission": "deals:read",
"availablePermissions": ["contacts:read", "contacts:write"]
}
404 Not Found
{
"success": false,
"error": "Deal not found"
}
422 Validation Error
{
"success": false,
"error": "Validation failed",
"details": {
"title": "Title is required",
"value": "Value must be a positive number"
}
}
💻 Code Examples
JavaScript/Node.js
const axios = require('axios');
class DealsAPI {
constructor(apiKey) {
this.client = axios.create({
baseURL: 'https://staging.isao.io/api/external',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
});
}
// List all deals with filtering
async listDeals(options = {}) {
const params = {
page: options.page || 1,
limit: options.limit || 50,
status: options.status,
stage: options.stage,
createdSince: options.createdSince,
updatedSince: options.updatedSince
};
const response = await this.client.get('/deals', { params });
return response.data;
}
// Get deal by ID
async getDeal(dealId) {
const response = await this.client.get(`/deals/${dealId}`);
return response.data;
}
// Create new deal
async createDeal(dealData) {
const response = await this.client.post('/deals', dealData);
return response.data;
}
// Update deal status
async updateDealStatus(dealId, statusData) {
const response = await this.client.put(`/deals/${dealId}/status`, statusData);
return response.data;
}
// Mark deal as won
async markDealAsWon(dealId, closeDate = new Date().toISOString()) {
return this.updateDealStatus(dealId, {
status: 'won',
actualCloseDate: closeDate
});
}
// Mark deal as lost
async markDealAsLost(dealId, closeDate = new Date().toISOString()) {
return this.updateDealStatus(dealId, {
status: 'lost',
actualCloseDate: closeDate
});
}
// Get deals by status
async getDealsByStatus(status, limit = 50) {
return this.listDeals({ status, limit });
}
// Get deals in pipeline (open deals)
async getPipelineDeals() {
return this.listDeals({ status: 'open' });
}
}
// Usage example
const dealsAPI = new DealsAPI(process.env.ISAO_API_KEY);
async function example() {
try {
// Create a deal
const newDeal = await dealsAPI.createDeal({
title: "Mobile App Development",
description: "Native iOS and Android app development",
value: 75000,
currency: "EUR",
stage: "discovery",
priority: "high",
probability: 40,
expectedCloseDate: "2024-12-31",
source: "referral",
contactId: "contact_123"
});
console.log('Created deal:', newDeal);
// List pipeline deals
const pipelineDeals = await dealsAPI.getPipelineDeals();
console.log('Pipeline deals:', pipelineDeals);
// Update deal stage
const updatedDeal = await dealsAPI.updateDealStatus(newDeal.data.id, {
stage: "proposal",
probability: 60
});
console.log('Updated deal:', updatedDeal);
// Mark deal as won
const wonDeal = await dealsAPI.markDealAsWon(newDeal.data.id);
console.log('Won deal:', wonDeal);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
Python
import requests
from typing import Optional, Dict, List
from datetime import datetime
class DealsAPI:
def __init__(self, api_key: str):
self.base_url = "https://staging.isao.io/api/external"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def list_deals(self, page: int = 1, limit: int = 50,
status: Optional[str] = None,
stage: Optional[str] = None,
created_since: Optional[str] = None,
updated_since: Optional[str] = None) -> Dict:
params = {
"page": page,
"limit": limit,
"status": status,
"stage": stage,
"createdSince": created_since,
"updatedSince": updated_since
}
# Remove None values
params = {k: v for k, v in params.items() if v is not None}
response = requests.get(f"{self.base_url}/deals",
headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def get_deal(self, deal_id: str) -> Dict:
response = requests.get(f"{self.base_url}/deals/{deal_id}",
headers=self.headers)
response.raise_for_status()
return response.json()
def create_deal(self, deal_data: Dict) -> Dict:
response = requests.post(f"{self.base_url}/deals",
json=deal_data, headers=self.headers)
response.raise_for_status()
return response.json()
def update_deal_status(self, deal_id: str, status_data: Dict) -> Dict:
response = requests.put(f"{self.base_url}/deals/{deal_id}/status",
json=status_data, headers=self.headers)
response.raise_for_status()
return response.json()
def mark_deal_as_won(self, deal_id: str, close_date: Optional[str] = None) -> Dict:
if close_date is None:
close_date = datetime.now().isoformat()
return self.update_deal_status(deal_id, {
"status": "won",
"actualCloseDate": close_date
})
def mark_deal_as_lost(self, deal_id: str, close_date: Optional[str] = None) -> Dict:
if close_date is None:
close_date = datetime.now().isoformat()
return self.update_deal_status(deal_id, {
"status": "lost",
"actualCloseDate": close_date
})
def get_deals_by_status(self, status: str, limit: int = 50) -> Dict:
return self.list_deals(status=status, limit=limit)
def get_pipeline_deals(self) -> Dict:
"""Get all open deals in the pipeline"""
return self.list_deals(status="open")
# Usage example
import os
deals_api = DealsAPI(os.getenv("ISAO_API_KEY"))
try:
# Create a deal
new_deal = deals_api.create_deal({
"title": "E-commerce Platform",
"description": "Custom e-commerce solution with integrations",
"value": 120000,
"currency": "EUR",
"stage": "qualification",
"priority": "high",
"probability": 50,
"expectedCloseDate": "2025-02-28",
"source": "website",
"contactId": "contact_456"
})
print("Created deal:", new_deal)
# List pipeline deals
pipeline = deals_api.get_pipeline_deals()
print(f"Pipeline has {pipeline['meta']['total']} open deals")
# Get won deals from this month
won_deals = deals_api.get_deals_by_status("won", limit=100)
print(f"Won {len(won_deals['data'])} deals")
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e.response.status_code}")
print(f"Error details: {e.response.json()}")
PHP
<?php
class DealsAPI {
private $baseUrl = 'https://staging.isao.io/api/external';
private $headers;
public function __construct($apiKey) {
$this->headers = [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
];
}
private function makeRequest($method, $endpoint, $data = null, $params = []) {
$url = $this->baseUrl . $endpoint;
if (!empty($params)) {
$url .= '?' . http_build_query(array_filter($params));
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $this->headers,
]);
if ($data) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$result = json_decode($response, true);
if ($httpCode >= 400) {
throw new Exception("API Error ({$httpCode}): " . ($result['error'] ?? 'Unknown error'));
}
return $result;
}
public function listDeals($options = []) {
$params = [
'page' => $options['page'] ?? 1,
'limit' => $options['limit'] ?? 50,
'status' => $options['status'] ?? null,
'stage' => $options['stage'] ?? null,
'createdSince' => $options['createdSince'] ?? null,
'updatedSince' => $options['updatedSince'] ?? null
];
return $this->makeRequest('GET', '/deals', null, $params);
}
public function getDeal($dealId) {
return $this->makeRequest('GET', "/deals/{$dealId}");
}
public function createDeal($dealData) {
return $this->makeRequest('POST', '/deals', $dealData);
}
public function updateDealStatus($dealId, $statusData) {
return $this->makeRequest('PUT', "/deals/{$dealId}/status", $statusData);
}
public function markDealAsWon($dealId, $closeDate = null) {
if ($closeDate === null) {
$closeDate = date('c'); // ISO 8601 format
}
return $this->updateDealStatus($dealId, [
'status' => 'won',
'actualCloseDate' => $closeDate
]);
}
public function markDealAsLost($dealId, $closeDate = null) {
if ($closeDate === null) {
$closeDate = date('c'); // ISO 8601 format
}
return $this->updateDealStatus($dealId, [
'status' => 'lost',
'actualCloseDate' => $closeDate
]);
}
public function getDealsByStatus($status, $limit = 50) {
return $this->listDeals(['status' => $status, 'limit' => $limit]);
}
public function getPipelineDeals() {
return $this->listDeals(['status' => 'open']);
}
}
// Usage example
try {
$dealsAPI = new DealsAPI(getenv('ISAO_API_KEY'));
// Create a deal
$newDeal = $dealsAPI->createDeal([
'title' => 'Digital Marketing Campaign',
'description' => '6-month digital marketing strategy and execution',
'value' => 45000,
'currency' => 'EUR',
'stage' => 'proposal',
'priority' => 'medium',
'probability' => 70,
'expectedCloseDate' => '2024-12-15',
'source' => 'referral',
'contactId' => 'contact_789'
]);
echo "Created deal: " . json_encode($newDeal) . "\n";
// List pipeline deals
$pipeline = $dealsAPI->getPipelineDeals();
echo "Pipeline has " . $pipeline['meta']['total'] . " open deals\n";
// Mark deal as won
$wonDeal = $dealsAPI->markDealAsWon($newDeal['data']['id']);
echo "Marked deal as won: " . json_encode($wonDeal) . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
🔔 Webhook Events
When deals are created or updated, webhook events are triggered for real-time integrations:
Available Events
deal.created- When a new deal is createddeal.updated- When a deal is updateddeal.stage_changed- When a deal moves to a new stagedeal.won- When a deal is marked as wondeal.lost- When a deal is marked as lost
Example Webhook Payload
{
"event": "deal.won",
"data": {
"id": "deal_789",
"title": "Website Redesign Project",
"value": 25000,
"currency": "EUR",
"stage": "closed-won",
"status": "won",
"wonAt": "2024-11-08T15:30:00.000Z",
"contact": {
"id": "contact_456",
"name": "John Smith",
"email": "john@techcorp.com"
}
}
}
🔗 Related Documentation
- Authentication - API key setup and security
- Contacts API - Link deals to customer contacts
- Webhooks - Real-time deal notifications
- Error Handling - Comprehensive error reference
✅ Best Practices
- Link deals to contacts for better relationship tracking
- Use meaningful stage names that reflect your sales process
- Set realistic probabilities to improve forecast accuracy
- Track expected close dates for pipeline management
- Use webhooks for real-time deal updates in your CRM
- Set appropriate currencies for international deals
- Monitor deal progression through stage changes