aircall-api 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ """Contact models for Aircall API."""
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class PhoneNumber(BaseModel):
8
+ """Phone number associated with a contact"""
9
+ id: int
10
+ label: Optional[str] = None
11
+ value: str
12
+
13
+
14
+ class Email(BaseModel):
15
+ """Email address associated with a contact"""
16
+ id: int
17
+ label: Optional[str] = None
18
+ value: str
19
+
20
+
21
+ class Contact(BaseModel):
22
+ """Contact resource from Aircall API"""
23
+ id: int
24
+ direct_link: str
25
+ first_name: Optional[str] = None
26
+ last_name: Optional[str] = None
27
+ company_name: Optional[str] = None
28
+ description: Optional[str] = None
29
+ information: Optional[str] = None
30
+ is_shared: bool
31
+ phone_numbers: list[PhoneNumber] = []
32
+ emails: list[Email] = []
@@ -0,0 +1,42 @@
1
+ """Content models for Aircall API."""
2
+ from typing import Literal, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class Utterance(BaseModel):
8
+ """A single sentence/utterance in a transcription"""
9
+ start_time: float
10
+ end_time: float
11
+ text: str
12
+ participant_type: Literal["external", "internal"]
13
+ user_id: Optional[int] = None
14
+ phone_number: Optional[str] = None
15
+
16
+
17
+ class Content(BaseModel):
18
+ """Content object for transcription type"""
19
+ language: Literal[
20
+ "en", "en-US", "en-GB", "en-AU",
21
+ "fr-FR", "fr",
22
+ "es-ES", "es",
23
+ "de-DE", "de",
24
+ "nl-NL", "nl",
25
+ "it-IT", "it"
26
+ ]
27
+ utterances: list[Utterance] = []
28
+
29
+
30
+ class SummaryContent(BaseModel):
31
+ """Content object for summary type"""
32
+ content: str
33
+
34
+
35
+ class TopicsContent(BaseModel):
36
+ """Content object for topics type"""
37
+ content: list[str] = []
38
+
39
+
40
+ class ActionItemsContent(BaseModel):
41
+ """Content object for action items type"""
42
+ content: str
@@ -0,0 +1,66 @@
1
+ """Conversation Intelligence models for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import Any, Literal, Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ from aircall.models.participant import Participant
8
+
9
+
10
+ class Playbook(BaseModel):
11
+ """Playbook definition object"""
12
+ # Define based on actual API response structure
13
+
14
+
15
+ class PlaybookResultTopic(BaseModel):
16
+ """Playbook topic result"""
17
+ name: str
18
+ result: Any # Define more specifically based on API structure
19
+
20
+
21
+ class ConversationIntelligence(BaseModel):
22
+ """
23
+ Conversation Intelligence object for AI entities
24
+ (Transcription, Sentiment, Topics, Summary, Action Items, Playbook Results)
25
+ """
26
+ id: int
27
+ call_id: str
28
+ call_uuid: Optional[str] = None
29
+ number_id: Optional[int] = None
30
+ participants: Optional[list[Participant]] = None
31
+ type: Optional[Literal["call", "voicemail"]] = None
32
+ content: Optional[Any] = None # Can be string, Array, or Object
33
+ call_created_at: Optional[datetime] = None
34
+ created_at: Optional[datetime] = None
35
+ created_by: Optional[int] = None
36
+ updated_at: Optional[datetime] = None
37
+ updated_by: Optional[int] = None
38
+ ai_generated: Optional[bool] = None
39
+ adherence_score: Optional[float] = None
40
+ playbook: Optional[Playbook] = None
41
+ playbook_result_topics: Optional[list[PlaybookResultTopic]] = None
42
+
43
+
44
+ class RealtimeTranscriptionUtterance(BaseModel):
45
+ """Utterance object for realtime transcription webhook"""
46
+ participant_type: Literal["internal", "external"]
47
+ user_id: Optional[int] = None
48
+ timestamp: int
49
+ duration_ms: int
50
+ text: str
51
+ language: str
52
+
53
+
54
+ class RealtimeTranscriptionCall(BaseModel):
55
+ """Call information for realtime transcription webhook"""
56
+ id: Optional[int] = None
57
+ uuid: str
58
+ number_id: int
59
+ direction: Literal["inbound", "outbound"]
60
+
61
+
62
+ class RealtimeTranscription(BaseModel):
63
+ """Realtime transcription webhook event object"""
64
+ id: str
65
+ call: RealtimeTranscriptionCall
66
+ utterances: list[RealtimeTranscriptionUtterance]
@@ -0,0 +1,21 @@
1
+ """Dialer Campaign models for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class DialerCampaignPhoneNumber(BaseModel):
9
+ """Phone number in a dialer campaign"""
10
+ id: int
11
+ number: str
12
+ called: bool
13
+ created_at: datetime
14
+
15
+
16
+ class DialerCampaign(BaseModel):
17
+ """Dialer Campaign (Power Dialer) resource"""
18
+ id: int
19
+ number_id: Optional[str] = None
20
+ created_at: datetime
21
+ phone_numbers: list[DialerCampaignPhoneNumber] = []
@@ -0,0 +1,20 @@
1
+ """Integration models for Aircall API."""
2
+ from typing import TYPE_CHECKING, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+ if TYPE_CHECKING:
7
+ from aircall.models.user import User
8
+
9
+
10
+ class Integration(BaseModel):
11
+ """Integration object representing connection state with third-party services"""
12
+ name: str
13
+ custom_name: Optional[str] = None
14
+ logo: str
15
+ company_id: int
16
+ status: str
17
+ active: bool
18
+ number_ids: list[int] = []
19
+ numbers_count: int
20
+ user: Optional["User"] = None
@@ -0,0 +1,22 @@
1
+ """IVR Option model for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class IVROption(BaseModel):
9
+ """
10
+ IVR Option object representing IVR input from Smartflow-enabled number.
11
+
12
+ Read-only. Available within call object when fetch_call_timeline=true.
13
+ Only available for calls from last 2 months.
14
+ All timestamps are in ISO 8601 format.
15
+ """
16
+ id: str
17
+ title: str
18
+ key: str
19
+ branch: Optional[str] = None
20
+ created_at: datetime
21
+ transition_started_at: datetime
22
+ transition_ended_at: datetime
@@ -0,0 +1,52 @@
1
+ """Message models for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import TYPE_CHECKING, Literal, Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ if TYPE_CHECKING:
8
+ from aircall.models.contact import Contact
9
+ from aircall.models.number import Number
10
+
11
+
12
+ class MediaDetail(BaseModel):
13
+ """Media file attached to a message"""
14
+ file_name: str
15
+ file_type: str
16
+ presigned_url: str
17
+
18
+
19
+ class Message(BaseModel):
20
+ """
21
+ Message object for SMS, MMS, and WhatsApp communications.
22
+
23
+ Read-only. Not updatable or destroyable via API.
24
+ WhatsApp-specific attributes won't be present for SMS/MMS.
25
+ """
26
+ id: str
27
+ direct_link: str
28
+ direction: Literal["inbound", "outbound"]
29
+ external_number: str
30
+ body: str
31
+ status: str
32
+ raw_digits: str
33
+ media_details: list[MediaDetail] = []
34
+ created_at: datetime
35
+ updated_at: datetime
36
+ sent_at: Optional[datetime] = None
37
+
38
+ # Channel-specific fields
39
+ channel: Optional[Literal["whatsapp"]] = None # null for SMS/MMS
40
+
41
+ # WhatsApp-specific fields
42
+ template_content: Optional[str] = None
43
+ type: Optional[str] = None
44
+ metadata: Optional[str] = None
45
+ parent_id: Optional[str] = None
46
+ whatsapp_message_category: Optional[Literal["marketing", "utility", "authentication"]] = None
47
+ whatsapp_message_type: Optional[Literal["regular", "free_entry_point", "free_customer_serivce"]] = None
48
+ recipient_country: Optional[str] = None
49
+
50
+ # Related objects
51
+ number: Optional["Number"] = None
52
+ contact: Optional["Contact"] = None
@@ -0,0 +1,55 @@
1
+ """Number models for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import Literal, Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ from aircall.models.user import User
8
+
9
+
10
+ class NumberMessages(BaseModel):
11
+ """
12
+ Music and Messages configuration for a Number.
13
+
14
+ Custom audio files can be uploaded with public URLs.
15
+ Check Aircall encoding recommendations first.
16
+ """
17
+ welcome: Optional[str] = None
18
+ waiting: Optional[str] = None
19
+ ringing_tone: Optional[str] = None
20
+ unanswered_call: Optional[str] = None # Deprecated
21
+ after_hours: Optional[str] = None
22
+ ivr: Optional[str] = None
23
+ voicemail: Optional[str] = None
24
+ closed: Optional[str] = None # Deprecated
25
+ callback_later: Optional[str] = None # Deprecated
26
+
27
+
28
+ class Number(BaseModel):
29
+ """
30
+ Number resource representing an Aircall phone number.
31
+
32
+ Numbers can be purchased and configured via Dashboard.
33
+ Note: Several fields are deprecated due to Smartflows migration.
34
+ """
35
+ id: int
36
+ direct_link: str
37
+ name: str
38
+ digits: str
39
+ e164_digits: Optional[str] = None # Only in webhook events
40
+ created_at: datetime
41
+ country: str
42
+ time_zone: str
43
+
44
+ # Deprecated: No longer updated for Smartflows
45
+ open: Optional[bool] = None
46
+
47
+ availability_status: Optional[Literal["open", "custom", "closed"]] = None
48
+
49
+ # Deprecated: No longer supported
50
+ is_ivr: Optional[bool] = None
51
+
52
+ live_recording_activated: bool
53
+ users: list["User"] = []
54
+ priority: Optional[int] = None # null, 0 (no priority), or 1 (top priority)
55
+ messages: Optional[NumberMessages] = None
@@ -0,0 +1,38 @@
1
+ """Participant models for Aircall API."""
2
+ from typing import Literal, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class Participant(BaseModel):
8
+ """
9
+ Participant in a conference call (Call Object).
10
+
11
+ Referenced as 'conference_participants' in Call APIs
12
+ and as 'participants' in call webhook events.
13
+ """
14
+ id: Optional[str] = None # Contact or User ID (not present for external)
15
+ type: Literal["user", "contact", "external"]
16
+ name: Optional[str] = None # Not present for external
17
+ phone_number: Optional[str] = None # Not present for user type
18
+
19
+
20
+ class ConversationIntelligenceParticipant(BaseModel):
21
+ """
22
+ Participant in Conversation Intelligence Object.
23
+
24
+ Used in transcription and sentiment events.
25
+ """
26
+ participant_type: Literal["internal", "external", "ai_voice_agent"]
27
+
28
+ # Not present for internal or ai_voice_agent
29
+ phone_number: Optional[str] = None
30
+
31
+ # Sentiment value (only for sentiment.created event)
32
+ value: Optional[Literal["NEUTRAL", "POSITIVE", "NEGATIVE"]] = None
33
+
34
+ # User ID (only for transcription.created, not for external/ai_voice_agent)
35
+ user_id: Optional[str] = None
36
+
37
+ # AI Voice Agent ID (only for transcription.created, only for ai_voice_agent type)
38
+ ai_voice_agent_id: Optional[str] = None
aircall/models/tag.py ADDED
@@ -0,0 +1,18 @@
1
+ """Tag models for Aircall API."""
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class Tag(BaseModel):
8
+ """
9
+ Tag resource for categorizing calls.
10
+
11
+ Can be created by Admins in Dashboard or via API.
12
+ Emojis cannot be used in Tag attributes (will be removed).
13
+ """
14
+ id: int
15
+ direct_link: str
16
+ name: str
17
+ color: str # Hexadecimal format (e.g., "#FF5733")
18
+ description: Optional[str] = None
aircall/models/team.py ADDED
@@ -0,0 +1,20 @@
1
+ """Team models for Aircall API."""
2
+ from datetime import datetime
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from aircall.models.user import User
7
+
8
+
9
+ class Team(BaseModel):
10
+ """
11
+ Team resource for grouping users.
12
+
13
+ Teams are used in call distributions of Numbers.
14
+ Name must be unique in a company (max 64 characters).
15
+ """
16
+ id: int
17
+ direct_link: str
18
+ name: str # Max 64 characters, must be unique in company
19
+ created_at: datetime
20
+ users: list[User] = []
aircall/models/user.py ADDED
@@ -0,0 +1,48 @@
1
+ """User models for Aircall API."""
2
+ from datetime import datetime
3
+ from typing import TYPE_CHECKING, Literal, Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ if TYPE_CHECKING:
8
+ from aircall.models.number import Number
9
+
10
+
11
+ class User(BaseModel):
12
+ """
13
+ User resource representing an Aircall user.
14
+
15
+ Users can be Admins (Dashboard + Phone app access) or Agents (Phone app only).
16
+ Users are assigned to Numbers.
17
+ """
18
+ id: int
19
+ direct_link: str
20
+ name: str # Result of first_name + last_name
21
+ email: str
22
+ created_at: datetime
23
+
24
+ # Availability fields
25
+ available: bool # Based on working hours
26
+ availability_status: Literal["available", "custom", "unavailable"]
27
+ substatus: str # always_open, always_closed, or specific reason
28
+
29
+ # Related resources
30
+ numbers: list["Number"] = []
31
+
32
+ # Settings
33
+ time_zone: str # Default: Etc/UTC
34
+ language: str # IETF language tag, default: en-US
35
+ wrap_up_time: int # Timer after call ends (seconds)
36
+
37
+
38
+ class UserAvailability(BaseModel):
39
+ """
40
+ Granular availability status for a user.
41
+
42
+ Use the dedicated endpoint to retrieve these statuses.
43
+ """
44
+ available: Optional[bool] = None # Ready to answer calls
45
+ offline: Optional[bool] = None # Not online
46
+ do_not_disturb: Optional[bool] = None # DND toggled
47
+ in_call: Optional[bool] = None # Currently on a call
48
+ after_call_work: Optional[bool] = None # Tagging/wrapping up
@@ -0,0 +1,22 @@
1
+ """Webhook Model File"""
2
+ from datetime import datetime
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+
8
+ class Webhook(BaseModel):
9
+ """
10
+ Webhook resource for receiving event notifications.
11
+
12
+ Composed of a custom_name and list of events.
13
+ Use the token field to identify which Aircall account sent the webhook.
14
+ """
15
+ webhook_id: str = Field(..., description="UUID identifier for the webhook")
16
+ direct_link: str
17
+ created_at: datetime
18
+ custom_name: str = "Webhook" # Default value
19
+ url: str # Valid URL to web server
20
+ active: bool = True # Default is true
21
+ token: str # Unique token for authentication
22
+ events: list[str] = [] # List of registered event names
@@ -0,0 +1,29 @@
1
+ """Aircall API resource classes."""
2
+
3
+ from aircall.resources.base import BaseResource
4
+ from aircall.resources.call import CallResource
5
+ from aircall.resources.company import CompanyResource
6
+ from aircall.resources.contact import ContactResource
7
+ from aircall.resources.dialer_campaign import DialerCampaignResource
8
+ from aircall.resources.integration import IntegrationResource
9
+ from aircall.resources.message import MessageResource
10
+ from aircall.resources.number import NumberResource
11
+ from aircall.resources.tag import TagResource
12
+ from aircall.resources.team import TeamResource
13
+ from aircall.resources.user import UserResource
14
+ from aircall.resources.webhook import WebhookResource
15
+
16
+ __all__ = [
17
+ "BaseResource",
18
+ "CallResource",
19
+ "CompanyResource",
20
+ "ContactResource",
21
+ "DialerCampaignResource",
22
+ "IntegrationResource",
23
+ "MessageResource",
24
+ "NumberResource",
25
+ "TagResource",
26
+ "TeamResource",
27
+ "UserResource",
28
+ "WebhookResource",
29
+ ]
@@ -0,0 +1,77 @@
1
+ """Base resource class for all Aircall API resources."""
2
+
3
+ import logging
4
+
5
+
6
+ class BaseResource:
7
+ """
8
+ Base class for all API resource classes.
9
+
10
+ Provides common functionality for making API requests and helper methods
11
+ that all resource classes can use.
12
+ """
13
+
14
+ def __init__(self, client):
15
+ """
16
+ Initialize the resource with a client instance.
17
+
18
+ Args:
19
+ client: AircallClient instance
20
+ """
21
+ self._client = client
22
+ self._logger = logging.getLogger(f'aircall.resources.{self.__class__.__name__}')
23
+
24
+ def _get(self, endpoint: str, params: dict = None, **kwargs) -> dict:
25
+ """
26
+ Make a GET request.
27
+
28
+ Args:
29
+ endpoint: API endpoint
30
+ params: Query parameters
31
+ **kwargs: Additional arguments passed to _request()
32
+
33
+ Returns:
34
+ dict: Parsed JSON response
35
+ """
36
+ return self._client._request("GET", endpoint, params=params, **kwargs)
37
+
38
+ def _post(self, endpoint: str, json: dict = None, **kwargs) -> dict:
39
+ """
40
+ Make a POST request.
41
+
42
+ Args:
43
+ endpoint: API endpoint
44
+ json: Request body
45
+ **kwargs: Additional arguments passed to _request()
46
+
47
+ Returns:
48
+ dict: Parsed JSON response
49
+ """
50
+ return self._client._request("POST", endpoint, json=json, **kwargs)
51
+
52
+ def _put(self, endpoint: str, json: dict = None, **kwargs) -> dict:
53
+ """
54
+ Make a PUT request.
55
+
56
+ Args:
57
+ endpoint: API endpoint
58
+ json: Request body
59
+ **kwargs: Additional arguments passed to _request()
60
+
61
+ Returns:
62
+ dict: Parsed JSON response
63
+ """
64
+ return self._client._request("PUT", endpoint, json=json, **kwargs)
65
+
66
+ def _delete(self, endpoint: str, **kwargs) -> dict:
67
+ """
68
+ Make a DELETE request.
69
+
70
+ Args:
71
+ endpoint: API endpoint
72
+ **kwargs: Additional arguments passed to _request()
73
+
74
+ Returns:
75
+ dict: Parsed JSON response
76
+ """
77
+ return self._client._request("DELETE", endpoint, **kwargs)