Skip to content

trader.mail ​

9 methods on trader.mail. Each returns the answer's data and throws NoviqaError on a failed answer.

list ​

GET/trader/v1/mail

List the own mailbox (trader)

One page of the caller's own folder: inbox (default), sent or draft. Inbox and sent come one row per thread, newest thread first: the row is the thread's newest message, thread_count is how many messages of the thread the folder holds and read is false while any of them is unread; drafts come one row each, newest first. total counts threads (drafts: drafts), unread counts unread messages. page is 1-based; limit defaults to 50, values outside 1-200 fall back to 50.

More details

With thread (a thread_id) the answer is instead a plain array of every inbox and sent message of that thread, oldest first, and all of them are marked read; folder, page and limit are ignored.

A trader account whose group has mail switched off gets an empty page with enabled false (an empty array for thread); staff always have a mailbox.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
folderstring · query
threadstring · query
one thread across inbox and sent, oldest first
pageinteger · query
limitinteger · query
Returns
Promise<Page>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.list({
  folder: "string",
  thread: "string",
  page: 1
})
bash
curl -X GET "$NOVIQA_API_URL/trader/v1/mail?folder=string&thread=string&page=1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "enabled": true,
    "items": [
      {
        "attachments": [
          {}
        ],
        "body": "string",
        "created_at": "2026-09-25T10:15:00Z",
        "draft": {},
        "folder": "string",
        "from": 1,
        "from_name": "string",
        "id": 1,
        "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
        "read": true,
        "recipients": "string",
        "subject": "string"
      }
    ],
    "page": 1,
    "total": 1,
    "unread": 1
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.list(query?: { folder?, thread?, page?, limit? }, options?: RequestOptions): Promise<mail.Page>

create ​

POST/trader/v1/mail

Write to a staff mailbox

Sends the account's message to one of its mailboxes: to must be a login from GET /trader/v1/mailboxes (staff with the mailbox right whose scope covers the account's group). subject is required (1-256 characters, one line), body is plain text up to 64 KiB. Attachments: up to 5 files per message, each 1 byte to 1 MB, 2 MB together (files already uploaded onto the draft count too); the name must be a plain file name of up to 128 characters (no path, quotes or line breaks) ending in .png, .jpg, .jpeg, .bmp, .gif, .zip, .7z, .doc, .docx, .xls, .xlsx, .odt, .rtf, .csv, .txt, .log or .pdf. In JSON bodies content is the file base64-encoded; the whole request may be 4 MB at most. reply_to (a mail the account holds) joins its thread; draft_id sends from that draft (its files go along, the draft is removed). Refused when the account's group has mail switched off.

More details

Answers the account's sent copy; the staff member gets an inbox copy and a mail socket message; a journal line is written. Not idempotent.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
Request body
attachmentsNewAttachment_input[]
bodystring
draft_idinteger
reply_tointeger
subjectstring
tointeger
Login is the numeric identity of every account, trader or staff.
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
403forbidden: you do not have access to this action
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.create({
  body: "Hello, when will my withdrawal arrive?",
  subject: "Withdrawal question",
  to: 1000
})
bash
curl -X POST "$NOVIQA_API_URL/trader/v1/mail" \
  -H "Authorization: Bearer $NOVIQA_TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
  "body": "Hello, when will my withdrawal arrive?",
  "subject": "Withdrawal question",
  "to": 1000
}'
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.create(body: mail.TraderMessage, options?: RequestOptions): Promise<models.Mail>

drafts ​

POST/trader/v1/mail/drafts

Save a draft (trader)

Stores what the caller is writing in the draft folder and answers it as saved. id 0 (or left out) makes a new draft; an id of one of the caller's drafts rewrites it (same as PUT). Staff address a draft with to_logins (up to 1000) or to_group (a group mask, up to 128 characters) and may set email; a trader account uses to (a staff mailbox login from GET /trader/v1/mailboxes) and the staff fields are ignored. reply_to (a non-draft mail the caller holds) keeps the draft in that thread. Nothing is checked against scope or mailboxes here — sending does that — and the subject may still be empty; it must fit 256 characters on one line and the body 64 KiB. Upload files with POST …/mail/drafts/{id}/attachments. A trader whose group has mail switched off is refused.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
Request body
bodystring
emailboolean
idinteger
reply_tointeger
subjectstring
tointeger
Login is the numeric identity of every account, trader or staff.
to_groupstring
to_loginsinteger[]
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
403forbidden: you do not have access to this action
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.drafts({
  body: "Dear {{name}}, …",
  email: true,
  subject: "Margin requirements update",
  to_logins: [
    10001,
    10002
  ]
})
bash
curl -X POST "$NOVIQA_API_URL/trader/v1/mail/drafts" \
  -H "Authorization: Bearer $NOVIQA_TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
  "body": "Dear {{name}}, …",
  "email": true,
  "subject": "Margin requirements update",
  "to_logins": [
    10001,
    10002
  ]
}'
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.drafts(body: mail.Draft, options?: RequestOptions): Promise<models.Mail>

updateDrafts ​

PUT/trader/v1/mail/drafts/{id}

Rewrite a draft (trader)

