Chats
API reference for Nodukan Chats — list conversations, read message history, and send replies.
Chats API
The Chats API gives you programmatic access to the creator's inbox — the conversations that happen when buyers send messages through the storefront or via Instagram Auto-DM. You can list conversations, read message history, and send replies.
Endpoints#
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /chats | chats:read | List all conversations |
GET | /chats/:id/messages | chats:read | Get messages in a conversation |
POST | /chats/:id/reply | chats:write | Send a reply |
GET /chats#
Returns a paginated list of conversations ordered by most recent activity.
Query parameters#
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max records (default 20, max 100) |
offset | integer | Records to skip |
status | string | Filter by open, resolved |
source | string | Filter by storefront, instagram, whatsapp |
unreadOnly | boolean | Return only conversations with unread messages |
curl "https://api.nodukan.com/v1/chats?status=open&limit=50" \
-H "Authorization: Bearer NDK_live_..."
const res = await fetch('https://api.nodukan.com/v1/chats?status=open&unreadOnly=true', {
headers: { Authorization: `Bearer ${process.env.NODUKAN_API_KEY}` },
});
const { data: chats, pagination } = await res.json();
console.log(`${pagination.total} open conversations`);
Response#
{
"data": [
{
"id": "chat_01j9x4km2v",
"source": "instagram",
"status": "open",
"buyer": {
"id": "buyer_01j9x...",
"name": "Ravi Kumar",
"username": "ravikumar_ig",
"avatarUrl": "https://instagram.com/avatars/..."
},
"lastMessage": {
"id": "msg_01j9x...",
"content": "Hi! Is the Notion template still available?",
"senderType": "buyer",
"createdAt": "2026-05-06T09:45:00Z"
},
"unreadCount": 1,
"createdAt": "2026-05-06T09:45:00Z",
"updatedAt": "2026-05-06T09:45:00Z"
},
{
"id": "chat_01j9y7mp3k",
"source": "storefront",
"status": "open",
"buyer": {
"id": "buyer_01j9y...",
"name": "Meera Pillai",
"username": null,
"avatarUrl": null
},
"lastMessage": {
"id": "msg_01j9y...",
"content": "Thank you! I loved the caption pack 🙌",
"senderType": "buyer",
"createdAt": "2026-05-06T08:30:00Z"
},
"unreadCount": 0,
"createdAt": "2026-05-05T14:00:00Z",
"updatedAt": "2026-05-06T08:30:00Z"
}
],
"pagination": { "total": 34, "limit": 50, "offset": 0, "hasMore": false },
"requestId": "req_01j9xabc..."
}
GET /chats/:id/messages#
Returns the full message history for a conversation.
Query parameters#
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max messages (default 50, max 200) |
offset | integer | Messages to skip |
before | ISO datetime | Return messages sent before this time (for reverse pagination) |
curl https://api.nodukan.com/v1/chats/chat_01j9x4km2v/messages \
-H "Authorization: Bearer NDK_live_..."
const res = await fetch(`https://api.nodukan.com/v1/chats/${chatId}/messages`, {
headers: { Authorization: `Bearer ${process.env.NODUKAN_API_KEY}` },
});
const { data: messages } = await res.json();
const lastMessage = messages[messages.length - 1];
Response#
{
"data": [
{
"id": "msg_01j9x1",
"chatId": "chat_01j9x4km2v",
"content": "Hi! Is the Notion template still available?",
"senderType": "buyer",
"senderId": "buyer_01j9x...",
"mediaUrl": null,
"isRead": true,
"isAutomated": false,
"createdAt": "2026-05-06T09:45:00Z"
},
{
"id": "msg_01j9x2",
"chatId": "chat_01j9x4km2v",
"content": "Hi Ravi! Yes, it's available. Here's the link: https://ndk.in/notion-template 🎉",
"senderType": "creator",
"senderId": "usr_01j9x...",
"mediaUrl": null,
"isRead": true,
"isAutomated": true,
"createdAt": "2026-05-06T09:45:15Z"
}
],
"pagination": { "total": 2, "limit": 50, "offset": 0, "hasMore": false },
"requestId": "req_01j9xabc..."
}
isAutomated: true indicates the message was sent by an Auto-DM rule rather than manually by the creator.
POST /chats/:id/reply#
Sends a reply message to a conversation.
Request body#
| Field | Type | Required | Description |
|---|---|---|---|
content | string | ✅ | The message text (max 1000 chars) |
mediaUrl | string | URL of an image to attach |
curl -X POST https://api.nodukan.com/v1/chats/chat_01j9x4km2v/reply \
-H "Authorization: Bearer NDK_live_..." \
-H "Content-Type: application/json" \
-d '{
"content": "Hi Ravi! Yes, grab it here: https://ndk.in/notion-template 🎉"
}'
const res = await fetch(`https://api.nodukan.com/v1/chats/${chatId}/reply`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NODUKAN_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: `Hi ${buyerName}! Your order is confirmed. Track it here: https://ndk.in/track-${orderId}`,
}),
});
const { data } = await res.json();
console.log('Reply sent:', data.id);
Response 201 Created#
{
"data": {
"id": "msg_01j9znew00",
"chatId": "chat_01j9x4km2v",
"content": "Hi Ravi! Yes, grab it here: https://ndk.in/notion-template 🎉",
"senderType": "creator",
"isRead": false,
"isAutomated": false,
"createdAt": "2026-05-06T11:00:00Z"
},
"requestId": "req_01j9xabc..."
}
For Instagram DMs, replies via this API count against Instagram's messaging rate limits. Instagram allows approximately 1,000 messages per day per connected account. If you build a bulk messaging flow, implement your own rate limiting to stay within these bounds.
Subscribe to the chat.new and chat.message.received webhook events to avoid polling /chats repeatedly. Real-time delivery via webhooks is far more efficient and doesn't consume your API rate limit quota.
Last updated