Reference: Applications

Application and appeal forms, what people sent, and deciding it.

Good to know

Every request needs your key: Authorization: Bearer tfy_…. Replace YOUR_SERVER_ID with your Discord server id. Errors are explained in Requests, errors and limits.

GET /forms

GET /guilds/{guildId}/forms

Key permissionforms.read (See applications and appeals)

Query parameters

Added to the address after a ?, like ?limit=10&order=asc.

FieldTypeRequiredWhat it is
kind"application" | "appeal"NoOnly applications, or only appeals.
state"draft" | "open" | "paused" | "archived"NoOnly forms in this state.

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/forms" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"
Answer · 200
{
  "items": [
    {
      "id": "frm_01M5TXYKPJRX6P75ZMRW5SFGW4",
      "kind": "application",
      "title": "Moderator application",
      "description": null,
      "state": "open",
      "version": 1,
      "submitAccess": "anyone",
      "oneOpenSubmission": true,
      "publishOnPublicPage": false,
      "appealPunishmentType": null,
      "requirePunishment": true,
      "scope": "guild",
      "createdAt": "2026-10-26T01:42:11.410Z"
    }
  ]
}

POST /forms

POST /guilds/{guildId}/forms

Key permissionforms.write (Decide applications and edit forms)

Request body

JSON, sent with Content-Type: application/json.

kind: "application"

FieldTypeRequiredWhat it is
titlestringYes1 to 120 characters
descriptionstring or nullNoat most 2000 characters · default null
questionsarray of objectsYes1 to 100 items
questions[].idstringYes1 to 40 characters
questions[].type"short_text" | "long_text" | "number" | "single_choice" | "multiple_choice" | "date" | "yes_no" | "file" | "section"Yes
questions[].labelstringYes1 to 200 characters
questions[].descriptionstringNoat most 500 characters
questions[].requiredbooleanNodefault false
questions[].optionsarray of stringNoat most 25 items
questions[].minLengthintegerNo0 to 4000
questions[].maxLengthintegerNo1 to 4000
questions[].minnumberNo
questions[].maxnumberNo
questions[].showIfobjectNo
questions[].showIf.questionIdstringYes1 to 40 characters
questions[].showIf.equalsobject, one of the shapes belowYes
questions[].logicobjectNo
questions[].logic.match"all" | "any"Nodefault "all"
questions[].logic.conditionsarray of objectsYes1 to 10 items
questions[].logic.conditions[].questionIdstringYes1 to 40 characters
questions[].logic.conditions[].is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].logic.conditions[].valueobject, one of the shapes belowNo
questions[].stopobjectNo
questions[].stop.is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].stop.valueobject, one of the shapes belowNo
questions[].stop.messagestringYes1 to 500 characters
submitAccess"anyone" | "link" | "verified"Nodefault "anyone"
oneOpenSubmissionbooleanNodefault true
publishOnPublicPagebooleanNodefault false
kind"application"Yes

kind: "appeal"

FieldTypeRequiredWhat it is
titlestringYes1 to 120 characters
descriptionstring or nullNoat most 2000 characters · default null
questionsarray of objectsYes1 to 100 items
questions[].idstringYes1 to 40 characters
questions[].type"short_text" | "long_text" | "number" | "single_choice" | "multiple_choice" | "date" | "yes_no" | "file" | "section"Yes
questions[].labelstringYes1 to 200 characters
questions[].descriptionstringNoat most 500 characters
questions[].requiredbooleanNodefault false
questions[].optionsarray of stringNoat most 25 items
questions[].minLengthintegerNo0 to 4000
questions[].maxLengthintegerNo1 to 4000
questions[].minnumberNo
questions[].maxnumberNo
questions[].showIfobjectNo
questions[].showIf.questionIdstringYes1 to 40 characters
questions[].showIf.equalsobject, one of the shapes belowYes
questions[].logicobjectNo
questions[].logic.match"all" | "any"Nodefault "all"
questions[].logic.conditionsarray of objectsYes1 to 10 items
questions[].logic.conditions[].questionIdstringYes1 to 40 characters
questions[].logic.conditions[].is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].logic.conditions[].valueobject, one of the shapes belowNo
questions[].stopobjectNo
questions[].stop.is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].stop.valueobject, one of the shapes belowNo
questions[].stop.messagestringYes1 to 500 characters
submitAccess"anyone" | "link" | "verified"Nodefault "anyone"
oneOpenSubmissionbooleanNodefault true
publishOnPublicPagebooleanNodefault false
kind"appeal"Yes
appealPunishmentType"ban" | "mute" | "warning" | "kick" | "serverban"Yes
requirePunishmentbooleanNodefault true

Example

curl -X POST "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/forms" \
  -H "Authorization: Bearer $TECHNIFIED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"application","title":"Moderator application","questions":[{"id":"why","type":"long_text","label":"Why do you want to moderate?","required":true},{"id":"age","type":"number","label":"How old are you?","required":true,"min":13}]}'
