Skip to content

Forms SDK

Examples use a client built as forms = FormsClient(oauth_token="…", organization_id="…").

FormsClient

FormsClient(*, oauth_token: str, organization_id: str, http: HTTPConfig | None = None, transport: BaseTransport | None = None, before_send: BeforeSend | None = None)

Bases: DomainClient

Holds the per-resource forms clients, all sharing one httpx2 core session.

Examples:

>>> forms.me.get().email
'ann@example.com'

probe

probe() -> None

One cheap authenticated read: the current user.

me

MeClient

MeClient(*, session: SyncSession)

Bases: Resource

The authenticated Forms user.

get

get() -> User

GET /users/me → the authenticated User (a safe auth probe).

Returns:

Type Description
User

The authenticated user.

Examples:

>>> forms.me.get().email
'ann@example.com'

surveys

SurveysClient

SurveysClient(*, session: SyncSession)

Bases: Resource

List, get, create, modify, delete, publish and unpublish forms.

list

list(*, limit: int | None = None, name: str | None = None, published: bool | None = None, ownership: str | None = None, group: str | None = None, favourite: bool | None = None, show_all: bool = False, orderby: str | None = None) -> ItemList[Survey]

GET /surveys → every form, page by page, at most limit (None = all).

Parameters:

Name Type Description Default
limit int | None

The most forms to return; None returns every form.

None
name str | None

Keep the forms whose name matches.

None
published bool | None

Keep only published (True) or only unpublished (False) forms.

None
ownership str | None

mine (created by the caller) or shared (open to the caller).

None
group str | None

Keep the forms of this group.

None
favourite bool | None

Keep only favourite (True) or only other (False) forms.

None
show_all bool

For an administrator, list every form of the organization.

False
orderby str | None

The sort, a comma list such as name,-modified,-count.

None

Returns:

Type Description
ItemList[Survey]

The forms.

Examples:

>>> forms.surveys.list(limit=500).root[0].name
'Onboarding'

get

get(survey_id: str) -> Survey

GET /surveys/{id} → a single Survey (settings).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
Survey

The form's settings.

Examples:

>>> forms.surveys.get("686d0a1b2c3d4e5f00000001").name
'Onboarding'

create

create(body: dict[str, Any]) -> Survey

POST /surveys — create a form from a ready body (a dumped SurveyCreate).

Parameters:

Name Type Description Default
body dict[str, Any]

The dumped SurveyCreate.

required

Returns:

Type Description
Survey

The created form, with its id.

Examples:

>>> forms.surveys.create({"name": "Onboarding", "language": "en"}).id
'686d0a1b2c3d4e5f00000001'

modify

modify(survey_id: str, body: dict[str, Any]) -> Survey

PATCH /surveys/{id} — only the keys present in body change (a SurveyUpdate).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The keys to change.

required

Returns:

Type Description
Survey

The updated form.

Examples:

>>> forms.surveys.modify("686d0a1b2c3d4e5f00000002", {"name": "Onboarding"}).name
'Onboarding'

delete

delete(survey_id: str) -> Ack

DELETE /surveys/{id} (204 No Content) → an :class:Ack.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
Ack

An acknowledgement naming the deleted form.

Examples:

>>> forms.surveys.delete("686d0a1b2c3d4e5f00000003").ok
True

publish

publish(survey_id: str) -> Ack

POST /surveys/{id}/publish → an :class:Ack.

Fails (typed YandexError) if the form is blocked, has hit its response cap, or is inside an unexpired response-period window.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
Ack

An acknowledgement naming the published form.

Examples:

>>> forms.surveys.publish("686d0a1b2c3d4e5f00000004").detail
'published survey 686d0a1b2c3d4e5f00000004'

unpublish

unpublish(survey_id: str) -> Ack

POST /surveys/{id}/unpublish → an :class:Ack (auto-publication forms included).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
Ack

An acknowledgement naming the unpublished form.

Examples:

>>> forms.surveys.unpublish("686d0a1b2c3d4e5f00000005").detail
'unpublished survey 686d0a1b2c3d4e5f00000005'

questions

QuestionsClient

QuestionsClient(*, session: SyncSession)

Bases: Resource

Get, list, create, modify, delete and move the questions of a form.

get

get(survey_id: str, question_id: str, *, with_slugs: bool = False) -> Question

GET /surveys/{id}/questions/{question_id} → a single :class:Question (settings).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
with_slugs bool

The API's flag of that name: refer to other questions by slug.

False

Returns:

Type Description
Question

The question.

Examples:

>>> forms.questions.get("686d0a1b2c3d4e5f00000010", "17").slug
'name'

list

list(survey_id: str) -> QuestionsResponse

GET /surveys/{id}/questions → every question, grouped into the {pages} envelope.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
QuestionsResponse

Every question, grouped by page.

Examples:

>>> forms.questions.list("686d0a1b2c3d4e5f00000010").pages[0].items[0].slug
'name'

create

create(survey_id: str, body: QuestionCreate) -> Question

POST /surveys/{id}/questions — append a question from a typed body.

body is one member of the :data:~ycli.yandex.forms.questions.models.QuestionCreate union (StringQuestion, EnumQuestion, …). The question lands at the end of the form; reorder it with :meth:move.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body QuestionCreate

The new question's settings.

required

Returns:

Type Description
Question

The created question, with its id.

Examples:

>>> from ycli.yandex.forms.questions.models import StringQuestion
>>> forms.questions.create("686d0a1b2c3d4e5f00000010", StringQuestion(label="Name")).id
17

modify

modify(survey_id: str, question_id: str, body: QuestionCreate) -> Question

