Welcome to Loriginal Closer API
Create an API key to get started.
Pagination and errors
Lists return 20 items by default. Set limit to 1–100. Pass pagination.next_cursor as after for the next page, keeping the same filters and limit. Stop when the cursor is null, even if a page is empty.
Successful responses use data. Errors include error.code and error.message explaining what failed.
List campaigns
#Get your campaigns. Later, to add leads, you might need the campaign ids that this query returns.
/campaignscurl --request GET \
--url 'https://closer.loriginal.org/api/v1/campaigns' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": [
{
"id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"name": "Follow-up",
"status": "draft",
"total_leads": 1,
"created_at": "2026-09-07T14:00:00Z",
"updated_at": "2026-09-07T14:00:00Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}Add lead
#Add a lead to an existing campaign. The only required field is phone.
/campaigns/{id}/leadsReplace {id} with a campaign ID. Use a phone number with its country code, such as +14165550123. If the campaign is running, the lead will be called within 1 minute if the pace is set to ASAP in the campaign settings; or sometime later during the day otherwise. If the campaign is stopped, the lead will be processed once the campaign starts.
If the lead already exists, their call cycle will be restarted, meaning they might get another call.
Optional fields
| Field | Description |
|---|---|
first_name / last_name | Contact name. Up to 100 characters each. |
email | Email address. Up to 254 characters. |
company | Company name. Up to 200 characters. |
external_id | Your CRM or contact ID. Up to 200 characters. |
notes / other | Extra context for the agent. Up to 5,000 characters each. |
language | Language code, such as en or fr_ca. New leads default to en. |
verify_lead | Set true for a paid Twilio phone lookup before adding. Defaults to false. Unreachable numbers are excluded from calls. |
curl --request POST \
--url 'https://closer.loriginal.org/api/v1/campaigns/9bc96054-7b88-4bde-8c8a-1e3051f6778c/leads' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY" \
--header 'Content-Type: application/json' \
--data-raw '{
"phone": "+14165550123",
"first_name": "Alex",
"external_id": "crm_123"
}'Example response201 Created
{
"data": {
"id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"campaign_id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"phone": "+14165550123",
"first_name": "Alex",
"external_id": "crm_123",
"last_name": null,
"full_name": "Alex",
"email": null,
"company": null,
"notes": null,
"other": null,
"language": "en",
"verification_status": "unverified",
"verification_line_status": null,
"verified_at": null,
"excluded": false,
"paused": false,
"created_at": "2026-09-07T14:00:00Z",
"updated_at": "2026-09-07T14:00:00Z"
}
}Find leads
#Find contacts across your campaigns.
/leadsFilters
| Field | Description |
|---|---|
external_id | Exact CRM or contact ID. |
phone | Exact phone number. Encode + as %2B. |
email | Email address, ignoring letter case. |
campaign_id | Only leads in this campaign. |
curl --request GET \
--url 'https://closer.loriginal.org/api/v1/leads?external_id=crm_123' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": [
{
"id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"campaign_id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"phone": "+14165550123",
"first_name": "Alex",
"external_id": "crm_123",
"last_name": null,
"full_name": "Alex",
"email": null,
"company": null,
"notes": null,
"other": null,
"language": "en",
"verification_status": "unverified",
"verification_line_status": null,
"verified_at": null,
"excluded": false,
"paused": false,
"created_at": "2026-09-07T14:00:00Z",
"updated_at": "2026-09-07T14:00:00Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}Remove lead
#Remove a lead from a campaign. The contact and call history are kept.
/campaigns/{id}/leads/{leadId}Use a lead ID from Find leads. No body is needed. Queued or active calls may still finish.
curl --request DELETE \
--url 'https://closer.loriginal.org/api/v1/campaigns/9bc96054-7b88-4bde-8c8a-1e3051f6778c/leads/806e184b-94aa-46e9-83ec-c7d81735588b' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": {
"id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"campaign_id": null,
"removed": true
}
}List calls
#Read call history and results.
/callsUse history_status for the result, such as Answered or No answer.
Filters
| Field | Description |
|---|---|
campaign_id | Only this campaign's calls. |
lead_id | Only this lead's history. |
phone | Sender or recipient number. Encode + as %2B. |
date_from / date_to | Start and end timestamps, such as 2026-09-07T00:00:00Z. |
curl --request GET \
--url 'https://closer.loriginal.org/api/v1/calls?campaign_id=9bc96054-7b88-4bde-8c8a-1e3051f6778c' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": [
{
"id": "b6f3d38e-86a8-457b-a09c-248c8e32ff63",
"campaign_id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"lead_id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"direction": "outbound",
"from_number": "+14165550100",
"to_number": "+14165550123",
"status": "ended",
"history_status": "Answered",
"started_at": "2026-09-07T14:00:00Z",
"ended_at": "2026-09-07T14:01:15Z",
"duration_ms": 75000,
"created_at": "2026-09-07T14:00:00Z",
"updated_at": "2026-09-07T14:01:15Z",
"recording_url": "https://closer.loriginal.org/api/v1/recordings/8d3a612a6f3748ff9b0a12c74b81e073609ecaa31c354f148ba3e08191b2f445"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}Get call
#Get a call's transcript, recording, and collected answers.
/calls/{id}Use a call ID from List calls. Anyone with recording_url can play or download the audio.
curl --request GET \
--url 'https://closer.loriginal.org/api/v1/calls/b6f3d38e-86a8-457b-a09c-248c8e32ff63' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": {
"id": "b6f3d38e-86a8-457b-a09c-248c8e32ff63",
"campaign_id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"lead_id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"direction": "outbound",
"from_number": "+14165550100",
"to_number": "+14165550123",
"status": "ended",
"history_status": "Answered",
"started_at": "2026-09-07T14:00:00Z",
"ended_at": "2026-09-07T14:01:15Z",
"duration_ms": 75000,
"created_at": "2026-09-07T14:00:00Z",
"updated_at": "2026-09-07T14:01:15Z",
"recording_url": "https://closer.loriginal.org/api/v1/recordings/8d3a612a6f3748ff9b0a12c74b81e073609ecaa31c354f148ba3e08191b2f445",
"transcript": "Call date and time: 2026-09-07T10:00:00-04:00 (ET)\nDuration: 75 seconds\nFrom: +14165550100 Sarah (Agent)\nTo: +14165550123 Alex (Lead)\nAgent: Hi Alex, is now a good time to talk?\nLead: Yes, go ahead.",
"transcript_entries": [
{
"role": "agent",
"content": "Hi Alex, is now a good time to talk?",
"start": 0
},
{
"role": "lead",
"content": "Yes, go ahead.",
"start": 3.2
}
],
"data_collected": {
"interested": true
},
"disconnection_reason": "user_hangup"
}
}Send SMS
#Send a text to a lead. A sending number is chosen depending on what number previously contacted the lead (SMS or phone call), or, which area code matches most with the lead's
/messagesConnect Twilio with an SMS number. Leads use their campaign's selected numbers. Opted-out contacts cannot receive messages.
| Field | Description |
|---|---|
lead_id or to_number | A lead ID, or a phone number with its country code. |
body | Message text, 1–1,600 characters. |
Optional fields
| Field | Description |
|---|---|
campaign_id | Use this campaign's numbers. Defaults to the lead's campaign; must match when sending to a lead. |
from_number | Choose one of your SMS numbers. It must be selected for the campaign when one is used. |
A queued message is still waiting to send. Check message history for delivery. After a send error, check history before sending again.
curl --request POST \
--url 'https://closer.loriginal.org/api/v1/messages' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY" \
--header 'Content-Type: application/json' \
--data-raw '{
"lead_id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"body": "Hi Alex, are you available tomorrow?"
}'Example response201 Created
{
"data": {
"lead_id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"campaign_id": "9bc96054-7b88-4bde-8c8a-1e3051f6778c",
"from_number": "+14165550100",
"to_number": "+14165550123",
"sender_selection": "call_history",
"id": "SM8d3a612a6f3748ff9b0a12c74b81e073",
"direction": "outbound",
"body": "Hi Alex, are you available tomorrow?",
"status": "queued",
"occurred_at": "2026-09-07T14:00:00Z",
"sent_at": null,
"received_at": null
}
}List messages
#Read message history from your connected Twilio account.
/messagesFilter by lead_id to get that contact's messages across campaigns.
Filters
| Field | Description |
|---|---|
lead_id | Only this lead's history. |
phone | Sender or recipient number. Encode + as %2B. |
date_from / date_to | Start and end timestamps, such as 2026-09-07T00:00:00Z. |
curl --request GET \
--url 'https://closer.loriginal.org/api/v1/messages?lead_id=806e184b-94aa-46e9-83ec-c7d81735588b' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"With filters
curl --request GET \
--url 'https://closer.loriginal.org/api/v1/messages?phone=%2B14165550123&date_from=2026-09-07T00:00:00Z&date_to=2026-09-07T23:59:59.999Z' \
--header "Authorization: Bearer $LORIGINAL_CLOSER_API_KEY"Example response200 OK
{
"data": [
{
"id": "SM8d3a612a6f3748ff9b0a12c74b81e073",
"lead_id": "806e184b-94aa-46e9-83ec-c7d81735588b",
"lead_ids": [
"806e184b-94aa-46e9-83ec-c7d81735588b"
],
"direction": "outbound",
"from_number": "+14165550100",
"to_number": "+14165550123",
"body": "Hi Alex, are you available tomorrow?",
"occurred_at": "2026-09-07T14:00:00Z",
"sent_at": "2026-09-07T14:00:00Z",
"received_at": null,
"status": "delivered"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}