Skip to main content
Contacts

Endpoints

Available endpoints for managing contact records.
MethodPathDescription
GET/api/contacts/List contacts
POST/api/contacts/Create a contact
GET/api/contacts/{id}/Get a contact
PATCH/api/contacts/{id}/Update a contact
DELETE/api/contacts/{id}/Delete a contact

Contacts

List Contacts

GET /api/contacts/
Authorization: Bearer <token>
Retrieve a paginated list of contacts with filtering and search support.
Query Parameters:
ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
stagestringFilter by stage (e.g., engaged, customer)
assignedTostringFilter by assigned user ID
searchstringSearch by name, email, or phone
createdAfterISO8601Filter contacts created after this date
createdBeforeISO8601Filter contacts created before this date
tagsstringComma-separated tag names to filter by
Response:
{
  "count": 52,
  "next": "https://api.parsalink.io/api/contacts/?page=2",
  "previous": null,
  "results": [
    {
      "id": "cnt_01HX...",
      "firstName": "John",
      "lastName": "Smith",
      "email": "[email protected]",
      "phone": "+15551234567",
      "title": "VP of Sales",
      "stage": "engaged",
      "accountId": "acc_01HX...",
      "accountName": "Acme Corp",
      "assignedTo": "usr_01HX...",
      "tags": ["enterprise", "warm"],
      "createdAt": "2025-01-15T10:30:00Z",
      "updatedAt": "2025-03-20T14:22:00Z"
    }
  ]
}

Creation

Create a Contact

POST /api/contacts/
Authorization: Bearer <token>
Content-Type: application/json
Create a new contact with profile, account linkage, and tags.
Request body:
{
  "firstName": "Sarah",
  "lastName": "Kim",
  "email": "[email protected]",
  "phone": "+15559876543",
  "title": "Engineering Manager",
  "stage": "new",
  "accountId": "acc_01HX...",
  "assignedTo": "usr_01HX...",
  "tags": ["saas", "inbound"],
  "notes": "Met at SaaStr conference"
}
Required fields: firstName or lastName (at least one), email Response: 201 Created with the full contact object.
Contact Details

Get a Contact

GET /api/contacts/{id}/
Authorization: Bearer <token>
Retrieve full contact profile including ownership and activity flags.
Response:
{
  "id": "cnt_01HX...",
  "firstName": "Sarah",
  "lastName": "Kim",
  "email": "[email protected]",
  "phone": "+15559876543",
  "title": "Engineering Manager",
  "stage": "new",
  "accountId": "acc_01HX...",
  "accountName": "TechCorp",
  "assignedTo": "usr_01HX...",
  "assignedToName": "Alex Johnson",
  "tags": ["saas", "inbound"],
  "emailOptOut": false,
  "emailBounced": false,
  "notes": "Met at SaaStr conference",
  "createdAt": "2025-03-01T09:00:00Z",
  "updatedAt": "2025-03-01T09:00:00Z"
}

Updates

Update a Contact

Use PATCH to update specific fields without affecting the rest.
PATCH /api/contacts/{id}/
Authorization: Bearer <token>
Content-Type: application/json
Update contact attributes such as stage, owner, or tags.
Request body (any subset of writable fields):
{
  "stage": "engaged",
  "assignedTo": "usr_02HX...",
  "tags": ["saas", "inbound", "qualified"]
}
Response: 200 OK with the updated contact object.
Deletion

Delete a Contact

DELETE /api/contacts/{id}/
Authorization: Bearer <token>
Permanently remove a contact and its associated records.
Response: 204 No Content Deleting a contact removes the record and all associated notes and tasks. Activities logged on the contact’s timeline are retained in the audit log but no longer accessible through the contact record.
Stages

Contact Stage Values

ValueLabel
newNew
contactedContacted
engagedEngaged
proposal_sentProposal Sent
negotiationNegotiation
customerCustomer
inactiveInactive

Async CSV Import

For bulk imports of more than a few hundred rows, use the async import endpoints. The synchronous unified-import endpoint stays available for small CSVs and other file types (vCard, image, PDF) but will gateway-time-out on large CSVs.

Start an Import

POST /api/crm/contacts/import/start/
Content-Type: multipart/form-data
FormData fields
FieldRequiredDescription
fileyesThe CSV file (.csv only)
source_uidnoUID of a Source to stamp on every created contact
field_mappingsnoJSON string mapping unknown CSV column headers to schema fields
Limits
  • 10 MB CSV body cap
  • One job per request
  • File must be UTF-8 (falls back to latin-1 if UTF-8 decode fails)
Success response (202 Accepted)
{
  "uid": "fd8b9b8e-…",
  "status": "queued",
  "filename": "leads.csv"
}
The job is queued for background processing. Poll the detail endpoint to follow progress.

Poll a Job

GET /api/crm/contacts/import-jobs/{job_uid}/
Success response (200)
{
  "uid": "fd8b9b8e-…",
  "filename": "leads.csv",
  "status": "complete",
  "progressPercent": 100,
  "totalRows": 250,
  "processedRows": 250,
  "successCount": 247,
  "errorCount": 3,
  "errors": [
    { "row": 14, "message": "Invalid email format" }
  ],
  "duplicates": [  ],
  "errorMessage": "",
  "sourceName": "Trade Show",
  "createdAt": "2026-06-08T10:01:16Z",
  "startedAt": "2026-06-08T10:01:18Z",
  "finishedAt": "2026-06-08T10:02:04Z"
}
Status values
StatusMeaning
queuedIn the Celery queue, hasn’t started
processingWorker is currently importing rows
completeFinished — check successCount and errorCount
failedThrew an error; errorMessage carries the reason
Poll every 1–2 seconds during active runs. Stop polling once status is complete or failed.

List Recent Jobs

GET /api/crm/contacts/import-jobs/
Returns the last 50 jobs for the authenticated user’s tenant, most recent first. Same shape as the detail endpoint, but the response is an array. Useful for surfacing a “Recent Imports” panel in your UI without needing to track job UIDs yourself.