PATCH /surveys/{id}/questions/{question_id} — replace a question's settings.

Takes the same typed body as :meth:create; its type must match the existing question.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
body QuestionCreate

The question's new settings.

required

Returns:

Type Description
Question

The updated question.

Examples:

>>> from ycli.yandex.forms.questions.models import StringQuestion
>>> forms.questions.modify(
...     "686d0a1b2c3d4e5f00000010", "22", StringQuestion(label="Name")
... ).label
'Name'

delete

delete(survey_id: str, question_id: str, *, force: bool = False) -> Ack

DELETE /surveys/{id}/questions/{question_id} → an :class:Ack.

The API refuses to delete a question that another question's display conditions still reference (400 dependency_error.question_condition): delete the condition first. force is sent, and the API ignores it (checked live on 2026-10-04).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
force bool

Ignored by the API: the display-conditions check is not skipped.

False

Returns:

Type Description
Ack

An acknowledgement naming the deleted question.

Examples:

>>> forms.questions.delete("686d0a1b2c3d4e5f00000010", "28").ok
True

move

move(survey_id: str, question_id: str, body: QuestionMove) -> QuestionMoveResult

POST /surveys/{id}/questions/{question_id}/move — reposition a question.

body names the target page (page / page_id / create_page) and position; the API ignores a bare position, so QuestionMove refuses one.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
body QuestionMove

The target page and position.

required

Returns:

Type Description
QuestionMoveResult

The result, carrying the moved question's id.

Examples:

>>> from ycli.yandex.forms.questions.models import QuestionMove
>>> forms.questions.move(
...     "686d0a1b2c3d4e5f00000010", "20", QuestionMove(page_id=55, position=2)
... ).id
20

conditions

ConditionsClient

ConditionsClient(*, session: SyncSession)

Bases: Resource

List, get, create, modify, delete and re-join the display-condition groups of a target.

question_list

question_list(survey_id: str, question_id: str) -> ConditionsResponse

GET /surveys/{id}/questions/{question_id}/conditions → {operator, items}.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.question_list("686d0a1b2c3d4e5f00000090", "17").operator
'or'

question_get

question_get(survey_id: str, question_id: str, condition_id: int) -> Condition

GET …/questions/{question_id}/conditions/{condition_id} → one group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
condition_id int

The condition group's id.

required

Returns:

Type Description
Condition

The condition group.

Examples:

>>> forms.conditions.question_get("686d0a1b2c3d4e5f00000090", "17", 102).id
102

question_create

question_create(survey_id: str, question_id: str, body: ConditionCreate) -> Condition

POST …/questions/{question_id}/conditions — add a group → it, with its id.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
body ConditionCreate

The new group: its operator and clauses.

required

Returns:

Type Description
Condition

The created group, with its id.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionCreate, ConditionItemWrite
>>> body = ConditionCreate(
...     operator="and",
...     items=[
...         ConditionItemWrite(
...             type="question", condition="gt", question="age100", value="18"
...         )
...     ],
... )
>>> forms.conditions.question_create("686d0a1b2c3d4e5f00000090", "17", body).id
103

question_modify

question_modify(survey_id: str, question_id: str, condition_id: int, body: ConditionUpdate) -> Condition

PATCH …/questions/{question_id}/conditions/{condition_id} — replace the group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
condition_id int

The condition group's id.

required
body ConditionUpdate

The full replacement group: its operator and clauses.

required

Returns:

Type Description
Condition

The replaced group.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionItemWrite, ConditionUpdate
>>> body = ConditionUpdate(
...     operator="or",
...     items=[ConditionItemWrite(type="language", condition="eq", value="ru")],
... )
>>> forms.conditions.question_modify("686d0a1b2c3d4e5f00000090", "17", 104, body).id
104

question_delete

question_delete(survey_id: str, question_id: str, condition_id: int) -> None

DELETE …/questions/{question_id}/conditions/{condition_id} (200, no body).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
condition_id int

The condition group's id.

required

Examples:

>>> forms.conditions.question_delete("686d0a1b2c3d4e5f00000090", "17", 106)

question_set_operator

question_set_operator(survey_id: str, question_id: str, operator: ConditionOperatorType) -> ConditionsResponse

PATCH …/questions/{question_id}/conditions — the operator BETWEEN groups.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
question_id str

The question's id.

required
operator ConditionOperatorType

The operator joining the groups: and or or.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.question_set_operator(
...     "686d0a1b2c3d4e5f00000090", "17", "or"
... ).operator
'or'

page_list

page_list(survey_id: str, page_id: int) -> ConditionsResponse

GET /surveys/{id}/pages/{page_id}/conditions → {operator, items}.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.page_list("686d0a1b2c3d4e5f00000090", 3).operator
'or'

page_get

page_get(survey_id: str, page_id: int, condition_id: int) -> Condition

GET …/pages/{page_id}/conditions/{condition_id} → one group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required
condition_id int

The condition group's id.

required

Returns:

Type Description
Condition

The condition group.

Examples:

>>> forms.conditions.page_get("686d0a1b2c3d4e5f00000090", 3, 202).id
202

page_create

page_create(survey_id: str, page_id: int, body: ConditionCreate) -> Condition

POST …/pages/{page_id}/conditions — add a group → it, with its id.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required
body ConditionCreate

The new group: its operator and clauses.

required

Returns:

Type Description
Condition

The created group, with its id.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionCreate, ConditionItemWrite
>>> body = ConditionCreate(
...     operator="and",
...     items=[
...         ConditionItemWrite(
...             type="question", condition="gt", question="age200", value="18"
...         )
...     ],
... )
>>> forms.conditions.page_create("686d0a1b2c3d4e5f00000090", 3, body).id
203

