Back to reference

API Reference

Queue a scheduled message response

Queues a one-off response through Sonarly's outbound scheduler instead of sending synchronously. The response includes `activityId`, which matches the stable item ID returned by GET /activity for status monitoring. This endpoint only creates scheduled direct-message or InMail replies; it does not edit campaign-generated content, create LinkedIn comments, or send connection-request notes. Pass channel explicitly. Every reply to an existing conversation must use channel=direct_message with the conversationId returned by GET /messages, even when the conversation originally started as InMail; this keeps the response in the existing thread. For an existing prospect, pass prospectId. To answer an inbound-first conversation whose sender is not yet a Sonarly prospect, pass channel=direct_message and conversationId; Sonarly verifies that the conversation belongs to the requested account before scheduling the reply. InMail starts a new conversation and therefore must not include conversationId; it always requires prospectId, channel=inmail, and a subject. When channel is omitted but subject is present, Sonarly treats the response as InMail. The scheduler does not apply a recipient cooldown to replies: when no active outbound request already exists for the same prospect or conversation, Sonarly schedules the next available slot that satisfies business hours, fatigue, daily or weekly limits, and account rate limits. If that first valid slot is more than 72 hours away, the API returns 422 and no message content is queued. Campaign workflow sends continue to use campaign message hours. To edit generated campaign messages, comments, or invite notes, PATCH the campaign workflow-run messages before approval.

POST/v1/accounts/{accountGroupId}/messages/responses

Channel behavior

Use direct_message when the prospect is connected and has an existing chat. Use inmail with a subject for eligible new conversations.

Not campaign content

This endpoint does not edit campaign-generated messages, create LinkedIn comments, or send connection-request invite notes. For campaign content changes, PATCH workflow-run messages under Campaigns, then approve the run.

Scheduling rules

Replies do not have a recipient cooldown. Sonarly blocks only when the same prospect already has an active outbound request, then otherwise schedules the next valid business-hours slot that passes fatigue, daily or weekly limits, and account rate limits. If the first valid slot is more than 72 hours away, the API returns 422 and does not queue the content.

Safe retries

Send an Idempotency-Key header when retrying. Same-key, same-body retries return the original scheduled request; conflicting retries return 409 IDEMPOTENCY_CONFLICT.

Integration notes

Required API permission

messages:write.

Prerequisites

integration_api_key, account_group_access.

Idempotency

send a stable Idempotency-Key header when retrying this request.

Parameters

accountGroupIdPath

Type: string

Account group ID that scopes the request.

Required

Idempotency-KeyHeader

Type: string

Request field for idempotency key.

Required

Request body

Required

Optional

Content types

application/json

Schema

object

Fields

prospectId

Type: string

Sonarly prospect ID scoped to the account group.

Optional

message

Type: string

Message body for a scheduled response or editable campaign content item.

Required

channel

Type: direct_message | inmail

Delivery channel for the response, such as direct_message or inmail.

Optional

conversationId

Type: string

Existing conversation ID used when responding in a direct message thread.

Optional

subject

Type: string

InMail subject line. Required when channel is inmail.

Optional

Responses

202

Queued or scheduled outbound message response

Schema: ScheduledMessageResponseSuccessResponse

400

Request validation failed

Schema: ValidationErrorResponse

401

Invalid or missing API key

Schema: ErrorResponse

403

Missing required permission

Schema: ErrorResponse

409

Conflict — resource is in a state that prevents this operation

Schema: ErrorResponse

422

Request validation failed

Schema: ValidationErrorResponse

429

Rate limit exceeded

Schema: ErrorResponse

500

Internal server error

Schema: ErrorResponse

502

Upstream service error

Schema: ErrorResponse

Response examples

202 Example JSONScheduledMessageResponseSuccessResponse
{
    "success": true,
    "data": {
        "id": "507f1f77bcf86cd799439011",
        "activityId": "507f1f77bcf86cd799439011",
        "status": "queued",
        "scheduledAt": "2026-04-28T15:30:00.000Z",
        "sentAt": "2026-04-28T15:30:00.000Z",
        "channel": "direct_message",
        "conversationId": "507f1f77bcf86cd799439011",
        "messageId": "507f1f77bcf86cd799439011",
        "idempotencyKey": "string",
        "deferred": true
    },
    "error": null,
    "traceId": "507f1f77bcf86cd799439011"
}
400 Example JSONValidationErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
401 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
403 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
409 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
422 Example JSONValidationErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
429 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
500 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}
502 Example JSONErrorResponse
{
    "success": false,
    "data": null,
    "error": {
        "code": "string",
        "message": "Thanks for the context. I can send over details this afternoon.",
        "details": "string"
    },
    "traceId": "507f1f77bcf86cd799439011"
}