> For the complete documentation index, see [llms.txt](https://docs.usepylon.com/pylon-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.usepylon.com/pylon-docs/developer/api/api-reference/messages.md).

# Messages

## Get messages on an issue

> Returns messages for the specified issue, including replies and internal notes, ordered from oldest to newest.\
> \
> To post a reply, use the message's top-level id—not thread\_id or email\_info.message\_id. To post an internal note, use an internal thread's thread\_id or an internal note's top-level id. Omit both limit and cursor to return all messages; when cursor is provided without limit, the page size defaults to 100.\
> \
> \*\*Rate limit:\*\* 120 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"responses":{"GetIssueMessagesResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetIssueMessagesResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}},"schemas":{"GetIssueMessagesResponseBody":{"properties":{"data":{"description":"The data payload of the response.","items":{"$ref":"#/components/schemas/Message"},"type":"array"},"pagination":{"$ref":"#/components/schemas/Pagination"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["data","request_id"],"type":"object"},"Message":{"properties":{"author":{"allOf":[{"$ref":"#/components/schemas/MessageAuthor"}],"nullable":true},"author_unverified":{"description":"Whether this message's author identity has NOT been verified. True for public form submissions, unverified chat widget visitors, and emails that failed sender authentication. For emails, read email_info.sender_authentication_status to tell an authentication failure apart from the other cases.","type":"boolean"},"email_info":{"$ref":"#/components/schemas/EmailMessageInfo"},"file_urls":{"description":"The URLs of the files in the message, if any. Signed download URLs. Fetch with a plain GET, no Authorization header.","items":{"type":"string"},"type":"array"},"id":{"description":"The top-level Pylon message ID. Use this value as message_id when replying or when targeting an internal note's thread.","type":"string"},"is_private":{"description":"Whether the message is an internal note. If true, the message is not visible to the requester; if false, it is customer-visible.","type":"boolean"},"message_html":{"description":"The HTML body of the message.","type":"string"},"source":{"description":"The source of the message.","type":"string"},"thread_id":{"description":"The Pylon internal thread ID. This is set only for internal notes and can be passed as thread_id when creating an internal note.","type":"string"},"timestamp":{"description":"The time at which the message was created.","format":"date-time","type":"string"}},"required":["author_unverified","id","is_private","message_html","source","timestamp"],"type":"object"},"MessageAuthor":{"properties":{"avatar_url":{"type":"string"},"contact":{"$ref":"#/components/schemas/MiniContact"},"name":{"type":"string"},"user":{"$ref":"#/components/schemas/MiniUser"}},"required":["name"],"type":"object"},"MiniContact":{"properties":{"email":{"description":"The email of the contact.","type":"string"},"id":{"description":"The ID of the contact.","type":"string"}},"required":["id"],"type":"object"},"MiniUser":{"properties":{"email":{"description":"The email of the user.","type":"string"},"id":{"description":"The ID of the user.","type":"string"}},"required":["id"],"type":"object"},"EmailMessageInfo":{"properties":{"bcc_emails":{"description":"The email addresses of the BCC recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"},"cc_emails":{"description":"The email addresses of the CC recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"},"from_email":{"description":"The email address of the sender of the message.","type":"string"},"message_id":{"description":"The RFC 5322 Message-ID header value for this email. This is a provider-specific identifier, not the top-level Pylon message ID, and cannot be used as message_id when posting a reply or internal note.","type":"string"},"opens":{"description":"When each recipient first opened an email Pylon sent, at most one entry per recipient.\nAlways empty for inbound mail and for mail sent through a connected personal email account.\nOpen tracking is approximate: clients that prefetch images (such as Apple Mail Privacy Protection)\ncan report opens that never happened, and clients that block images report none.","items":{"$ref":"#/components/schemas/EmailEvent"},"nullable":true,"type":"array"},"sender_authentication_status":{"description":"The SPF/DKIM sender authentication result recorded by Pylon's inbound mail provider.\nOne of \"pass\", \"fail\", or \"unknown\".\n\"fail\" means SPF failed outright, or the message carried a DKIM signature that did not validate.\n\"pass\" means SPF passed, or a DKIM signature validated.\n\"unknown\" means nothing vouched for the sender and must not be read as a pass. It covers\nmail Pylon sent, mail synced from a personal email integration, submissions stored as email\nmessages, and senders whose domain published no SPF or DKIM records to check against.","type":"string"},"to_emails":{"description":"The email addresses of the recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"}},"required":["from_email","message_id","sender_authentication_status"],"type":"object"},"EmailEvent":{"properties":{"email":{"description":"The email address of the recipient the event applies to.","type":"string"},"time":{"description":"When the event happened, in RFC 3339 format.","type":"string"}},"required":["email","time"],"type":"object"},"Pagination":{"description":"Pagination information for list responses. Absent when there are no more results.","properties":{"cursor":{"description":"The cursor for the next page of results.","type":"string"},"has_next_page":{"description":"Indicates if there is a next page of results.","type":"boolean"}},"required":["cursor","has_next_page"],"title":"Pagination","type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}}},"paths":{"/issues/{id}/messages":{"get":{"description":"Returns messages for the specified issue, including replies and internal notes, ordered from oldest to newest.\n\nTo post a reply, use the message's top-level id—not thread_id or email_info.message_id. To post an internal note, use an internal thread's thread_id or an internal note's top-level id. Omit both limit and cursor to return all messages; when cursor is provided without limit, the page size defaults to 100.\n\n**Rate limit:** 120 requests per minute","operationId":"GetIssueMessages","parameters":[{"description":"The ID of the issue to fetch messages for.","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"The cursor to use for pagination.","in":"query","name":"cursor","schema":{"type":"string"}},{"description":"The number of messages to fetch. Must be greater than 0 and at most 1000. If omitted, all messages are returned for backward compatibility.","in":"query","name":"limit","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"$ref":"#/components/responses/GetIssueMessagesResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Get messages on an issue","tags":["messages"]}}}}
```

## Get all threads on an issue

> Returns all threads for the specified issue.\
> \
> \*\*Rate limit:\*\* 120 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"responses":{"GetIssueThreadsResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetIssueThreadsResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}},"schemas":{"GetIssueThreadsResponseBody":{"properties":{"data":{"description":"The data payload of the response.","items":{"$ref":"#/components/schemas/IssueThread"},"type":"array"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["data","request_id"],"type":"object"},"IssueThread":{"description":"A thread of notes on an issue, for internal discussions not visible to the customer.\nThreads can be created manually through the UI or from triggers.\nIf a channel ID is set, this thread is being synced with a chat platform.","properties":{"channel_id":{"description":"The ID of the channel that the thread belongs to, if the thread is being synced with a chat platform.","type":"string"},"id":{"description":"The ID of the thread.","type":"string"},"issue_id":{"description":"The issue ID that the thread belongs to.","type":"string"},"name":{"description":"The name of the thread.","type":"string"},"source":{"description":"The source of the thread.","type":"string"},"thread_id":{"description":"The ID of the thread that the thread belongs to, if the thread is being synced with a chat platform. A thread ID for Slack would be the thread timestamp.","type":"string"}},"required":["id","issue_id","name"],"title":"IssueThread","type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}}},"paths":{"/issues/{id}/threads":{"get":{"description":"Returns all threads for the specified issue.\n\n**Rate limit:** 120 requests per minute","operationId":"GetIssueThreads","parameters":[{"description":"The ID of the issue to fetch threads for.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/GetIssueThreadsResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Get all threads on an issue","tags":["messages"]}}}}
```

## Create a thread on an issue

> Creates a new internal thread on an issue.\
> \
> \*\*Rate limit:\*\* 120 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"schemas":{"CreateIssueThreadRequestBody":{"properties":{"name":{"description":"The name of the thread.","type":"string"},"slack_channel_id":{"description":"The Slack channel ID to sync the thread to. When slack_thread_ts is also provided, links that existing Slack thread. Otherwise, creates a new Slack-backed thread.\nLinking an existing Slack thread imports its message history and enables ongoing synchronization. Creating or linking a Slack-backed thread requires an API token configured to act as a human Pylon user whose verified Slack identity is a member of the channel. Pylon bot users and standalone API identities are not supported because they do not have Slack-verifiable channel membership.","type":"string"},"slack_thread_ts":{"description":"The root message timestamp of an existing Slack thread to link. Requires slack_channel_id.","type":"string"}},"type":"object"},"CreateIssueThreadResponseBody":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/IssueThread"}],"nullable":true},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"IssueThread":{"description":"A thread of notes on an issue, for internal discussions not visible to the customer.\nThreads can be created manually through the UI or from triggers.\nIf a channel ID is set, this thread is being synced with a chat platform.","properties":{"channel_id":{"description":"The ID of the channel that the thread belongs to, if the thread is being synced with a chat platform.","type":"string"},"id":{"description":"The ID of the thread.","type":"string"},"issue_id":{"description":"The issue ID that the thread belongs to.","type":"string"},"name":{"description":"The name of the thread.","type":"string"},"source":{"description":"The source of the thread.","type":"string"},"thread_id":{"description":"The ID of the thread that the thread belongs to, if the thread is being synced with a chat platform. A thread ID for Slack would be the thread timestamp.","type":"string"}},"required":["id","issue_id","name"],"title":"IssueThread","type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}},"responses":{"CreateIssueThreadResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueThreadResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}}},"paths":{"/issues/{id}/threads":{"post":{"description":"Creates a new internal thread on an issue.\n\n**Rate limit:** 120 requests per minute","operationId":"CreateIssueThread","parameters":[{"description":"The ID of the issue to create a thread for.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueThreadRequestBody"}}}},"responses":{"200":{"$ref":"#/components/responses/CreateIssueThreadResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Create a thread on an issue","tags":["messages"]}}}}
```

## Reply to an issue

> Sends a customer-facing reply on an issue, visible to the requester.\
> \
> message\_id is required to identify which existing customer-visible conversation or thread to continue. Use the top-level message id returned by GET /issues/{id}/messages; do not use an external provider's message ID or the nested email\_info.message\_id value.\
> \
> For an email conversation, email\_info must contain at least one recipient across to\_emails, cc\_emails, and bcc\_emails. The referenced message controls email threading, but its recipients are not copied automatically.\
> \
> \*\*Rate limit:\*\* 30 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"schemas":{"CreateIssueReplyRequestBody":{"properties":{"attachment_urls":{"description":"URLs of files to attach to this reply.","items":{"type":"string"},"type":"array"},"body_html":{"description":"The body of the message in HTML.","type":"string"},"contact_id":{"description":"Optional contact ID to post the message as. Only one of user_id or contact_id can be provided.","type":"string"},"custom_source":{"$ref":"#/components/schemas/CustomSourceInfo"},"email_info":{"$ref":"#/components/schemas/CreateIssueReplyEmailInfo"},"message_id":{"description":"The top-level Pylon message ID to reply to, from the `id` field returned by GET /issues/{id}/messages. The message must belong to the issue in the request path and must be customer-visible, not an internal note. This selects the external conversation or thread where the reply is delivered. For email, it also sets the In-Reply-To and References chain. Do not use a provider-specific message ID or email_info.message_id.","type":"string"},"user_id":{"description":"Optional user ID to post the message as. Only one of user_id or contact_id can be provided.","type":"string"}},"required":["body_html","message_id"],"type":"object"},"CustomSourceInfo":{"properties":{"created_at":{"description":"The timestamp of when the message was created in the external system. (RFC3339)","format":"date-time","type":"string"},"external_id":{"description":"The external ID of this message in the custom system. Unique per custom source: retrying a reply with the same external_id on the same issue returns the existing message instead of creating a duplicate.","type":"string"},"metadata":{"additionalProperties":{},"description":"Arbitrary metadata to store with the message.","type":"object"}},"required":["external_id"],"title":"CustomSourceInfo contains metadata for messages on custom source issues.","type":"object"},"CreateIssueReplyEmailInfo":{"description":"Recipient information for replies to email conversations.\nProvide at least one address across to_emails, cc_emails, and bcc_emails.\nRecipients are not inferred from the referenced message.","properties":{"bcc_emails":{"description":"The blind-carbon-copy recipients of the email reply.","items":{"type":"string"},"type":"array"},"cc_emails":{"description":"The carbon-copy recipients of the email reply.","items":{"type":"string"},"type":"array"},"to_emails":{"description":"The primary recipients of the email reply.","items":{"type":"string"},"type":"array"}},"title":"CreateIssueReplyEmailInfo","type":"object"},"CreateIssueReplyResponseBody":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/CreateIssueReplyResponseData"}],"nullable":true},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"CreateIssueReplyResponseData":{"properties":{"id":{"description":"The ID of the message.","type":"string"},"issue_id":{"description":"The ID of the issue.","type":"string"}},"required":["id","issue_id"],"type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}},"responses":{"CreateIssueReplyResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueReplyResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}}},"paths":{"/issues/{id}/reply":{"post":{"description":"Sends a customer-facing reply on an issue, visible to the requester.\n\nmessage_id is required to identify which existing customer-visible conversation or thread to continue. Use the top-level message id returned by GET /issues/{id}/messages; do not use an external provider's message ID or the nested email_info.message_id value.\n\nFor an email conversation, email_info must contain at least one recipient across to_emails, cc_emails, and bcc_emails. The referenced message controls email threading, but its recipients are not copied automatically.\n\n**Rate limit:** 30 requests per minute","operationId":"CreateIssueReply","parameters":[{"description":"The ID of the issue.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueReplyRequestBody"}}}},"responses":{"200":{"$ref":"#/components/responses/CreateIssueReplyResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Reply to an issue","tags":["messages"]}}}}
```

## Create or update a draft reply

> Creates a private customer-reply draft without sending it. The draft is visible only to its owner and may require a normal issue refetch before appearing in the app. For unlinked or service API tokens, user\_id is required. This endpoint updates only untouched drafts that it previously created; every other existing draft returns a conflict.\
> \
> \*\*Rate limit:\*\* 30 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"schemas":{"CreateIssueDraftReplyRequestBody":{"properties":{"body_html":{"description":"The draft body in HTML.","type":"string"},"user_id":{"description":"The active Pylon user who should own and see the draft. Defaults to the API-token user when it is a human Pylon user; required for unlinked or service API tokens.","type":"string"}},"required":["body_html"],"type":"object"},"CreateIssueDraftReplyResponseBody":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/CreateIssueDraftReplyResponseData"}],"nullable":true},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"CreateIssueDraftReplyResponseData":{"properties":{"id":{"description":"The ID of the draft.","type":"string"},"issue_id":{"description":"The ID of the issue.","type":"string"},"status":{"description":"Whether the endpoint created or updated the draft.\n\nKnown values: `created`, `updated`. This list is not exhaustive.","type":"string"},"updated_at":{"description":"The time the draft was last updated.","format":"date-time","type":"string"},"user_id":{"description":"The ID of the Pylon user who owns and can see the draft.","type":"string"}},"required":["id","issue_id","status","updated_at","user_id"],"type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}},"responses":{"CreateIssueDraftReplyResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueDraftReplyResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}}},"paths":{"/issues/{id}/draft-reply":{"post":{"description":"Creates a private customer-reply draft without sending it. The draft is visible only to its owner and may require a normal issue refetch before appearing in the app. For unlinked or service API tokens, user_id is required. This endpoint updates only untouched drafts that it previously created; every other existing draft returns a conflict.\n\n**Rate limit:** 30 requests per minute","operationId":"CreateIssueDraftReply","parameters":[{"description":"The ID of the issue.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueDraftReplyRequestBody"}}},"description":"The request body.","required":true},"responses":{"200":{"$ref":"#/components/responses/CreateIssueDraftReplyResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"409":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Create or update a draft reply","tags":["messages"]}}}}
```

## Create an internal note on an issue

> Posts an internal note on an issue thread. Not visible to the requester.\
> \
> Thread selection:\
> \* If thread\_id is provided, posts to that internal thread.\
> \* If message\_id is provided, posts to the thread containing that internal note.\
> \* Providing both thread\_id and message\_id returns a 400 response.\
> \* If neither is provided, posts to the most recently created Slack-backed internal thread. If none exists, creates a Pylon-only internal thread.\
> \* thread\_name names that newly created Pylon-only thread and is otherwise ignored.\
> \
> Empty thread\_id, message\_id, and thread\_name values are treated as omitted.\
> \
> \*\*Rate limit:\*\* 30 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"schemas":{"CreateIssueNoteRequestBody":{"properties":{"attachment_urls":{"description":"URLs of files to attach to this internal note.","items":{"type":"string"},"type":"array"},"body_html":{"description":"The body of the message in HTML.","type":"string"},"message_id":{"description":"The ID of an internal note whose thread should receive the new note. Use the top-level `id` from GET /issues/{id}/messages. Cannot be combined with thread_id.","type":"string"},"thread_id":{"description":"The ID of the internal thread to post the note to. Use the `id` field (not `thread_id`) from GET /issues/{id}/threads. Cannot be combined with message_id.","type":"string"},"thread_name":{"description":"Optional name for a new Pylon-only internal thread. Used only when neither thread_id nor message_id is provided and no Slack-backed internal thread exists.","type":"string"},"user_id":{"description":"Optional user ID to post the message as. If not provided, the API token user will be used.","type":"string"}},"required":["body_html"],"type":"object"},"CreateIssueNoteResponseBody":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/CreateIssueNoteResponseData"}],"nullable":true},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"CreateIssueNoteResponseData":{"properties":{"id":{"description":"The ID of the message.","type":"string"},"issue_id":{"description":"The ID of the issue.","type":"string"}},"required":["id","issue_id"],"type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}},"responses":{"CreateIssueNoteResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueNoteResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}}},"paths":{"/issues/{id}/note":{"post":{"description":"Posts an internal note on an issue thread. Not visible to the requester.\n\nThread selection:\n* If thread_id is provided, posts to that internal thread.\n* If message_id is provided, posts to the thread containing that internal note.\n* Providing both thread_id and message_id returns a 400 response.\n* If neither is provided, posts to the most recently created Slack-backed internal thread. If none exists, creates a Pylon-only internal thread.\n* thread_name names that newly created Pylon-only thread and is otherwise ignored.\n\nEmpty thread_id, message_id, and thread_name values are treated as omitted.\n\n**Rate limit:** 30 requests per minute","operationId":"CreateIssueNote","parameters":[{"description":"The ID of the issue.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIssueNoteRequestBody"}}}},"responses":{"200":{"$ref":"#/components/responses/CreateIssueNoteResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Create an internal note on an issue","tags":["messages"]}}}}
```

## Redact a message

> Permanently replaces a message's stored content with redacted\_body\_message and optionally deletes its attachments. This action cannot be undone.\
> When omitted, redacted\_body\_message defaults to "This message has been redacted." and redact\_attachments defaults to true.\
> \
> \*\*Rate limit:\*\* 120 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"schemas":{"RedactMessageRequestBody":{"properties":{"redact_attachments":{"description":"Whether to permanently delete the message's attachments. Defaults to true.","type":"boolean"},"redacted_body_message":{"description":"Replacement message body in HTML. The caller is responsible for replacing any sensitive portions. Defaults to \"This message has been redacted.\"","type":"string"}},"type":"object"},"RedactMessageResponseBody":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Message"}],"nullable":true},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"Message":{"properties":{"author":{"allOf":[{"$ref":"#/components/schemas/MessageAuthor"}],"nullable":true},"author_unverified":{"description":"Whether this message's author identity has NOT been verified. True for public form submissions, unverified chat widget visitors, and emails that failed sender authentication. For emails, read email_info.sender_authentication_status to tell an authentication failure apart from the other cases.","type":"boolean"},"email_info":{"$ref":"#/components/schemas/EmailMessageInfo"},"file_urls":{"description":"The URLs of the files in the message, if any. Signed download URLs. Fetch with a plain GET, no Authorization header.","items":{"type":"string"},"type":"array"},"id":{"description":"The top-level Pylon message ID. Use this value as message_id when replying or when targeting an internal note's thread.","type":"string"},"is_private":{"description":"Whether the message is an internal note. If true, the message is not visible to the requester; if false, it is customer-visible.","type":"boolean"},"message_html":{"description":"The HTML body of the message.","type":"string"},"source":{"description":"The source of the message.","type":"string"},"thread_id":{"description":"The Pylon internal thread ID. This is set only for internal notes and can be passed as thread_id when creating an internal note.","type":"string"},"timestamp":{"description":"The time at which the message was created.","format":"date-time","type":"string"}},"required":["author_unverified","id","is_private","message_html","source","timestamp"],"type":"object"},"MessageAuthor":{"properties":{"avatar_url":{"type":"string"},"contact":{"$ref":"#/components/schemas/MiniContact"},"name":{"type":"string"},"user":{"$ref":"#/components/schemas/MiniUser"}},"required":["name"],"type":"object"},"MiniContact":{"properties":{"email":{"description":"The email of the contact.","type":"string"},"id":{"description":"The ID of the contact.","type":"string"}},"required":["id"],"type":"object"},"MiniUser":{"properties":{"email":{"description":"The email of the user.","type":"string"},"id":{"description":"The ID of the user.","type":"string"}},"required":["id"],"type":"object"},"EmailMessageInfo":{"properties":{"bcc_emails":{"description":"The email addresses of the BCC recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"},"cc_emails":{"description":"The email addresses of the CC recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"},"from_email":{"description":"The email address of the sender of the message.","type":"string"},"message_id":{"description":"The RFC 5322 Message-ID header value for this email. This is a provider-specific identifier, not the top-level Pylon message ID, and cannot be used as message_id when posting a reply or internal note.","type":"string"},"opens":{"description":"When each recipient first opened an email Pylon sent, at most one entry per recipient.\nAlways empty for inbound mail and for mail sent through a connected personal email account.\nOpen tracking is approximate: clients that prefetch images (such as Apple Mail Privacy Protection)\ncan report opens that never happened, and clients that block images report none.","items":{"$ref":"#/components/schemas/EmailEvent"},"nullable":true,"type":"array"},"sender_authentication_status":{"description":"The SPF/DKIM sender authentication result recorded by Pylon's inbound mail provider.\nOne of \"pass\", \"fail\", or \"unknown\".\n\"fail\" means SPF failed outright, or the message carried a DKIM signature that did not validate.\n\"pass\" means SPF passed, or a DKIM signature validated.\n\"unknown\" means nothing vouched for the sender and must not be read as a pass. It covers\nmail Pylon sent, mail synced from a personal email integration, submissions stored as email\nmessages, and senders whose domain published no SPF or DKIM records to check against.","type":"string"},"to_emails":{"description":"The email addresses of the recipients of the message.","items":{"type":"string"},"nullable":true,"type":"array"}},"required":["from_email","message_id","sender_authentication_status"],"type":"object"},"EmailEvent":{"properties":{"email":{"description":"The email address of the recipient the event applies to.","type":"string"},"time":{"description":"When the event happened, in RFC 3339 format.","type":"string"}},"required":["email","time"],"type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}},"responses":{"RedactMessageResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedactMessageResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}}},"paths":{"/issues/{id}/messages/{message_id}/redact":{"post":{"description":"Permanently replaces a message's stored content with redacted_body_message and optionally deletes its attachments. This action cannot be undone.\nWhen omitted, redacted_body_message defaults to \"This message has been redacted.\" and redact_attachments defaults to true.\n\n**Rate limit:** 120 requests per minute","operationId":"RedactMessage","parameters":[{"description":"The ID of the issue that the message belongs to.","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"The ID of the message to redact.","in":"path","name":"message_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedactMessageRequestBody"}}}},"responses":{"200":{"$ref":"#/components/responses/RedactMessageResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Redact a message","tags":["messages"]}}}}
```

## Delete a message

> Permanently deletes a message from an issue and its connected external system.\
> \
> \*\*Rate limit:\*\* 30 requests per minute

```json
{"openapi":"3.0.3","info":{"title":"Pylon API.","version":"1.0.0"},"tags":[],"servers":[{"description":"US region","url":"https://api.usepylon.com"},{"description":"EU region","url":"https://api.eu.usepylon.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"Authorization: Bearer <token>","scheme":"bearer","type":"http"}},"responses":{"DeleteMessageResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteMessageResponseBody"}}},"description":""},"BadRequestApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request was invalid or could not be completed."},"UnauthorizedApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request could not be authenticated for this API."},"ForbiddenApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The authenticated caller or organization is not allowed to access this endpoint or operation."},"ErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":""},"TooManyRequestsApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"The request exceeded the applicable rate limit.","headers":{"Retry-After":{"description":"Seconds until the next request to this endpoint is permitted.","schema":{"format":"int64","type":"integer"}},"X-Retry-After":{"description":"Seconds until the full per-minute allowance is restored. Capacity returns gradually before then.","schema":{"format":"int64","type":"integer"}}}},"InternalServerErrorApiResponse":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorApiResponseBody"}}},"description":"An unexpected internal error occurred."}},"schemas":{"DeleteMessageResponseBody":{"properties":{"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"},"ErrorApiResponseBody":{"properties":{"code":{"description":"A stable machine-readable identifier for this failure, safe to branch on\ninstead of the message text. Omitted when the failure has no assigned code.\n\nKnown values: `recipients_suppressed`, `email_bounced`, `internal_issue_reply_not_allowed`, `duplicate_object`, `invalid_authorization_header`, `invalid_api_token`, `invalid_oauth_token`, `wrong_region_token`, `organization_deactivated`, `organization_suspended`, `permission_denied`, `oauth_not_permitted`, `rate_limited`, `not_found`, `method_not_allowed`, `payload_too_large`, `invalid_request_body`, `internal_error`, `invalid_webhook_credentials`, `organization_inactive`. This list is not exhaustive.","type":"string"},"errors":{"description":"The list of errors.","items":{"type":"string"},"type":"array"},"exists_id":{"description":"The ID of the object that already exists if this is a duplicate object error.","type":"string"},"request_id":{"description":"The request ID for tracking.","type":"string"}},"required":["request_id"],"type":"object"}}},"paths":{"/issues/{id}/messages/{message_id}":{"delete":{"description":"Permanently deletes a message from an issue and its connected external system.\n\n**Rate limit:** 30 requests per minute","operationId":"DeleteMessage","parameters":[{"description":"The ID of the issue that the message belongs to.","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"The ID of the message to delete.","in":"path","name":"message_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/DeleteMessageResponse"},"400":{"$ref":"#/components/responses/BadRequestApiResponse"},"401":{"$ref":"#/components/responses/UnauthorizedApiResponse"},"403":{"$ref":"#/components/responses/ForbiddenApiResponse"},"404":{"$ref":"#/components/responses/ErrorApiResponse"},"429":{"$ref":"#/components/responses/TooManyRequestsApiResponse"},"500":{"$ref":"#/components/responses/InternalServerErrorApiResponse"}},"summary":"Delete a message","tags":["messages"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.usepylon.com/pylon-docs/developer/api/api-reference/messages.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