page_modify

page_modify(survey_id: str, page_id: int, condition_id: int, body: ConditionUpdate) -> Condition

PATCH …/pages/{page_id}/conditions/{condition_id} — replace the group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required
condition_id int

The condition group's id.

required
body ConditionUpdate

The full replacement group: its operator and clauses.

required

Returns:

Type Description
Condition

The replaced group.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionItemWrite, ConditionUpdate
>>> body = ConditionUpdate(
...     operator="or",
...     items=[ConditionItemWrite(type="language", condition="eq", value="ru")],
... )
>>> forms.conditions.page_modify("686d0a1b2c3d4e5f00000090", 3, 204, body).id
204

page_delete

page_delete(survey_id: str, page_id: int, condition_id: int) -> None

DELETE …/pages/{page_id}/conditions/{condition_id} (200, no body).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required
condition_id int

The condition group's id.

required

Examples:

>>> forms.conditions.page_delete("686d0a1b2c3d4e5f00000090", 3, 206)

page_set_operator

page_set_operator(survey_id: str, page_id: int, operator: ConditionOperatorType) -> ConditionsResponse

PATCH …/pages/{page_id}/conditions — the operator BETWEEN groups.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
page_id int

The page's id.

required
operator ConditionOperatorType

The operator joining the groups: and or or.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.page_set_operator("686d0a1b2c3d4e5f00000090", 3, "or").operator
'or'

submit_list

submit_list(survey_id: str) -> ConditionsResponse

GET /surveys/{id}/conditions → {operator, items}.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.submit_list("686d0a1b2c3d4e5f00000090").operator
'or'

submit_get

submit_get(survey_id: str, condition_id: int) -> Condition

GET /surveys/{id}/conditions/{condition_id} → one group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
condition_id int

The condition group's id.

required

Returns:

Type Description
Condition

The condition group.

Examples:

>>> forms.conditions.submit_get("686d0a1b2c3d4e5f00000090", 302).id
302

submit_create

submit_create(survey_id: str, body: ConditionCreate) -> Condition

POST /surveys/{id}/conditions — add a group → it, with its id.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body ConditionCreate

The new group: its operator and clauses.

required

Returns:

Type Description
Condition

The created group, with its id.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionCreate, ConditionItemWrite
>>> body = ConditionCreate(
...     operator="and",
...     items=[
...         ConditionItemWrite(
...             type="question", condition="gt", question="age300", value="18"
...         )
...     ],
... )
>>> forms.conditions.submit_create("686d0a1b2c3d4e5f00000090", body).id
303

submit_modify

submit_modify(survey_id: str, condition_id: int, body: ConditionUpdate) -> Condition

PATCH /surveys/{id}/conditions/{condition_id} — replace the group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
condition_id int

The condition group's id.

required
body ConditionUpdate

The full replacement group: its operator and clauses.

required

Returns:

Type Description
Condition

The replaced group.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionItemWrite, ConditionUpdate
>>> body = ConditionUpdate(
...     operator="or",
...     items=[ConditionItemWrite(type="language", condition="eq", value="ru")],
... )
>>> forms.conditions.submit_modify("686d0a1b2c3d4e5f00000090", 304, body).id
304

submit_delete

submit_delete(survey_id: str, condition_id: int) -> None

DELETE /surveys/{id}/conditions/{condition_id} (200, no body).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
condition_id int

The condition group's id.

required

Examples:

>>> forms.conditions.submit_delete("686d0a1b2c3d4e5f00000090", 306)

submit_set_operator

submit_set_operator(survey_id: str, operator: ConditionOperatorType) -> ConditionsResponse

PATCH /surveys/{id}/conditions — the operator BETWEEN groups.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
operator ConditionOperatorType

The operator joining the groups: and or or.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.submit_set_operator("686d0a1b2c3d4e5f00000090", "or").operator
'or'

hook_list

hook_list(survey_id: str, hook_id: int) -> ConditionsResponse

GET /surveys/{id}/hooks/{hook_id}/conditions → {operator, items}.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.hook_list("686d0a1b2c3d4e5f00000090", 11).operator
'or'

hook_get

hook_get(survey_id: str, hook_id: int, condition_id: int) -> Condition

GET …/hooks/{hook_id}/conditions/{condition_id} → one group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
condition_id int

The condition group's id.

required

Returns:

Type Description
Condition

The condition group.

Examples:

>>> forms.conditions.hook_get("686d0a1b2c3d4e5f00000090", 11, 402).id
402

hook_create

hook_create(survey_id: str, hook_id: int, body: ConditionCreate) -> Condition

POST …/hooks/{hook_id}/conditions — add a group → it, with its id.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
body ConditionCreate

The new group: its operator and clauses.

required

Returns:

Type Description
Condition

The created group, with its id.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionCreate, ConditionItemWrite
>>> body = ConditionCreate(
...     operator="and",
...     items=[
...         ConditionItemWrite(
...             type="question", condition="gt", question="age400", value="18"
...         )
...     ],
... )
>>> forms.conditions.hook_create("686d0a1b2c3d4e5f00000090", 11, body).id
403

hook_modify

hook_modify(survey_id: str, hook_id: int, condition_id: int, body: ConditionUpdate) -> Condition

PATCH …/hooks/{hook_id}/conditions/{condition_id} — replace the group.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
condition_id int

The condition group's id.

required
body ConditionUpdate

The full replacement group: its operator and clauses.

required

Returns:

Type Description
Condition

The replaced group.

Examples:

