Back

Step by Step Guide to Building a Teamleader API Integration in Python

Aug 15, 20246 minute read

Introduction

Hey there, fellow developer! Ready to dive into the world of Teamleader API integration? You're in for a treat. We'll be building a robust Python integration that'll have you managing contacts, deals, and invoices like a pro. Let's get cracking!

Prerequisites

Before we jump in, make sure you've got:

  • A Python environment (3.6+ recommended)
  • requests library installed (pip install requests)
  • Your Teamleader API credentials (if you don't have them, grab 'em from your Teamleader account)

Authentication

First things first, let's get you authenticated:

import requests def get_access_token(client_id, client_secret, code): url = "https://app.teamleader.eu/oauth2/access_token" data = { "client_id": client_id, "client_secret": client_secret, "code": code, "grant_type": "authorization_code" } response = requests.post(url, data=data) return response.json()["access_token"] # Use this to refresh your token when needed def refresh_token(client_id, client_secret, refresh_token): # Similar to get_access_token, but use "refresh_token" grant type pass

Basic API Request Structure

Now that we're authenticated, let's set up our basic request structure:

BASE_URL = "https://api.teamleader.eu" def make_request(endpoint, method="GET", data=None, params=None): url = f"{BASE_URL}/{endpoint}" headers = {"Authorization": f"Bearer {access_token}"} response = requests.request(method, url, headers=headers, json=data, params=params) response.raise_for_status() return response.json()

Core API Operations

Let's put our make_request function to work:

# GET request contacts = make_request("contacts.list") # POST request new_contact = make_request("contacts.add", method="POST", data={"name": "John Doe"}) # DELETE request make_request(f"contacts.delete", method="DELETE", data={"id": contact_id})

Handling Pagination

Teamleader uses cursor-based pagination. Here's how to handle it:

def get_all_pages(endpoint, params=None): all_data = [] while True: response = make_request(endpoint, params=params) all_data.extend(response["data"]) if not response.get("meta", {}).get("pagination", {}).get("next_cursor"): break params["cursor"] = response["meta"]["pagination"]["next_cursor"] return all_data

Error Handling and Rate Limiting

Always be prepared for errors and respect those rate limits:

import time def make_request_with_retry(endpoint, max_retries=3, **kwargs): for attempt in range(max_retries): try: return make_request(endpoint, **kwargs) except requests.exceptions.HTTPError as e: if e.response.status_code == 429: # Too Many Requests retry_after = int(e.response.headers.get("Retry-After", 5)) time.sleep(retry_after) elif attempt == max_retries - 1: raise

Data Processing

Let's process that data:

import pandas as pd def contacts_to_dataframe(contacts): return pd.DataFrame([ { "id": contact["id"], "name": contact["name"], "email": contact.get("email", {}).get("email", ""), "phone": contact.get("telephones", [{}])[0].get("number", "") } for contact in contacts ])

Building Reusable Functions

Time to wrap it all up in some handy functions:

def get_all_contacts(): return get_all_pages("contacts.list") def create_invoice(customer_id, items): return make_request("invoices.add", method="POST", data={ "customer": {"type": "customer", "id": customer_id}, "invoice_lines": items })

Example Use Cases

Let's put it all together:

# Fetch and process contacts contacts = get_all_contacts() contact_df = contacts_to_dataframe(contacts) # Create an invoice invoice = create_invoice("customer_123", [ {"description": "Web Development", "price": 1000, "quantity": 1} ])

Testing and Debugging

Always test your code! Here's a simple unit test:

import unittest from unittest.mock import patch class TestTeamleaderAPI(unittest.TestCase): @patch('requests.request') def test_get_contacts(self, mock_request): mock_request.return_value.json.return_value = {"data": [{"id": "1", "name": "Test"}]} contacts = get_all_contacts() self.assertEqual(len(contacts), 1) self.assertEqual(contacts[0]["name"], "Test")

Best Practices and Optimization

  • Cache frequently accessed data to reduce API calls
  • Use asynchronous requests for better performance when dealing with multiple API calls

Conclusion

And there you have it! You've just built a solid Teamleader API integration in Python. Remember, this is just the beginning - there's so much more you can do with the Teamleader API. Keep exploring, keep coding, and most importantly, have fun with it!

For more details, check out the official Teamleader API documentation. Now go forth and automate all the things!