Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/lettermint/endpoints/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ def cancel(self, message_id: str) -> lm_types.RescheduleMessageResponse:
),
)

def process(self, message_id: str) -> lm_types.ProcessInboundMessageResponse:
return cast(
lm_types.ProcessInboundMessageResponse,
self._client.post(
self._path("/messages/{messageId}/process", messageId=message_id), data={}
),
)

def events(self, message_id: str, query: Query | None = None) -> lm_types.MessageEventsResponse:
return cast(
lm_types.MessageEventsResponse,
Expand Down Expand Up @@ -374,6 +382,14 @@ async def cancel(self, message_id: str) -> lm_types.RescheduleMessageResponse:
),
)

async def process(self, message_id: str) -> lm_types.ProcessInboundMessageResponse:
return cast(
lm_types.ProcessInboundMessageResponse,
await self._client.post(
self._path("/messages/{messageId}/process", messageId=message_id), data={}
),
)

async def delete(self, domain_id: str) -> lm_types.DomainDestroyResponse:
return cast(
lm_types.DomainDestroyResponse,
Expand Down
8 changes: 8 additions & 0 deletions src/lettermint/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"scheduled",
"pending",
"queued",
"quarantined",
"suppressed",
"processed",
"delivered",
Expand Down Expand Up @@ -194,6 +195,7 @@
"inbound_received",
"inbound_queued",
"inbound_spam_blocked",
"inbound_released",
"inbound_processed",
"inbound_retry",
]
Expand Down Expand Up @@ -885,6 +887,12 @@
)

MessageShowResponse: TypeAlias = MessageData
ProcessInboundMessageResponse = TypedDict(
"ProcessInboundMessageResponse",
{
"data": "Required[dict[str, str | int]]",
},
)
MessageEventsResponse = TypedDict(
"MessageEventsResponse",
{
Expand Down
6 changes: 6 additions & 0 deletions tests/test_api_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ def test_scheduled_message_endpoints(self) -> None:
200, json={"message_id": "message/id", "status": "canceled", "scheduled_at": None}
)
)
process_route = respx.post("https://api.lettermint.co/v1/messages/message%2Fid/process").mock(
return_value=Response(202, json={"data": {"message_id": "message/id", "status": "queued", "webhook_target_count": 1}})
)

with Lettermint.api("api-token") as api:
assert (
Expand All @@ -195,11 +198,13 @@ def test_scheduled_message_endpoints(self) -> None:
== "scheduled"
)
assert api.messages.cancel("message/id")["status"] == "canceled"
assert api.messages.process("message/id")["data"]["status"] == "queued"

assert json.loads(reschedule_route.calls.last.request.content) == {
"scheduled_at": "2026-08-27T09:00:00Z"
}
assert cancel_route.called
assert process_route.called

@respx.mock
def test_team_role_and_member_assignment_endpoints(self) -> None:
Expand Down Expand Up @@ -244,6 +249,7 @@ def test_documented_operations_are_exposed(self) -> None:
(Lettermint.api("token").messages, "retrieve"),
(Lettermint.api("token").messages, "reschedule"),
(Lettermint.api("token").messages, "cancel"),
(Lettermint.api("token").messages, "process"),
(Lettermint.api("token").messages, "events"),
(Lettermint.api("token").messages, "source"),
(Lettermint.api("token").messages, "html"),
Expand Down