Replaces the whole draft named in the URL (any id in the body is overridden by the URL). Same rules as POST …/mail/drafts; fields left out are cleared, not kept. Its uploaded files stay. Answers the draft as saved.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
Request body
bodystring
emailboolean
idinteger
reply_tointeger
subjectstring
tointeger
Login is the numeric identity of every account, trader or staff.
to_groupstring
to_loginsinteger[]
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
403forbidden: you do not have access to this action
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.updateDrafts(1, {
  body: "Dear {{name}}, …",
  subject: "Holiday trading hours",
  to_group: "real\\*"
})
bash
curl -X PUT "$NOVIQA_API_URL/trader/v1/mail/drafts/1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
  "body": "Dear {{name}}, …",
  "subject": "Holiday trading hours",
  "to_group": "real\\*"
}'
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.updateDrafts(id: number, body: mail.Draft, options?: RequestOptions): Promise<models.Mail>

draftsAttachments ​

POST/trader/v1/mail/drafts/{id}/attachments

Upload a file onto a draft (trader)

Uploads one file as multipart/form-data field file (the only field read; the part's file name becomes the attachment name, path stripped). The file must be 1 byte to 1 MB; with the files already on the draft at most 5 files and 2 MB together; the name must be a plain file name of up to 128 characters with an allowed extension (.png, .jpg, .jpeg, .bmp, .gif, .zip, .7z, .doc, .docx, .xls, .xlsx, .odt, .rtf, .csv, .txt, .log, .pdf). Sending the draft (with draft_id) sends its files. Answers the draft with its file list. A trader whose group has mail switched off is refused.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
403forbidden: you do not have access to this action
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.draftsAttachments(1)
bash
curl -X POST "$NOVIQA_API_URL/trader/v1/mail/drafts/1/attachments" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.draftsAttachments(id: number, options?: RequestOptions): Promise<models.Mail>

deleteDraftsAttachments ​

DELETE/trader/v1/mail/drafts/{id}/attachments/{file}

Remove a file from a draft (trader)

Deletes one uploaded file from the caller's draft and answers the draft with its remaining files.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
fileinteger · pathrequired
Attachment id, from the draft's attachments.
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.deleteDraftsAttachments(1, 1)
bash
curl -X DELETE "$NOVIQA_API_URL/trader/v1/mail/drafts/1/attachments/1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.deleteDraftsAttachments(id: number, file: number, options?: RequestOptions): Promise<models.Mail>

retrieve ​

GET/trader/v1/mail/{id}

Read one mail (trader)

One message the caller holds (any folder), with its file list. Reading an unread inbox message marks it read. Download a file with GET …/mail/{id}/attachments/{file}.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
Returns
Promise<Mail>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.retrieve(1)
bash
curl -X GET "$NOVIQA_API_URL/trader/v1/mail/1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": {
    "attachments": [
      {
        "id": 1,
        "name": "Ann Smith",
        "size": 1
      }
    ],
    "body": "string",
    "created_at": "2026-09-25T10:15:00Z",
    "draft": {
      "email": "ann@example.com",
      "reply_to": 1,
      "to": 1,
      "to_group": "string",
      "to_logins": [
        1
      ]
    },
    "folder": "string",
    "from": 1,
    "from_name": "string",
    "id": 1,
    "message_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
    "read": true,
    "recipients": "string",
    "subject": "string"
  },
  "request_id": "5b7f2c1e"
}
ts
trader.mail.retrieve(id: number, options?: RequestOptions): Promise<models.Mail>

delete ​

DELETE/trader/v1/mail/{id}

Delete one mail (trader)

Removes the caller's own copy (inbox, sent or draft); other people's copies stay. The files go when the last copy of the message is gone.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
Returns
Promise<null>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.csrf_invalid: request refused: reload the page and try again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.delete(1)
bash
curl -X DELETE "$NOVIQA_API_URL/trader/v1/mail/1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
json
{
  "success": true,
  "code": "ok",
  "message": "done",
  "data": null,
  "request_id": "5b7f2c1e"
}
ts
trader.mail.delete(id: number, options?: RequestOptions): Promise<null>

retrieveAttachments ​

GET/trader/v1/mail/{id}/attachments/{file}

Download a mail attachment (trader)

The bytes of one file of a message the caller holds a copy of, sent as application/octet-stream with Content-Disposition: attachment; filename=… and X-Content-Type-Options: nosniff: save it, never show it inline. The file ids are in the mail's attachments.

Parameters
X-HST-Accountstring · header
Intended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
idinteger · pathrequired
Numeric id.
fileinteger · pathrequired
Attachment id, from the mail's attachments.
Returns
Promise<Response>
The answer's data.
Errors
400invalid_input: invalid input
401auth.session_expired: session expired, sign in again
403auth.invalid_terminal: this terminal cannot be used here
403auth.otp_enrol_required: your group requires one-time codes: set them up to continue
403auth.password_change_required: you must change your password first
404not_found: not found
409auth.account_changed: the signed-in account changed; sign in again before continuing
500internal: something went wrong
ts
import { trader } from "@/lib/noviqa"

const data = await trader.mail.retrieveAttachments(1, 1)
bash
curl -X GET "$NOVIQA_API_URL/trader/v1/mail/1/attachments/1" \
  -H "Authorization: Bearer $NOVIQA_TOKEN"
ts
// application/octet-stream file: the SDK returns the raw Response
ts
trader.mail.retrieveAttachments(id: number, file: number, options?: RequestOptions): Promise<Response>