Answer · 201
{
  "id": "frm_01M5TXYKPJRX6P75ZMRW5SFGW4",
  "kind": "application",
  "title": "Moderator application",
  "description": null,
  "state": "draft",
  "version": 1,
  "submitAccess": "anyone",
  "oneOpenSubmission": true,
  "publishOnPublicPage": false,
  "appealPunishmentType": null,
  "requirePunishment": true,
  "scope": "guild",
  "questions": [
    {
      "id": "why",
      "type": "long_text",
      "label": "Why do you want to moderate?",
      "required": true
    },
    {
      "id": "age",
      "type": "number",
      "label": "How old are you?",
      "required": true,
      "min": 13
    }
  ],
  "createdAt": "2026-10-26T01:42:11.410Z"
}

GET /forms/{formId}

GET /guilds/{guildId}/forms/{formId}

The form to fill in. This is the one a member loads.

Key permissionAny key of this server.

In the address

FieldTypeRequiredWhat it is
formIdstringYesA form’s id (frm_…).

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/forms/FORMID" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"

PATCH /forms/{formId}

PATCH /guilds/{guildId}/forms/{formId}

Edits a form. Writes a new version rather than changing the old one. An appeal form also takes appealPunishmentType and requirePunishment (422 on an application).

Key permissionforms.write (Decide applications and edit forms)

In the address

FieldTypeRequiredWhat it is
formIdstringYesA form’s id (frm_…).

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredWhat it is
titlestringNo1 to 120 characters
descriptionstring or nullNoat most 2000 characters
questionsarray of objectsNo1 to 100 items
questions[].idstringYes1 to 40 characters
questions[].type"short_text" | "long_text" | "number" | "single_choice" | "multiple_choice" | "date" | "yes_no" | "file" | "section"Yes
questions[].labelstringYes1 to 200 characters
questions[].descriptionstringNoat most 500 characters
questions[].requiredbooleanNodefault false
questions[].optionsarray of stringNoat most 25 items
questions[].minLengthintegerNo0 to 4000
questions[].maxLengthintegerNo1 to 4000
questions[].minnumberNo
questions[].maxnumberNo
questions[].showIfobjectNo
questions[].showIf.questionIdstringYes1 to 40 characters
questions[].showIf.equalsobject, one of the shapes belowYes
questions[].logicobjectNo
questions[].logic.match"all" | "any"Nodefault "all"
questions[].logic.conditionsarray of objectsYes1 to 10 items
questions[].logic.conditions[].questionIdstringYes1 to 40 characters
questions[].logic.conditions[].is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].logic.conditions[].valueobject, one of the shapes belowNo
questions[].stopobjectNo
questions[].stop.is"equals" | "not_equals" | "includes" | "not_includes" | "at_least" | "at_most" | "contains" | "not_contains" | "answered" | "empty"Yes
questions[].stop.valueobject, one of the shapes belowNo
questions[].stop.messagestringYes1 to 500 characters
submitAccess"anyone" | "link" | "verified"No
oneOpenSubmissionbooleanNo
publishOnPublicPagebooleanNo
state"draft" | "open" | "paused" | "archived"No
appealPunishmentType"ban" | "mute" | "warning" | "kick" | "serverban"No
requirePunishmentbooleanNo

Example

curl -X PATCH "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/forms/FORMID" \
  -H "Authorization: Bearer $TECHNIFIED_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

GET /submissions

GET /guilds/{guildId}/submissions

The queue.

Key permissionforms.read (See applications and appeals)

Query parameters

Added to the address after a ?, like ?limit=10&order=asc.

FieldTypeRequiredWhat it is
limitintegerNoHow many to answer with at most, 1 to 100.1 to 100 · default 25
cursorstringNoThe nextCursor of the page before, to get the next page. Absent: the first page.at most 64 characters
order"asc" | "desc"Nodesc for newest first, asc for oldest first.default "desc"
formIdstringNoOnly submissions to this form.at most 40 characters
state"submitted" | "approved" | "declined" | "withdrawn"NoOnly submissions in this state, such as submitted (waiting).
discordUserIdstringNoOnly what this member sent.at most 32 characters
punishmentIdstringNoOnly the appeals against this punishment.at most 40 characters
kind"application" | "appeal"NoOnly applications, or only appeals.

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"
Answer · 200
{
  "items": [
    {
      "id": "sub_01M5TXYKWGTNCFFEXH6CZ433YB",
      "formId": "frm_01M5TXYKPJRX6P75ZMRW5SFGW4",
      "formVersion": 1,
      "guildId": "gld_01M5TXYJPNJZ19BDXJCNTD8WDW",
      "discordUserId": "17929789298638349990005",
      "state": "submitted",
      "answers": {
        "why": "I know the rules and I am online every day.",
        "age": 17
      },
      "punishmentId": null,
      "decidedBy": null,
      "decidedAt": null,
      "decisionNote": null,
      "notified": false,
      "createdAt": "2026-10-26T01:42:11.600Z"
    }
  ],
  "nextCursor": null
}

