Docs

REST API reference

Sloggr Developer API v1 — authentication, scopes, endpoints, pagination, analytics, errors, and examples for developers and AI agents.

Last updated: 11 August 2026

This is the public contract for Sloggr Developer API v1. It is written for human developers and for AI assistants that need accurate, citable endpoint details.


Authentication

Create an API key in the app: Settings → API Keys.

Authorization: Bearer <api_key_secret>
Content-Type: application/json

Optional request signing (recommended for server-to-server writes). If present, the signature must be valid:

X-Sloggr-Signature: <hex_hmac_sha256(raw_body, api_key_secret)>
ConditionResult
Missing / invalid / revoked key401 unauthorized
Signature present but wrong403 forbidden
Key missing required scope403 forbidden

Rate limit: 60 requests/minute per API key (configurable). Exceeding the limit returns 429.


Tenancy model

ConceptMeaning
Account orgYour Sloggr account. Owns API keys, webhook subscriptions, billing, and team users.
Target orgA customer organization belonging to the account. Deals, tickets, and contacts live here.
API key scopeEvery key belongs to one account org. It can only see that account’s data.

Cross-account access is rejected even if record IDs collide globally.

Integrators should send:

FieldDescription
source_appStable app id (e.g. client-diary, n8n)
external_org_idYour tenant/practice id

Sloggr stores (source_app, external_org_id) → org_id after the first successful resolve. You do not need to persist Sloggr org ids for normal flows.

First-time link hints: org_name, contact_email (and optional contact_name).


API key scopes

AccessHow to createCan do
Full (*)Default “Full access” key, or legacy keys with scopes = nullRead + write
AI / agent read-only“AI / agent read-only” in API Keys UILists, activity, analytics, webhook readno creates/updates

Capabilities

