pythonpython-3.xtwiliosendgridsendgrid-api-v3

How do I get a list of Single Send campaign names from the Sendgrid API?


I want to use the SendGrid v3 API to retrieve a list of all my Single Send campaigns and their names.

According to the SendGrid API documentation, I can retrieve statistics for all my Single Sends by sending a GET request to the endpoint /v3/marketing/stats/singlesends. However, the response doesn't include the name of each SingleSend campaign, only message level data like recipient, status, and clicks.

Example Python code:

import sendgrid
import json
import os

sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.client.messages.get()
parsed_json = json.loads(response.body)
print(json.dumps(parsed_json, indent=4))

Example response

{
    "messages": [
        {
            "from_email": "email@example.com",
            "msg_id": "some-message-id-here1",
            "subject": "Message subject here",
            "to_email": "madeline@example.com",
            "status": "processing",
            "opens_count": 0,
            "clicks_count": 0,
            "last_event_time": "2025-05-14T12:00:10Z"
        },
        {
            "from_email": "email@example.com",
            "msg_id": "some-message-id-here2",
            "subject": "Message subject here",
            "to_email": "theo@example.com",
            "status": "delivered",
            "opens_count": 1,
            "clicks_count": 0,
            "last_event_time": "2025-05-14T12:00:08Z"
        }
    ]
}

There's also an endpoint for getting Single Send stats by ID, but that only helps if I already have the ID linked to a specific Single Send name.

Is there an API Endpoint or method to retrieve a list of all my Single Send campaigns and their names?


Solution

  • According to SendGrid's documentation, you can get a list of all your Single Sends and their names by sending a GET request to /v3/marketing/singlesends. The server response is limited to 100 results per page, with a link to the next page in _metadata.next when applicable.

    Example response:

    {
        "result": [
            {
                "id": "some_long_id_1",
                "name": "Name of Single Send 1",
                "status": "draft",
                "categories": [],
                "send_at": null,
                "created_at": "2025-05-14T11:00:00Z",
                "updated_at": "2025-05-14T11:30:00Z",
                "is_abtest": false,
                "abtest": null
            },
            {
                "id": "some_long_id_2",
                "name": "Name of Single Send 2",
                "status": "triggered",
                "categories": [],
                "send_at": "2025-05-10T12:00:00Z",
                "created_at": "2025-05-05T12:00:00Z",
                "updated_at": "2025-05-07T12:00:00Z",
                "is_abtest": false,
                "abtest": null
            },
            {
            ...
            }
        ],
        "_metadata": {
            "self": "https://api.sendgrid.com/v3/marketing/singlesends?page_token=SOME_TOKEN_HERE_1",
            "next": "https://api.sendgrid.com/v3/marketing/singlesends?page_token=SOME_TOKEN_HERE_2",
            "count": 159
        }
    }
    

    I didn't see a way to handle pagination in the sendgrid Python library, so I switched to using requests instead. The following Python code will retrieve a full list of Single Send campaigns.

    import requests
    import os
    import json
    
    headers = {"Authorization": f"Bearer {os.environ.get('SENDGRID_API_KEY')}"}
    all_single_sends = []
    request_url = 'https://api.sendgrid.com/v3/marketing/singlesends'
    
    # Get list of Single Send campaigns
    while True:
        response = requests.get(request_url, headers=headers)
        response_json = response.json()
    
        # Add single sends to list
        all_single_sends.extend(response_json.get('result', []))
    
        # Get extra pages
        next_page_url = response_json.get("_metadata").get("next")
        if next_page_url:
            request_url = next_page_url
        else:
            break  # No more pages
    
    print(json.dumps(all_single_sends, indent=2))