GET /submissions/{submissionId}

GET /guilds/{guildId}/submissions/{submissionId}

One submission, with the version of the form it answered, and openTicket ({ id, number } or null): the ticket still open about it.

Key permissionforms.read (See applications and appeals)

In the address

FieldTypeRequiredWhat it is
submissionIdstringYesA submission’s id (sub_…).

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/SUBMISSIONID" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"
Answer · 200
{
  "id": "sub_01M5TXYKWGTNCFFEXH6CZ433YB",
  "formId": "frm_01M5TXYKPJRX6P75ZMRW5SFGW4",
  "formVersion": 1,
  "guildId": "gld_01M5TXYJPNJZ19BDXJCNTD8WDW",
  "discordUserId": "17929789298638349990005",
  "state": "submitted",
  "answers": {
    "why": "I know the rules and I am online every day.",
    "age": 17
  },
  "punishmentId": null,
  "decidedBy": null,
  "decidedAt": null,
  "decisionNote": null,
  "notified": false,
  "createdAt": "2026-10-26T01:42:11.600Z",
  "questions": [
    {
      "id": "why",
      "type": "long_text",
      "label": "Why do you want to moderate?",
      "required": true
    },
    {
      "id": "age",
      "type": "number",
      "label": "How old are you?",
      "required": true,
      "min": 13
    }
  ],
  "openTicket": null
}

GET /submissions/{submissionId}/comments

GET /guilds/{guildId}/submissions/{submissionId}/comments

Key permissionforms.read (See applications and appeals)

In the address

FieldTypeRequiredWhat it is
submissionIdstringYesA submission’s id (sub_…).

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/SUBMISSIONID/comments" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"

POST /submissions/{submissionId}/comments

POST /guilds/{guildId}/submissions/{submissionId}/comments

Key permissionforms.write (Decide applications and edit forms)

In the address

FieldTypeRequiredWhat it is
submissionIdstringYesA submission’s id (sub_…).

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredWhat it is
bodystringYesThe note. Only staff see it, never the person.1 to 2000 characters

Example

curl -X POST "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/SUBMISSIONID/comments" \
  -H "Authorization: Bearer $TECHNIFIED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"…"}'

POST /submissions/{submissionId}/decide

POST /guilds/{guildId}/submissions/{submissionId}/decide

Approves or declines, and can lift the punishment an appeal is about.

Key permissionforms.write (Decide applications and edit forms)

In the address

FieldTypeRequiredWhat it is
submissionIdstringYesA submission’s id (sub_…).

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredWhat it is
decision"approved" | "declined"Yesapproved or declined. Final.
notestring or nullNoA word to the person, sent in the direct message with the decision.at most 2000 characters · default null
liftPunishmentbooleanNoAppeals only: true lifts the punishment the appeal is about, in the same step.default false

Example

curl -X POST "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/SUBMISSIONID/decide" \
  -H "Authorization: Bearer $TECHNIFIED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"decision":"approved","note":"Welcome to the team!"}'
Answer · 200
{
  "id": "sub_01M5TXYKWGTNCFFEXH6CZ433YB",
  "formId": "frm_01M5TXYKPJRX6P75ZMRW5SFGW4",
  "formVersion": 1,
  "guildId": "gld_01M5TXYJPNJZ19BDXJCNTD8WDW",
  "discordUserId": "17929789298638349990005",
  "state": "approved",
  "answers": {
    "why": "I know the rules and I am online every day.",
    "age": 17
  },
  "punishmentId": null,
  "decidedBy": "key_01M5TXYJPZQGNT2KXZG3ZBA672",
  "decidedAt": "2026-10-26T01:42:11.722Z",
  "decisionNote": "Welcome to the team!",
  "notified": false,
  "createdAt": "2026-10-26T01:42:11.600Z",
  "punishmentLifted": false
}

POST /submissions/{submissionId}/ticket

POST /guilds/{guildId}/submissions/{submissionId}/ticket

Continues a submission as a ticket. 409 ticket_open while one is still open about it.

Key permissionforms.write (Decide applications and edit forms), tickets.write (Handle tickets)

In the address

FieldTypeRequiredWhat it is
submissionIdstringYesA submission’s id (sub_…).

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredWhat it is
panelIdstringNoat most 40 characters

Example

curl -X POST "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/SUBMISSIONID/ticket" \
  -H "Authorization: Bearer $TECHNIFIED_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

GET /submissions/uploads/{uploadId}

GET /guilds/{guildId}/submissions/uploads/{uploadId}

A file somebody attached.

Key permissionforms.read (See applications and appeals)

In the address

FieldTypeRequiredWhat it is
uploadIdstringYesA file uploaded with a form (upl_…), from the submission’s answers.

No request body.

Example

curl -X GET "https://api.technified.xyz/v1/guilds/YOUR_SERVER_ID/submissions/uploads/UPLOADID" \
  -H "Authorization: Bearer $TECHNIFIED_KEY"

Still stuck? Get help from the Technified team.