CapabilityTypical routes
orgs:read / orgs:writeList orgs; resolve / link external ids
users:readList team members
contacts:readList contacts; marketing audience GET
deals:read / deals:writeList/get/search deals; list/create activities
support:read / support:writeList/get tickets & logs; create tickets
activity:readUnified activity feed
analytics:read/analytics/*
webhooks:read / webhooks:writeList endpoints/deliveries; create endpoints
readBundle of all read capabilities
*Everything

Marketing audience PUT/DELETE requires full access (*).


Conventions

Dates and times

Pagination

ParamDefaultNotes
page1≥ 1
per_page25Max 100

List responses include:

{
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 120,
    "pages": 5,
    "has_next": true,
    "has_prev": false
  }
}

Sorting (where supported)

sort + direction (asc | desc). Deal/ticket sorts include created_at, updated_at, id, title, status.

Idempotency (writes)

Send either:

Same key + account within the retention window returns the original response (no duplicate create).

Errors

Machine-readable JSON:

{
  "error": "validation_error",
  "message": "contact_email is required when contact_id is omitted.",
  "fields": {
    "contact_email": "required"
  }
}
HTTPerror examplesMeaning
401unauthorizedAuth failure
403forbiddenScope, tenancy, or bad signature
404*_not_found, org_not_foundMissing in account scope
409org_ambiguousMultiple org matches
422validation_error, org_lookup_requiredBad input
429rate limitedSlow down
500internal_errorUnexpected server error

Passwords, API secrets, and auth tokens are never returned in resource payloads (webhook endpoint create returns the endpoint signing secret once).


Endpoint index

Organizations

MethodPathScopePurpose
GET/orgsorgs:readList customer orgs (q)
POST/orgs/resolveorgs:writeMap external tenant → org
PUT/orgs/{org_id}/external-idsorgs:writeManual external id link

Users & contacts

MethodPathScopePurpose
GET/usersusers:readAccount team members
GET/contactscontacts:readContacts (org_id, email, q)
GET/contacts/{id}/marketing-audiencescontacts:readMarketing memberships
PUT/DELETE/contacts/{id}/marketing-audiences*Update/remove memberships

Deals

MethodPathScopePurpose
GET/dealsdeals:readList/filter/sort deals
GET/deals/searchdeals:readLookup by Stripe id / email / org
GET/deals/{id}deals:readGet one deal
GET/deals/{id}/activitiesdeals:readTimeline activities
POST/deals/{id}/activitiesdeals:writeLog note/call/email/meeting

Support

MethodPathScopePurpose
GET/support/ticketssupport:readList tickets
POST/support/ticketssupport:writeCreate ticket + first log
GET/support/tickets/{id}support:readGet ticket
GET/support/tickets/{id}/logssupport:readList support logs

Activity & analytics

MethodPathScopePurpose
GET/activityactivity:readUnified activity feed
GET/analytics/salesanalytics:readSales aggregates + compare
GET/analytics/supportanalytics:readSupport aggregates + compare
GET/analytics/teamanalytics:readPer-user totals
GET/analytics/customersanalytics:readCustomer health
GET/analytics/activityanalytics:readActivity volume mix
GET/analytics/trendsanalytics:readISO-week trends

Webhooks (management)

MethodPathScopePurpose
GET/webhooks/endpointswebhooks:readList subscriptions
POST/webhooks/endpointswebhooks:writeRegister endpoint
GET/webhooks/deliverieswebhooks:readDelivery log

Full event catalog and signing: Webhooks docs.


Organizations

Resolve external org

POST /api/v1/orgs/resolve
FieldRequiredDescription
source_appYesApp identifier
external_org_idYesYour tenant id
org_nameWhen unmappedCustomer name hint
contact_emailWhen unmappedPrimary contact email
contact_nameNoDisambiguation

200 statuses: mapped (already linked) or linked (newly linked).

curl -sS -X POST 'https://app.saleslogger.app/api/v1/orgs/resolve' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "source_app": "client-diary",
    "external_org_id": "practice_8842",
    "org_name": "Acme Physio",
    "contact_email": "owner@acmephysio.com"
  }'

List orgs

GET /api/v1/orgs?q=acme&page=1&per_page=25
PUT /api/v1/orgs/{org_id}/external-ids
{ "source_app": "client-diary", "external_org_id": "practice_8842" }

Users & contacts

List users

GET /api/v1/users?active_only=1

Returns account team members (id, email, display_name, role, is_active, support_enabled). No passwords or secrets.

List contacts

GET /api/v1/contacts?org_id=14673&q=jane

Deals

List deals

GET /api/v1/deals?status=qualified&owner_user_id=12&created_from=2026-08-01&sort=updated_at&direction=desc

Useful filters: status, org_id, owner_user_id, q, created_from/created_to, updated_from/updated_to.

Search deals

GET /api/v1/deals/search?stripe_customer_id=cus_abc123

At least one of: stripe_customer_id, contact_email, org_id.

Get deal

GET /api/v1/deals/{deal_id}

List deal activities

GET /api/v1/deals/{deal_id}/activities

Create deal activity

POST /api/v1/deals/{deal_id}/activities
Idempotency-Key: n8n:welcome-email:cus_abc123
FieldRequiredDescription
source_appYesIntegrator id
messageYesTimeline text
activity_kindNonote (default), email, call, meeting
outcomeNosuccess, failed, skipped
external_referenceNoCaller reference
metadata_jsonNoOpaque object

Emits webhook deal.activity.created when delivery subscriptions exist.

curl -sS -X POST 'https://app.saleslogger.app/api/v1/deals/42/activities' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: n8n:welcome:42' \
  -d '{
    "source_app": "n8n",
    "message": "Welcome email sent",
    "activity_kind": "email",
    "outcome": "success"
  }'

Support tickets

Create ticket

POST /api/v1/support/tickets
FieldRequiredDescription
source_appYesApp id
external_org_idYesYour tenant id
titleYesTicket title
detailsYesDescription
contact_emailYes*Required unless contact_id
org_nameWhen unmappedLookup hint
noteNoFirst update body (defaults to details)
channelNoDefault api
external_referenceNoCaller case id
metadata_jsonNoOpaque object
idempotency_keyNoOr use header
curl -sS -X POST 'https://app.saleslogger.app/api/v1/support/tickets' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: client-diary:case-8842' \
  -d '{
    "source_app": "client-diary",
    "external_org_id": "practice_8842",
    "org_name": "Acme Physio",
    "title": "Cannot export diary entries",
    "details": "Export button greyed out on mobile Safari.",
    "contact_email": "owner@acmephysio.com",
    "channel": "api",
    "external_reference": "case-8842"
  }'

List tickets

GET /api/v1/support/tickets?open_only=1&org_id=14673

Filters: status, open_only, org_id, owner_user_id, q, created_from/created_to, sort.

Get ticket / list logs

GET /api/v1/support/tickets/{ticket_id}
GET /api/v1/support/tickets/{ticket_id}/logs

Unified activity

Normalized customer-facing activity across deal timeline events and support logs.

GET /api/v1/activity?org_id=14673&from=2026-04-25&to=2026-07-24&employee_user_id=12&source=all
ParamDescription
org_idCustomer org
employee_user_id / user_idActor filter
deal_id / ticket_idRelated entity
sourceall, timeline, sales, support_log, support
from / toDate range

Each activity includes stable composite ids such as timeline:123 or support_log:456, plus employee, customer, type, content, related deal/ticket ids, and timestamps.

Note: Results are capped at 500 rows per source before pagination — narrow with from/to for large accounts.


Analytics

Server-side aggregates so agents do not need to download thousands of records. Prefer a read-only API key.

Date selection

ParamDescription
rangePreset: today, this_week, last_week, this_month, last_month, this_quarter, this_year, last_year (default this_month)
from / toCustom range (overrides preset)
compare1 / true / previous — include prior period + change

Change objects look like:

{
  "absolute": 4,
  "percent": 25.0,
  "note": null
}

When the previous value is 0, percent is null and note is "zero_baseline" (unless both periods are zero).

Sales

GET /api/v1/analytics/sales?range=this_month&compare=1

Includes sales results (created/won/lost/win rate/by rep), funnel, lost reasons, and open-pipeline follow-up signals (overdue_followups, deals_without_activity_14d). Optional: owner_user_id, by=owner|closer.

Support

GET /api/v1/analytics/support?range=this_month&compare=1

Tickets created, currently open, resolved/closed in period, support updates, aged open (>7d), by employee and by customer.

GET /api/v1/analytics/team?range=this_month
GET /api/v1/analytics/customers?range=this_month
GET /api/v1/analytics/activity?range=this_month
GET /api/v1/analytics/trends?range=this_month

/analytics/customers includes customer health rankings and customers_with_open_support_and_open_deals.


Example questions → endpoints

QuestionEndpoint
How did sales do this month vs last?GET /analytics/sales?range=this_month&compare=1
Which tickets are still open?GET /support/tickets?open_only=1
Everything for customer X in 90 daysGET /activity?org_id=X&from=...&to=...
Who has the most support updates?GET /analytics/support or /analytics/team
Customers with open support and open dealsGET /analytics/customers
Overdue follow-upsGET /analytics/salesopen_pipeline.overdue_followups

The API returns facts and calculations. Interpretation/commentary belongs in your AI layer, not in Sloggr.


Setup checklist (external SaaS)

  1. Create an API key (full for writes, or AI read-only for analytics).
  2. Store the secret in your backend only.
  3. Agree a stable source_app string with the account holder.
  4. Call POST /orgs/resolve on tenant onboarding.
  5. Create tickets / log deal activities with idempotency keys.
  6. Optionally register webhook endpoints for push updates.