The Myra REST API is a comprehensive, resource-oriented API designed to allow developers to build deep integrations, custom mobile apps, or internal business intelligence tools. It follows standard REST patterns, uses JSON for all request and response bodies, and utilizes standard HTTP status codes.
Authentication and Security
All API requests must be authenticated using a Personal Access Token (PAT).
Generating a Token
- Navigate to Settings → Developer → API Tokens.
- Click Generate New Token.
- Name the token (e.g., "Website Lead Form") and select the required Scopes (e.g.,
contacts:write,deals:read). - Copy your token immediately. For security, we never show the full token again.
Usage
Include the token in the Authorization header of every request:
curl -X GET "https://app.pulsepost.ai/api/v1/contacts" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
Base URL and Versioning
All requests should be made to:
https://app.pulsepost.ai/api/v1
We use semantic versioning. Major breaking changes will be released under a new path (e.g., /v2), while non-breaking additions (new fields or endpoints) are added to the current version.
Key Endpoints
Contacts (/contacts)
The backbone of your CRM data.
GET /contacts: List all contacts with advanced filtering and pagination.POST /contacts: Create a new contact. Supports duplicate detection logic.PATCH /contacts/{id}: Update specific fields of a contact.DELETE /contacts/{id}: Move a contact to the trash.
Deals and Pipelines (/pipelines)
Manage your sales funnel programmatically.
GET /pipelines: Retrieve your pipeline structure and stage IDs.POST /deals: Create a new deal and assign it to a contact and stage.PATCH /deals/{id}: Move a deal to a new stage or update the expected value.
Communications (/conversations)
Interact with your customers.
POST /conversations/{id}/messages: Send an outbound Email or SMS to a contact.GET /conversations/{id}/history: Retrieve the full message thread for a contact.
Pagination and Filtering
Pagination
We use cursor-based pagination for high performance on large datasets.
limit: Number of records to return (default 20, max 200).cursor: The ID provided in thenext_cursorfield of the previous response.
Filtering
Search for specific data using the filter query parameter:
GET /contacts?filter[email]=john@example.com
GET /deals?filter[stage_id]=stage_123&filter[value_gt]=1000
Rate Limits
To ensure platform stability, the API is subject to rate limiting:
- Standard: 300 requests per minute.
- Burst: Up to 50 requests in a 1-second window.
- Headers: Every response includes
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset(the time when the limit resets in UTC).
If you exceed the limit, the API returns a 429 Too Many Requests status code.
Error Handling
Myra returns descriptive error objects to help you debug quickly.
{
"error": {
"code": "validation_failed",
"message": "The provided data is invalid.",
"details": [
{ "field": "email", "issue": "Must be a valid email address" }
]
}
}
Best Practices for Developers
- Handle 429s Gracefully: Implement an exponential backoff strategy in your code to handle rate limiting.
- Use Webhooks over Polling: Instead of asking the API "Is there a new contact?" every 60 seconds, subscribe to the
contact.createdwebhook for real-time updates. - Minimize Scopes: Only grant your tokens the permissions they absolutely need.
- Idempotency: When creating records, use unique external IDs to prevent duplicate creation during network retries.
Multi-Language Code Snippets
Node.js (with fetch)
const response = await fetch('https://app.pulsepost.ai/api/v1/contacts', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.PP_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
first_name: 'Jane',
last_name: 'Doe',
email: 'jane@doe.com'
})
});
const data = await response.json();
Python (with requests)
import requests
url = "https://app.pulsepost.ai/api/v1/contacts"
headers = {"Authorization": "Bearer YOUR_TOKEN"}
payload = {"first_name": "Jane", "email": "jane@doe.com"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