>>> from ycli.yandex.forms.conditions.models import ConditionItemWrite, ConditionUpdate
>>> body = ConditionUpdate(
...     operator="or",
...     items=[ConditionItemWrite(type="language", condition="eq", value="ru")],
... )
>>> forms.conditions.hook_modify("686d0a1b2c3d4e5f00000090", 11, 404, body).id
404

hook_delete

hook_delete(survey_id: str, hook_id: int, condition_id: int) -> None

DELETE …/hooks/{hook_id}/conditions/{condition_id} (200, no body).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
condition_id int

The condition group's id.

required

Examples:

>>> forms.conditions.hook_delete("686d0a1b2c3d4e5f00000090", 11, 406)

hook_set_operator

hook_set_operator(survey_id: str, hook_id: int, operator: ConditionOperatorType) -> ConditionsResponse

PATCH …/hooks/{hook_id}/conditions — the operator BETWEEN groups.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
operator ConditionOperatorType

The operator joining the groups: and or or.

required

Returns:

Type Description
ConditionsResponse

The target's operator and condition groups.

Examples:

>>> forms.conditions.hook_set_operator("686d0a1b2c3d4e5f00000090", 11, "or").operator
'or'

access

AccessClient

AccessClient(*, session: SyncSession)

Bases: Resource

Read and change who may edit and who may fill a form.

get

get(survey_id: str) -> ItemList[Permission]

GET /surveys/{id}/access → one permission per action (change, submit).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ItemList[Permission]

One permission per action.

Examples:

>>> forms.access.get("686d0a1b2c3d4e5f000000d0").root[0].access
'restricted'

set

set(survey_id: str, body: dict[str, Any]) -> ItemList[Permission]

POST /surveys/{id}/access — set one action's level from a dumped AccessUpdate.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped AccessUpdate: the action and its new access level.

required

Returns:

Type Description
ItemList[Permission]

The permissions after the change.

Examples:

>>> forms.access.set(
...     "686d0a1b2c3d4e5f000000d0", {"action": "submit", "access": "common"}
... ).root[1].access
'common'

grant

grant(survey_id: str, body: dict[str, Any]) -> ItemList[Permission]

POST /surveys/{id}/access/grant — add a user or group (a dumped AccessGrant).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped AccessGrant: the action and the user or group to add.

required

Returns:

Type Description
ItemList[Permission]

The permissions after the change.

Examples:

>>> forms.access.grant(
...     "686d0a1b2c3d4e5f000000d0",
...     {"action": "change", "user": {"uid": "7001", "cloud_uid": "cloud-7001"}},
... ).root[0].action
'change'

revoke

revoke(survey_id: str, body: dict[str, Any]) -> ItemList[Permission]

POST /surveys/{id}/access/revoke — remove a user or group (AccessRevoke).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped AccessRevoke: the action and the user or group to remove.

required

Returns:

Type Description
ItemList[Permission]

The permissions after the change.

Examples:

>>> forms.access.revoke(
...     "686d0a1b2c3d4e5f000000d0",
...     {"action": "submit", "group": {"src": "staff", "id": "42"}},
... ).root[1].action
'submit'

history

HistoryClient

HistoryClient(*, session: SyncSession)

Bases: Resource

Read the change log of a form.

list

list(survey_id: str, *, ordering: str | None = None, limit: int | None = None) -> ItemList[HistoryEvent]

GET /surveys/{id}/history → the form's changes, page by page, at most limit.

ordering is desc (newest first, the API default) or asc.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
ordering str | None

desc (newest first) or asc.

None
limit int | None

The most events to return; None returns every event.

None

Returns:

Type Description
ItemList[HistoryEvent]

The form's change events.

Examples:

>>> events = forms.history.list("686d0a1b2c3d4e5f000000e1", ordering="asc", limit=500)
>>> [event.model for event in events.root]
['servicesurveyhooksubscription', 'surveyhook']

answers

AnswersClient

AnswersClient(*, session: SyncSession)

Bases: Resource

Read answers, list them page by page, and export them.

get

get(*, answer_id: int | None = None, answer_key: str | None = None) -> AnswerDetails

GET /answers?answer_id=… (or ?answer_key=…) → one full :class:AnswerDetails.

