Reply by Email API
Let customers reply. Deliver the answer to the right object.
Give an order, ticket, invoice, or application object an opaque Reply-To address. When the customer replies normally, Linje sends the email and your metadata to a signed inbox webhook.
Use cases
Keep email replies inside the product that owns the context.
Attach a customer's answer to the order or invoice that prompted it.
Turn the reply into a comment on the correct ticket or application case.
Receive requested files against the right application, claim, or review.
Why reply routes
Make correlation explicit instead of reconstructing it later.
Route
Create a project-scoped reply address.
curl -fsS \
-H "Authorization: Bearer $LINJE_PROJECT_TOKEN" \
-H "Idempotency-Key: 018f47d2-89ab-4cde-8123-456789abcdef" \
-H "content-type: application/json" \
-d '{
"inbox-id":"orders",
"metadata":{"order-id":"order_82921"}
}' \
https://api.linje.systems/v1/reply-routes
{
"reply-route": {
"id":"route_...",
"address":"r+012345...@in.linje.systems",
"metadata":{"order-id":"order_82921"},
"active":true
}
}
Use a fresh UUIDv4 as the idempotency key for each logical route. Concurrent and sequential exact retries return the same route and address; conflicting reuse returns 409. After retention cleanup, a retry returns 410 so a purged address cannot be revived or rebound.
Outbound
Use the generated address as Reply-To.
POST /v1/messages
{
"from":"orders@tx.example.com",
"to":["customer@example.com"],
"reply-to":["r+012345...@in.linje.systems"],
"subject":"Your order"
}
Inbound
The reply arrives with caller metadata.
POST https://app.example.com/linje/inbound
x-linje-inbound-id: ...
x-linje-delivery-id: ...
x-linje-timestamp: ...
x-linje-signature: sha256=...
{
"schema":"linje.inbound-email.v1",
"inbound-id":"...",
"inbox-id":"orders",
"route": {
"id":"route_...",
"metadata":{"order-id":"order_82921"}
},
"email": {
"from":[{"email":"customer@example.com"}],
"subject":"Re: Your order",
"in-reply-to":["<linje...@tx.example.com>"],
"references":[]
},
"content":{"text":"Can you change the address?"}
}
Lifecycle
Expire or disable addresses without changing metadata.
curl -fsS -X PATCH \
-H "Authorization: Bearer $LINJE_PROJECT_TOKEN" \
-H "content-type: application/json" \
-d '{"active":false}' \
https://api.linje.systems/v1/reply-routes/route_...
Disabled, expired, malformed, and unknown routes do not reach the target inbox webhook and do not expose caller metadata.
Route listings accept inbox-id, cursor, and limit. The default page size is 100 and the maximum is 500. Responses use next-cursor pagination.
The complete address is returned only on creation and exact idempotent retries, so store it when you create the route. Metadata is immutable and limited to 16 KiB.
Disabled and expired routes can be removed after the configured retention window; Linje retains only a minimal hash tombstone.
Boundary
Correlation is not workflow.
Linje tells your application which route received the email. Your application decides whether the message updates an order, creates a comment, or does nothing. Linje does not become a helpdesk, rules engine, or shared inbox.