Messages & notifications
Direct messages, conversations, and dashboard notifications.
Direct messages between Scrape.ly users, and the dashboard notification center. Paths are relative to https://api.scrape.ly.
All messaging routes require your user API key; run tokens are rejected with 403 insufficient-permissions.
Conversations
A conversation is a thread between two users. Every new conversation starts as pending. The recipient accepts or rejects it; only after acceptance can either side reply.
Rules for starting a conversation:
- Your profile must be public (
403 profile-not-public). - You can't message yourself (
403 forbidden). - If you already have a
pendingoracceptedconversation with that user, you get409 conversation-exists. A rejected conversation doesn't block a new one. - You can start at most 5 conversations per 24 hours (
429 rate-limited). - Message bodies are at most 10,000 characters and pass a profanity filter.
Sending (starting a conversation or replying) is also limited to 10 requests per minute per user (429 rate-limit-exceeded).
Start a conversation
/v2/users/{username}/messagesSends the first message to a user, identified by their Scrape.ly username, and creates a pending conversation. The recipient gets a dashboard notification.
curl -X POST "https://api.scrape.ly/v2/users/janedoe/messages" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body": "Hi! I have a question about your Actor" }'201 response:
{
"data": {
"id": "conv-uuid",
"status": "pending",
"initialMessage": {
"id": "msg-uuid",
"body": "Hi! I have a question about your Actor",
"senderId": "uSeRiDeXaMpLe123",
"senderUsername": "acme",
"createdAt": "2026-08-14T16:00:00.000Z"
}
}
}Find a conversation with a user
/v2/conversations/with/{username}Returns your conversation with that user if one exists that isn't rejected and that you haven't deleted from your view. Otherwise returns { "data": null }. Unknown usernames return 404 user-not-found.
{
"data": {
"id": "conv-uuid",
"status": "accepted",
"isInitiator": true,
"otherUser": { "id": "uSeRiDeXaMpLe456", "username": "janedoe", "imageUrl": null },
"createdAt": "2026-08-14T16:00:00.000Z",
"updatedAt": "2026-08-14T16:05:00.000Z"
}
}/v2/conversations/with/janedoeList conversations
/v2/user/conversations| Query param | Type | Default | Description |
|---|---|---|---|
status | string | — | pending, accepted, or rejected. |
limit | number | 20 | Page size, max 100. |
offset | number | 0 | Pagination offset. |
Conversations you deleted from your view are omitted.
curl "https://api.scrape.ly/v2/user/conversations?limit=20" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/user/conversationsGet a conversation
/v2/conversations/{conversationId}Returns the same fields as Find a conversation with a user, plus closedBy ({ "id", "username" }, or null if the conversation is open). Conversations you aren't part of return 403 forbidden; unknown conversations and ones you deleted from your view return 404 conversation-not-found.
curl "https://api.scrape.ly/v2/conversations/{conversationId}" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"List messages
/v2/conversations/{conversationId}/messagesMessage history, oldest first. limit defaults to 50 (max 100), offset to 0. Fetching messages marks the conversation as read for you.
curl "https://api.scrape.ly/v2/conversations/{conversationId}/messages?limit=50&offset=0" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Send a message
/v2/conversations/{conversationId}/messagesAllowed only on accepted conversations that aren't closed (403 forbidden otherwise). Body: { "body": "..." }.
curl -X POST "https://api.scrape.ly/v2/conversations/{conversationId}/messages" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body": "Thanks for the quick reply!" }'201 response:
{
"data": {
"id": "msg-uuid",
"conversationId": "conv-uuid",
"senderId": "uSeRiDeXaMpLe123",
"senderUsername": "acme",
"body": "Thanks for the quick reply!",
"createdAt": "2026-08-14T16:05:00.000Z"
}
}The other participant gets a dashboard notification unless they turned off dashboard notifications for this conversation.
Accept, reject, or close
/v2/conversations/{conversationId}/accept/v2/conversations/{conversationId}/reject/v2/conversations/{conversationId}/close- Only the recipient can accept or reject, and only while the conversation is
pending. - Either participant can close an accepted conversation. After that, nobody can send messages.
- Acting on a conversation in the wrong state returns
400 invalid-action.
curl -X PATCH "https://api.scrape.ly/v2/conversations/{conversationId}/accept" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Accept returns { "data": { "id": "...", "status": "accepted" } } and notifies the sender. Reject returns status: "rejected". Close returns { "data": { "id": "...", "closedBy": "<userId>" } } and notifies the other participant.
Delete a conversation
/v2/conversations/{conversationId}Hides the conversation from your list. The other participant still sees it. Returns { "data": { "success": true } }.
curl -X DELETE "https://api.scrape.ly/v2/conversations/{conversationId}" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Conversation notification settings
/v2/conversations/{conversationId}/settings/v2/conversations/{conversationId}/settingsYour notification settings for one conversation. Defaults: notifyConsole: true, notifyEmail: false.
PUT replaces both values: a field you leave out is saved as false. Always send both.
curl -X PUT "https://api.scrape.ly/v2/conversations/{conversationId}/settings" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "notifyConsole": false, "notifyEmail": false }'Dashboard notifications
The dashboard notification center (the bell icon). Notification type values include low_balance, plan_expiration, credit_expiration, api_key_created, storage_digest, schedule_failure, actor_auto_test, actor_maintenance_expired, actor_pricing_changed, alert, issue_created, issue_comment, new_message, message_accepted, conversation_closed, and quota_reached. See Notifications for when each is sent.
Errors on these routes use a plain string body, for example { "error": "Failed to fetch notifications" }.
List notifications
/v2/console-notificationsNewest first. limit defaults to 50 (max 100), offset to 0. The list is data (an array), with pagination fields at the top level.
curl "https://api.scrape.ly/v2/console-notifications?limit=20&offset=0" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Scrape.ly keeps roughly your newest 1,000 notifications and trims older ones.
/v2/console-notificationsUnread count
/v2/console-notifications/unread-count{ "unreadCount": 3 }There is no data wrapper.
/v2/console-notifications/unread-countMark as read
/v2/console-notifications/read-all/v2/console-notifications/{notificationId}/readBoth return { "success": true }.
curl -X PATCH "https://api.scrape.ly/v2/console-notifications/read-all" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Delete all notifications
/v2/console-notificationsDeletes all of your dashboard notifications, read and unread. Returns { "success": true }.
curl -X DELETE "https://api.scrape.ly/v2/console-notifications" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Account-wide email and dashboard notification preferences live in the Users API.
Errors
| Status | Type | Meaning |
|---|---|---|
| 400 | invalid-input | Missing or empty message body, or body over 10,000 characters |
| 400 | invalid-action | Conversation is in the wrong state for accept, reject, or close |
| 400 | profanity-detected | Message failed the profanity filter |
| 403 | forbidden | Messaging yourself, not allowed to act on this conversation, or conversation not accepted or closed |
| 403 | profile-not-public | Your profile must be public to start a conversation |
| 404 | user-not-found / conversation-not-found | Unknown user or conversation |
| 409 | conversation-exists | A pending or accepted conversation already exists |
| 429 | rate-limited | More than 5 new conversations in 24 hours |
| 429 | rate-limit-exceeded | More than 10 sends per minute |