Exactly one selector: answer_id (the numeric id from a listing; needs form-edit access) or answer_key (the answer's hash; works without form-edit access).

Parameters:

Name Type Description Default
answer_id int | None

The numeric answer id.

None
answer_key str | None

The answer's hash.

None

Returns:

Type Description
AnswerDetails

The full answer.

Raises:

Type Description
ValueError

If both or neither of answer_id and answer_key are given.

Examples:

>>> forms.answers.get(answer_id=2469549806).survey.name
'Feedback'

list

list(survey_id: str, *, questions: str | None = None, use_slugs: bool = False, date_from: str | None = None, date_to: str | None = None, ordering: str | None = None, page_size: int | None = None, answer_format: str | None = None) -> AnswersResponse

GET /surveys/{id}/answers → the first page's {columns, answers, next} envelope.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
questions str | None

The comma-separated question ids to return answers for.

None
use_slugs bool

Name questions and options by slug instead of id.

False
date_from str | None

ISO-8601 start of the period the answers were given in.

None
date_to str | None

ISO-8601 end of that period.

None
ordering str | None

asc (oldest first) or desc (the API's default).

None
page_size int | None

The most answers a page holds (the API's default is 25).

None
answer_format str | None

default (cells aligned to columns) or raw (each answer's data as the API stores it, with no columns).

None

Returns:

Type Description
AnswersResponse

The first page of answers, with its columns.

Examples:

>>> forms.answers.list("686d0a1b2c3d4e5f00000030").columns[0].slug
'answer_short_text_1'

list_all

list_all(survey_id: str, *, limit: int | None = None, questions: str | None = None, use_slugs: bool = False, date_from: str | None = None, date_to: str | None = None, ordering: str | None = None, page_size: int | None = None, answer_format: str | None = None) -> AnswersResponse

Every answer across pages, at most limit (None = all).

columns come from the first page (identical across pages); the merged next is None.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
limit int | None

The most answers to return; None returns every answer.

None
questions str | None

The comma-separated question ids to return answers for.

None
use_slugs bool

Name questions and options by slug instead of id.

False
date_from str | None

ISO-8601 start of the period the answers were given in.

None
date_to str | None

ISO-8601 end of that period.

None
ordering str | None

asc (oldest first) or desc (the API's default).

None
page_size int | None

The most answers a page holds (the API's default is 25).

None
answer_format str | None

default (cells aligned to columns) or raw (each answer's data as the API stores it, with no columns).

None

Returns:

Type Description
AnswersResponse

The answers of every page, with the first page's columns.

Examples:

>>> len(forms.answers.list_all("686d0a1b2c3d4e5f00000030", limit=500).answers)
1

export

export(survey_id: str, body: dict[str, Any]) -> OperationResult

POST /surveys/{id}/answers/export — start an export → 202 with its operation.

Build body from an AnswerExport; poll :meth:export_results (or operations.get) on the returned id until ready, then :meth:download_export.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped AnswerExport: format, destination and filters.

required

Returns:

Type Description
OperationResult

The export operation, with its id to poll.

Examples:

>>> forms.answers.export(
...     "686d0a1b2c3d4e5f00000030", {"format": "csv", "upload": "disk"}
... ).id
'op-77'

export_results

export_results(survey_id: str, task_id: str) -> OperationResult

GET /surveys/{id}/answers/export-results?task_id= → the export's status.

While running or failed it answers {id, status, message}; once ready it redirects to the exported file, reported as a terminal ok.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
task_id str

The export operation's id.

required

Returns:

Type Description
OperationResult

The export's status.

Examples:

>>> forms.answers.export_results("686d0a1b2c3d4e5f00000030", "op-77").status
'running'

download_export

download_export(survey_id: str, task_id: str) -> bytes

The exported file's raw bytes, once :meth:export_results reports it ready.

Binary payload — SDK and CLI only, never an MCP result.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
task_id str

The export operation's id.

required

Returns:

Type Description
bytes

The exported file's raw bytes.

Examples:

>>> forms.answers.export_results("686d0a1b2c3d4e5f00000030", "op-77").status  # poll
'running'
>>> # ...until it is no longer running, then:
>>> forms.answers.download_export("686d0a1b2c3d4e5f00000030", "op-77").splitlines()[0]
b'id,name'

integrations_list

integrations_list(*, answer_id: int | None = None, answer_key: str | None = None) -> ItemList[AnswerIntegration]

GET /answers/integrations → the integration runs one answer triggered.

Exactly one selector, as for :meth:get.

Parameters:

Name Type Description Default
answer_id int | None

The numeric answer id.

None
answer_key str | None

The answer's hash.

None

Returns:

Type Description
ItemList[AnswerIntegration]

The integration runs the answer triggered.

Raises:

Type Description
ValueError

If both or neither of answer_id and answer_key are given.

Examples:

>>> forms.answers.integrations_list(answer_id=2542485382).root[0].status
'success'

delete

delete(survey_id: str, answer_id: int) -> None

DELETE /surveys/{id}/answers/{answer_id} — delete an answer; see :meth:restore.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
answer_id int

The numeric answer id.

required

Examples:

>>> forms.answers.delete("686d0a1b2c3d4e5f00000031", 2542485431)

restore

restore(survey_id: str, answer_id: int) -> None

POST /surveys/{id}/answers/{answer_id}/restore — bring a deleted answer back.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
answer_id int

The numeric answer id.

required

Examples:

>>> forms.answers.restore("686d0a1b2c3d4e5f00000032", 2542485498)

keysets

KeysetsClient

KeysetsClient(*, session: SyncSession)

Bases: Resource

List, get, create, modify, delete and download a form's key sets.

list

list(survey_id: str) -> ItemList[Keyset]

GET /surveys/{id}/keysets → every key set (a bare, unpaged array).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ItemList[Keyset]

Every key set of the form.

Examples:

>>> forms.keysets.list("686d0a1b2c3d4e5f00000020").root[0].name
'Q1 invites'

get

get(survey_id: str, keyset_id: int) -> Keyset

GET /surveys/{id}/keysets/{keyset_id} → a single :class:Keyset.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
keyset_id int

The key set's id.

required

Returns:

Type Description
Keyset

The key set.

Examples:

>>> forms.keysets.get("686d0a1b2c3d4e5f00000020", 3).id
3

create

create(survey_id: str, body: dict[str, Any]) -> Keyset

POST /surveys/{id}/keysets — create a key set from a dumped KeysetCreate.

The API requires is_enabled on create, alongside name and total.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped KeysetCreate.

required

Returns:

Type Description
Keyset

The created key set, with its id.

Examples:

>>> forms.keysets.create(
...     "686d0a1b2c3d4e5f00000020",
...     {"name": "Q1 invites", "total": 100, "is_enabled": True},
... ).id
3

modify

modify(survey_id: str, keyset_id: int, body: dict[str, Any]) -> Keyset

PATCH /surveys/{id}/keysets/{keyset_id} — replace a key set → the :class:Keyset.

Despite the method, the API validates a full record: name, total and is_enabled are all required (a KeysetUpdate with every field set).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
keyset_id int

The key set's id.

required
body dict[str, Any]

The dumped KeysetUpdate with every field set.

required

Returns:

Type Description
Keyset

The replaced key set.

Examples:

>>> forms.keysets.modify(
...     "686d0a1b2c3d4e5f00000020",
...     4,
...     {"name": "Q1 invites", "total": 100, "is_enabled": True},
... ).name
'Q1 invites'

delete

delete(survey_id: str, keyset_id: int) -> None

DELETE /surveys/{id}/keysets/{keyset_id} — delete a key set (no body comes back).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
keyset_id int

The key set's id.

required

Examples:

>>> forms.keysets.delete("686d0a1b2c3d4e5f00000020", 5)

download

download(survey_id: str, keyset_id: int) -> bytes

GET /surveys/{id}/keysets/{keyset_id}/download → the key set's raw bytes.

Binary payload — SDK and CLI only, never an MCP result.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
keyset_id int

The key set's id.

required

Returns:

Type Description
bytes

The key set's raw bytes.

Examples:

>>> forms.keysets.download("686d0a1b2c3d4e5f00000020", 6)[:5]
b'key-1'

operations

OperationsClient

OperationsClient(*, session: SyncSession)

Bases: Resource

Read the status of an asynchronous Forms operation.

get

get(operation_id: str) -> OperationResult

GET /operations/{operation_id} → the operation's current :class:OperationResult.

Poll it on the id an async trigger returned (answers export --no-wait) until :attr:OperationResult.is_terminal.

Parameters:

Name Type Description Default
operation_id str

The operation's id.

required

Returns:

Type Description
OperationResult

The operation's current state.

Examples:

>>> forms.operations.get("op-4a1b").is_terminal
True

notifications

NotificationsClient

NotificationsClient(*, session: SyncSession)

Bases: Resource

List, inspect, restart and cancel the runs of a form's integrations.

list

list(*, survey_id: str | None = None, hook_id: int | None = None, subscription_id: int | None = None, answer_id: int | None = None, status: Sequence[str] | None = None, created_since: str | None = None, created_until: str | None = None, finished_since: str | None = None, finished_until: str | None = None, visible: bool | None = None, integration_type: str | None = None, ordering: str | None = None, limit: int | None = None) -> ItemList[Notification]

GET /notifications → runs matching every filter given, at most limit.

status holds any of pending, success, error, canceled; the *_since / *_until bounds are ISO-8601 times (both ends inclusive); ordering is asc (the API default) or desc.

Parameters:

Name Type Description Default
survey_id str | None

Only runs of this form.

None
hook_id int | None

Only runs of this integration group.

None
subscription_id int | None

Only runs of this integration.

None
answer_id int | None

Only runs triggered by this answer.

None
status Sequence[str] | None

Only runs in any of these states.

None
created_since str | None

Only runs created at or after this time.

None
created_until str | None

Only runs created at or before this time.

None
finished_since str | None

Only runs finished at or after this time.

None
finished_until str | None

Only runs finished at or before this time.

None
visible bool | None

Only visible (True) or hidden (False) runs.

None
integration_type str | None

Only runs of this integration type.

None
ordering str | None

asc (the API default) or desc.

None
limit int | None

The most runs to return; None returns every run.

None

Returns:

Type Description
ItemList[Notification]

The matching runs.

Examples:

>>> runs = forms.notifications.list(
...     survey_id="686d0a1b2c3d4e5f000000f0", status=["error", "pending"], limit=500
... )
>>> [run.id for run in runs.root]
[9001, 9002, 9003]

get

get(notification_id: int) -> NotificationDetails

GET /notifications/{id} → the run with its context, response and error.

Parameters:

Name Type Description Default
notification_id int

The run's id.

required

Returns:

Type Description
NotificationDetails

The run, with what the integration was given, answered and failed with.

Examples:

>>> forms.notifications.get(9100).error[0].name
'detail'

status_get

status_get(notification_id: int) -> NotificationStatus

GET /notifications/{id}/status → just the run's state.

Parameters:

Name Type Description Default
notification_id int

The run's id.

required

Returns:

Type Description
NotificationStatus

The run's state.

Examples:

>>> forms.notifications.status_get(9101).status
'success'

restart

restart(notification_id: int) -> NotificationAction

POST /notifications/{id}/restart — run the integration again for that answer.

result.status is ok, skip (a run that is still pending is left alone), fail (see detail) or operation: the run was queued again. A canceled run answered operation with the operation_id not-supported on the test organization, so there is nothing to poll: read the run's state with :meth:status_get.

Parameters:

Name Type Description Default
notification_id int

The run's id.

required

Returns:

Type Description
NotificationAction

How the restart went.

Examples:

>>> forms.notifications.restart(9102).result.status
'operation'

cancel

cancel(notification_id: int) -> NotificationAction

POST /notifications/{id}/cancel — stop a run that has not finished.

A run that is already canceled or finished answers result.status skip.

Parameters:

Name Type Description Default
notification_id int

The run's id.

required

Returns:

Type Description
NotificationAction

How the cancel went.

Examples:

>>> forms.notifications.cancel(9103).result.status
'fail'

errors_list

errors_list(survey_id: str) -> ItemList[int]

GET /surveys/{id}/show-errors → ids of the form's failed runs still shown.

Read each with :meth:get.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ItemList[int]

The ids of the form's failed runs.

Examples:

>>> forms.notifications.errors_list("686d0a1b2c3d4e5f000000f2").root
[9001, 9003]

files

FilesClient

FilesClient(*, session: SyncSession)

Bases: Resource

The files attached while filling a form.

upload

upload(survey_id: str, *, filename: str, data: bytes) -> FileOut

Upload a file for form filling (multipart field file) → :class:FileOut.

Needs external file storage connected in the form's settings; the returned path / url then reference the file in a File-type answer.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
filename str

The file's name.

required
data bytes

The file's raw bytes.

required

Returns:

Type Description
FileOut

The stored file, with its path and url.

Examples:

>>> forms.files.upload(
...     "686d0a1b2c3d4e5f00000040", filename="cv.txt", data=b"resume bytes"
... ).path
'a/b/cv.txt'

verify

verify(survey_id: str, files: list[FileIn]) -> ItemList[FileOut]

POST …/files/verify (a read) → the upload status and access of each file.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
files list[FileIn]

The files to check, each by path and/or url.

required

Returns:

Type Description
ItemList[FileOut]

The upload status and access of each file.

Examples:

>>> forms.files.verify(
...     "686d0a1b2c3d4e5f00000040",
...     [
...         FileIn(path="a/b/cv.txt", url="https://forms.test/a/b/cv.txt"),
...         FileIn(path="c/d.pdf"),
...     ],
... ).root[0].check_status
'ready'

download

download(path: str, *, download: bool = False, file_hash: str | None = None) -> bytes

GET /files?path=… → a stored file's raw bytes.

download=True asks for a Content-Disposition filename header; file_hash (the hash from an upload) lets an anonymous caller download a file whose access cannot otherwise be verified.

Parameters:

Name Type Description Default
path str

The stored file's path.

required
download bool

Whether to ask for a Content-Disposition filename header.

False
file_hash str | None

The hash from an upload, for an anonymous caller.

None

Returns:

Type Description
bytes

The file's raw bytes.

Examples:

>>> forms.files.download("a/b/cv.txt", download=True, file_hash="h4sh")
b'resume bytes'

delete

delete(*, path: str | None = None, url: str | None = None) -> Ack

DELETE /files (body {path, url}) → an :class:Ack naming what was given.

Parameters:

Name Type Description Default
path str | None

The stored file's path.

None
url str | None

The stored file's url.

None

Returns:

Type Description
Ack

An acknowledgement naming the deleted file.

Examples:

>>> forms.files.delete(path="a/b/cv.txt", url="https://forms.test/a/b/cv.txt").ok
True

images

ImagesClient

ImagesClient(*, session: SyncSession)

Bases: Resource

Images to reference from a form's questions, options or style.

upload

upload(survey_id: str, *, filename: str, data: bytes) -> Image

Upload an image (multipart field image) → :class:Image.

Reference the returned id from a question's, option's or form style's image.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
filename str

The image's file name.

required
data bytes

The image's raw bytes.

required

Returns:

Type Description
Image

The uploaded image, with its id.

Examples:

>>> forms.images.upload(
...     "686d0a1b2c3d4e5f00000050", filename="logo.png", data=b"PNGDATA"
... ).id
7

clone

clone(survey_id: str, body: dict[str, Any]) -> Image

POST /surveys/{id}/images/clone — copy an existing image into the form.

Build body from an ImageClone: the source image's id (or its links) and an optional new name.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped ImageClone.

required

Returns:

Type Description
Image

The copied image, with its new id.

Examples:

>>> forms.images.clone("686d0a1b2c3d4e5f00000051", {"id": 7, "name": "copy.png"}).id
8

filling

FillingClient

FillingClient(*, session: SyncSession)

Bases: Resource

Fill a form the way a respondent does.

get

get(survey: str, key: str | None = None) -> FillableForm

GET /surveys/{survey}/form → the :class:FillableForm settings for filling.

survey is the form id, its slug, or an id+verification-key combination; key is the personal-link fill key. The call also checks that the form is published and fillable.

Parameters:

Name Type Description Default
survey str

The form's id, slug, or id+verification-key combination.

required
key str | None

The personal-link fill key.

None

Returns:

Type Description
FillableForm

The form's settings for filling.

Examples:

>>> forms.filling.get("686d0a1b2c3d4e5f00000060", key="k-1").name
'Feedback'

submit

submit(survey: str, body: SubmitBody, *, dry_run: bool = False, key: str | None = None) -> SubmitResult

POST /surveys/{survey}/form — submit a response → :class:SubmitResult.

body maps each question slug to its answer. dry_run=True validates everything but saves nothing and fires no integrations.

Parameters:

Name Type Description Default
survey str

The form's id, slug, or id+verification-key combination.

required
body SubmitBody

The answers, keyed by question slug.

required
dry_run bool

Whether to validate only, saving nothing.

False
key str | None

The personal-link fill key.

None

Returns:

Type Description
SubmitResult

The submission result, with the new answer's id.

Examples:

>>> from ycli.yandex.forms.filling.models import SubmitBody
>>> body = SubmitBody.model_validate({"name": "Ann", "rating": 5})
>>> forms.filling.submit("686d0a1b2c3d4e5f00000060", body, key="k-2").answer_id
99

suggest

suggest(survey: str, *, question: str | None = None, text: str | None = None, suggest_id: str | None = None, parent_id: str | None = None) -> ItemList[Suggestion]

GET /surveys/{survey}/suggest → prompts for a fill field (read-only).

question is the question slug, text the search text, suggest_id (the API's id) a comma-separated list of suggestion ids to resolve, and parent_id scopes a Master/Detail lookup.

Parameters:

Name Type Description Default
survey str

The form's id, slug, or id+verification-key combination.

required
question str | None

The question's slug.

None
text str | None

The search text.

None
suggest_id str | None

A comma-separated list of suggestion ids to resolve.

None
parent_id str | None

The parent id scoping a Master/Detail lookup.

None

Returns:

Type Description
ItemList[Suggestion]

The suggestions for the field.

Examples:

>>> forms.filling.suggest("686d0a1b2c3d4e5f00000060", question="city", text="Ber").root[
...     0
... ].text
'Berlin'

hooks

HooksClient

HooksClient(*, session: SyncSession)

Bases: Resource

List, get, create, modify and delete a form's integration groups.

list

list(survey_id: str) -> ItemList[Hook]

GET /surveys/{id}/hooks → every integration group with its integrations.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ItemList[Hook]

Every integration group, with its integrations.

Examples:

>>> forms.hooks.list("686d0a1b2c3d4e5f000000a0").root[0].name
'CRM'

get

get(survey_id: str, hook_id: int) -> Hook

GET /surveys/{id}/hooks/{hook_id} → one :class:Hook.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required

Returns:

Type Description
Hook

The integration group.

Examples:

>>> forms.hooks.get("686d0a1b2c3d4e5f000000a0", 12).active
False

create

create(survey_id: str, body: dict[str, Any]) -> Hook

POST /surveys/{id}/hooks — create a group from a dumped HookCreate.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
body dict[str, Any]

The dumped HookCreate: the group's name and whether it is active.

required

Returns:

Type Description
Hook

The created integration group, with its id.

Examples:

>>> forms.hooks.create("686d0a1b2c3d4e5f000000a0", {"name": "CRM", "active": False}).id
13

modify

modify(survey_id: str, hook_id: int, body: dict[str, Any]) -> Hook

PATCH /surveys/{id}/hooks/{hook_id} — only the keys in body change.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
body dict[str, Any]

The keys to change.

required

Returns:

Type Description
Hook

The updated integration group.

Examples:

>>> forms.hooks.modify("686d0a1b2c3d4e5f000000a0", 15, {"name": "CRM"}).name
'CRM'

delete

delete(survey_id: str, hook_id: int) -> None

DELETE /surveys/{id}/hooks/{hook_id} — the group and its integrations (200).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required

Examples:

>>> forms.hooks.delete("686d0a1b2c3d4e5f000000a0", 16)

subscriptions

SubscriptionsClient

SubscriptionsClient(*, session: SyncSession)

Bases: Resource

List, get, create, modify and delete the integrations of a hook; upload attachments.

list

list(survey_id: str, hook_id: int) -> ItemList[Subscription]

GET /surveys/{id}/hooks/{hook_id}/subscriptions → every integration of the hook.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required

Returns:

Type Description
ItemList[Subscription]

Every integration of the hook.

Examples:

>>> forms.subscriptions.list("686d0a1b2c3d4e5f000000b0", 21).root[0].type
'http'

get

get(survey_id: str, hook_id: int, subscription_id: int) -> Subscription

GET …/subscriptions/{subscription_id} → one integration, typed by type.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
subscription_id int

The integration's id.

required

Returns:

Type Description
Subscription

The integration.

Examples:

>>> forms.subscriptions.get("686d0a1b2c3d4e5f000000b0", 21, 4).type
'tracker'

create

create(survey_id: str, hook_id: int, body: Subscription) -> Subscription

POST …/subscriptions — add an integration to the hook → it, with its id.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
body Subscription

The new integration.

required

Returns:

Type Description
Subscription

The created integration, with its id.

Examples:

>>> from ycli.yandex.forms.subscriptions.models import HttpSubscription
>>> forms.subscriptions.create(
...     "686d0a1b2c3d4e5f000000b0",
...     21,
...     HttpSubscription(url="https://example.com/hook", active=False),
... ).id
5

modify

modify(survey_id: str, hook_id: int, subscription_id: int, body: Subscription) -> Subscription

PATCH …/subscriptions/{subscription_id} — change the fields set in body.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
subscription_id int

The integration's id.

required
body Subscription

The fields to change.

required

Returns:

Type Description
Subscription

The updated integration.

Examples:

>>> from ycli.yandex.forms.subscriptions.models import HttpSubscription
>>> forms.subscriptions.modify(
...     "686d0a1b2c3d4e5f000000b0", 21, 6, HttpSubscription(active=False)
... ).active
False

delete

delete(survey_id: str, hook_id: int, subscription_id: int) -> None

DELETE …/subscriptions/{subscription_id} (200, no body).

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
subscription_id int

The integration's id.

required

Examples:

>>> forms.subscriptions.delete("686d0a1b2c3d4e5f000000b0", 21, 8)

attach

attach(survey_id: str, hook_id: int, subscription_id: int, *, filename: str, data: bytes) -> FileOut

Upload a fixed attachment (multipart field file) → its path.

Reference the returned path from attachments.static in a subscription body. Binary payload — SDK and CLI only.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required
hook_id int

The integration group's (hook's) id.

required
subscription_id int

The integration's id.

required
filename str

The attachment's file name.

required
data bytes

The attachment's raw bytes.

required

Returns:

Type Description
FileOut

The stored attachment, with its path.

Examples:

>>> forms.subscriptions.attach(
...     "686d0a1b2c3d4e5f000000b0", 21, 9, filename="terms.pdf", data=b"%PDF"
... ).path
'/forms/terms.pdf'

variables

VariablesClient

VariablesClient(*, session: SyncSession)

Bases: Resource

The variable types a form's integrations can reference.

list

list(survey_id: str) -> ItemList[VariableInfo]

GET /surveys/{id}/variables → every variable type available to the form.

Parameters:

Name Type Description Default
survey_id str

The form's id.

required

Returns:

Type Description
ItemList[VariableInfo]

Every variable type available to the form.

Examples:

>>> forms.variables.list("686d0a1b2c3d4e5f000000c0").root[0].type
'form.answer_url'