Рамочные договоры с фиксированными периодами: полное описание механики

Документ для заказчика (Пицца Венчур, КЦ Сыктывкар — интеграция из 1С по API YouDo). Формат: по слайдам, каждый шаг описан с трёх сторон — что делаете вы, что в этот момент делает YouDo, что видит исполнитель.


Слайд 1. Суть в трёх предложениях

Сейчас по 35-му протоколу ФНС на каждую выплату исполнителю формируется отдельный документ «Задание», который исполнитель обязан подписать до начала работ. При еженедельных (и чаще) выплатах это значит: исполнитель подписывает документы на каждую выплату — операционно неподъёмно и ломает ваш процесс в 1С.

Новая механика: один рамочный договор на период + один документ «Задание» к нему. Исполнитель подписывает один раз за период, одной кнопкой. Все выплаты внутри периода создаются по API сразу готовыми к оплате — без каких-либо действий исполнителя, в том числе задним числом после окончания периода.

Требование ФНС при этом соблюдается: задание подписано до начала работ — просто теперь оно одно на весь период, а не на каждую выплату.


Слайд 2. Глоссарий (важно: слово «задание» имеет три смысла)

Термин Что это Где встречается
Рамка / рамочный договор Договор с самозанятым на период (неделя/две/месяц — по шаблону проекта). Подписывается исполнителем один раз POST /frameworkagreements
Документ «Задание» PDF-документ к рамке: период, условия, цена, объём услуг. Подписывается вместе с договором одной кнопкой taskDocumentId в ответах API
Выплата (контракт) Сущность оплаты: к ней привязан акт и сам платёж. Создаётся вами по API внутри рамки POST /task/internal — ⚠️ в URL исторически слово task, но это именно выплата, не документ
Акт Закрывающий документ по факту выполненных работ. Формируется по существующей механике, тут ничего не меняется
«Не подтверждено в срок» Терминальный статус рамки, которую исполнитель не подписал вовремя. В интерфейсах может отображаться как «Срок истёк» state: expired

⚠️ Не путать: эндпоинт /task/internal создаёт выплату; документ «Задание» — это PDF при рамке; раздел «Задания» в кабинете исполнителя — это список его выплат. Три разные вещи, одно слово. В этом документе мы везде пишем «выплата» и «документ „Задание“», чтобы не смешивать.


Слайд 3. Направление интеграции: кто кого дёргает

   ВЫ (1С) ──────── REST API ────────►  YouDo
            создать рамку, изменить условия,
            создать выплату, узнать статусы,
            скачать PDF

   ВЫ (1С) ◄──────── вебхуки ─────────  YouDo
            «исполнитель подписал»,
            «рамка не подписана в срок»

   ВЫ (1С) ◄───────── ничего ─────────  YouDo
            мы НЕ ходим в вашу 1С, ничего из неё
            не читаем и не пишем

Ключевое отличие от интеграции по Dodo IS: там YouDo опрашивает API Додо. Здесь наоборот — вся инициатива на вашей стороне. Данные о сменах, суммах, расчётах живут в вашей 1С; вы вызываете наши API тогда, когда вам нужно. Мы ваши суммы не пересчитываем и не корректируем.

В вашу сторону мы отправляем только вебхуки (HTTP-уведомления на ваш URL) о событиях с рамками — подписка настраивается один раз через POST /api/v1/webhook/Subscribe. Вебхуки — это ускорение, не единственный канал: те же статусы всегда можно забрать опросом GET-метода (слайд 9).


Слайд 4. Статусная модель рамки

                 ┌─────────────────────────────────────────────────┐
  создали по API │                                                 │
        ▼        ▼                                                 │
  ┌────────────────┐  подписал до конца    ┌──────────┐  период    ┌─────────┐
  │  readyToSign   │  1-го дня периода     │  signed  │  кончился  │  ended  │
  │ (ждёт подписи) ├──────────────────────►│(действует├───────────►│(закончи-│
  └───────┬────────┘                       │  )       │            │  лась)  │
          │ не подписал в срок             └──────────┘            └─────────┘
          ▼                                 Выплаты можно создавать в signed
  ┌────────────────┐                        и в ended (задним числом).
  │    expired     │  терминальный статус.
  │(не подтверждено│  Подписать нельзя. Выплаты в неё — нельзя.
  │    в срок)     │  Лечится созданием новой рамки.
  └────────────────┘

Правила, которые стоит зафиксировать у себя:

  1. Период рамки фиксированный. Даты определяются в момент создания (ваш start + срок из шаблона проекта) и не сдвигаются при подписании. Исполнитель подписал вечером 1-го числа рамку «с 1-го» — период остался «с 1-го», а не «со 2-го». Именно это позволяет рамкам идти встык.
  2. Дедлайн подписания — конец первого дня периода включительно (обоснование: по 35-му протоколу задание подписывается до начала работ). Подписать заранее, до старта периода, — можно и нужно.
  3. ended ≠ расторжение. Окончание периода — это просто окончание периода: договор не расторгается, уведомления о расторжении не отправляются, задним числом в него можно создавать выплаты.
  4. Неподписанная рамка для выплат не существует. Пока рамка readyToSign — выплаты в её период создать нельзя (ошибка). Никакого «создастся и подождёт подписания».

Слайд 5. Общая картина: один месяц из жизни (пример для месячных периодов)

Когда Вы (1С) YouDo Исполнитель
~29–30 июля POST /frameworkagreements — рамка на август Генерирует PDF договора и задания, шлёт исполнителю SMS/TG со ссылкой Получает ссылку
30 июля – 1 августа Ждёте вебхук / опрашиваете статус Нажимает «Подписать» — одна кнопка на договор + задание
момент подписания ◄ вебхук FrameworkAgreementAccept Фиксирует подпись Больше в августе не делает ничего
весь август POST /task/internal — выплаты по вашему графику (день-в-день, еженедельно — как удобно) Находит рамку по датам, создаёт выплату сразу «выполняется», дальше акты/оплата Получает деньги, документы появляются в кабинете сами
~29–30 августа Рамка на сентябрь (августовская продолжает работать) Подписывает сентябрьскую
начало сентября Досоздаёте выплаты за август задним числом Пропускает: попадание в августовскую рамку по датам — этого достаточно

Слайд 6. Шаг 1 — создание рамки: полный контракт

POST /api/v1/frameworkagreements

Тело запроса:

Поле Тип Обяз. Что это
projectId int да Ваш проект в YouDo
employeeId int да Исполнитель
start date да* Дата начала периода. Конец = start + срок из шаблона проекта
taskPrice decimal нет Цена в документе «Задание»
taskTitle string нет Название задания
taskDescription string нет Описание работ
taskAddress string нет Адрес
itemsCount decimal нет Плановый объём услуг
itemsUnit string нет Единицы измерения объёма

Не переданные условия задания подставляются из шаблона проекта. Исключение — itemsCount/itemsUnit: в шаблоне их нет, хотите объём в задании — передавайте явно. Имена полей совпадают с полями POST /task/internal, чтобы в 1С можно было переиспользовать маппинг.

Про срок периода: длина периода (term_days) настраивается в шаблоне вашего проекта на нашей стороне. Через API она не задаётся — это осознанное решение (меньше валидаций и краевых случаев). Хотите неделю вместо месяца или разные сроки на разных проектах — говорите нам, меняем в шаблоне. Вы и так приходите к нам при смене тарифов — это тот же процесс.

Ответ: frameworkAgreementId + taskDocumentId — id PDF-документа «Задание» (скачивание — слайд 12).

Что происходит у нас в фоне после ответа:

  1. Создаётся рамка с фиксированным периодом.
  2. Генерируется PDF договора и PDF документа «Задание» из переданных условий.
  3. Исполнителю уходит SMS/Telegram со ссылкой на подписание.

Ошибки создания:

Код Когда Что делать
400 «Период пересекается с существующей рамкой (Id: N)» Новый период задевает уже существующую рамку исполнителя Проверить даты; рамки должны идти встык, без нахлёста
стандартные 400/404 Неверный исполнитель/проект и т.п. Как в остальных методах API

Пересечение с рамкой в статусе expired ошибкой не считается — протухшая рамка не блокирует создание новой на тот же период.


Слайд 7. Шаг 1а — изменение условий до подписания

Опубликовали рамку, а условия поменялись (тариф, объём, адрес)? Пока исполнитель не подписал — условия можно заменить:

PUT /api/v1/frameworkagreements/{agreementId}/task

Тело: тот же набор полей условий (taskPrice, taskTitle, taskDescription, taskAddress, itemsCount, itemsUnit) — полная замена, не патч. Отсутствующие поля — из шаблона проекта.

Что делает YouDo: перегенерирует PDF задания, обновляет опубликованные данные. Ответ: актуальный taskDocumentId (id документа может смениться — сохраняйте новый).

Ошибки:

Код Когда
400 Рамка уже подписана / не подтверждена в срок / завершена / расторгнута — редактирование только до подписания
404 Рамка не найдена или из чужого проекта

После подписания условия задания не меняются никогда. Расхождение плана с фактом закрывается актами — это штатная ситуация (слайд 15).


Слайд 8. Шаг 2 — подписание: глазами исполнителя

  1. Исполнителю приходит SMS/Telegram со ссылкой.
  2. Открывает личный кабинет → видит рамочный договор и документ «Задание» на период: срок действия, условия, цена, объём.
  3. Нажимает одну кнопку «Подписать». Этим действием он одновременно подписывает договор и принимает задание — одной транзакцией, отдельного принятия задания нет.
  4. Всё. До конца периода исполнитель в этой механике больше не участвует.

Окно подписания: от момента получения до конца первого дня периода включительно.

Что видите вы в момент подписания: вебхук FrameworkAgreementAccept (существующий тип, уже знакомый интеграциям). С этого момента можно создавать выплаты в период рамки.


Слайд 9. Шаг 2а — исполнитель не подписал в срок

Что делает YouDo: фоновый процесс переводит рамку в статус «Не подтверждено в срок» (expired). Статус терминальный: подписать эту рамку уже невозможно, выплаты в неё создать нельзя.

Что получаете вы:

{
  "frameworkAgreementId": 123,
  "employeeId": 456,
  "projectId": 789,
  "state": "expired"
}
GET /api/v1/frameworkagreements/employees/{employeeId}/projects/{projectId}

В ответе по каждой рамке: agreementStartDate (начало периода), agreementEndDate (конец), даты подписания и state: readyToSign | signed | expired | ended | terminated, плюс taskDocumentId.

Что делаете вы: создаёте новую рамку обычным POST /frameworkagreements — на тот же период или сдвинутый. Исполнителю снова уходит ссылка, подписывает заново.

⚠️ Практическое следствие: пока висит expired и вы не пересоздали рамку — выплаты за эти дни провести нельзя. Рекомендуем в 1С обрабатывать вебхук FrameworkAgreementExpired как сигнал к немедленному пересозданию, а не разбирать раз в неделю: чем быстрее новая рамка подписана, тем меньше дней «зависает» (потом их можно закрыть задним числом — но только после подписания новой рамки, покрывающей эти даты... нет — см. FAQ, вопрос 4).


Слайд 10. Шаг 3 — выплаты: полный контракт

POST /api/v1/task/internal

(метод существующий — тот же, которым выплаты создаются сегодня; меняется только поведение для вашего проекта)

Ключевые поля (остальной контракт — без изменений):

Поле Обяз. Роль в новой механике
employeeId да Исполнитель
taskStarts да Начало периода работ по этой выплате
taskEnds да Конец периода работ. По этим двум датам мы сами находим рамку — поля «id рамки» в запросе нет и не нужно
сумма, описание и пр. как сейчас Без изменений
хидер Idempotency-Key рекомендуем Защита от дублей при ретраях из 1С: повторный запрос с тем же ключом не создаст вторую выплату

Что делает YouDo при получении запроса:

  1. Ищет подписанную рамку исполнителя, чей период целиком покрывает интервал taskStarts..taskEnds. Рамка может быть действующей (signed) или уже завершённой (ended) — задним числом можно.
  2. Нашёл одну → создаёт выплату, привязанную к этой рамке, сразу в статусе «выполняется» — готова к оплате с первой секунды. Никаких документов исполнителю на подпись не формируется, никакого принятия не требуется.
  3. Дальше — существующий контур: акт, постановка на выплату, оплата. Здесь ничего не меняется.

Ошибки привязки (обе — 400 с внятным текстом):

Ошибка Причина Что делать в 1С
«Нет подписанного рамочного договора, покрывающего период задания» Даты не попадают ни в одну рамку, либо рамка есть, но readyToSign/expired Проверить статус рамки (GET / вебхуки); если не подписана — дождаться подписания или пересоздать; выплату повторить после
«Период задания пересекает границу рамочных договоров N и M — разделите на две выплаты» Интервал работ лежит в двух рамках Разбить платёж на две выплаты по границе рамок (слайд 11)

Ошибка ничего не ломает и ничего не создаёт — просто повторяете запрос с исправленными датами. Прежний запрет «дата начала не может быть раньше текущего дня» в этом режиме не действует — backdated разрешён.


Слайд 11. Единственное правило про даты: одна выплата = одна рамка

Пример. Рамки исполнителя: «1–31 июля» и «1–31 августа». Вы платите еженедельно и хотите закрыть неделю 28.07–03.08.

        июльская рамка   │   августовская рамка
   ──────────────────────│──────────────────────
        28.07 ━━━━━━━━━━━┿━━━━━━━━ 03.08     ← одним запросом: 400, ошибка
        28.07 ━━━━━━━━━━━┥                    ← выплата №1: taskStarts=28.07, taskEnds=31.07
                         ┝━━━━━━━━ 03.08      ← выплата №2: taskStarts=01.08, taskEnds=03.08

Почему так, а не «привяжем к какой-нибудь»: каждая выплата и её акт должны юридически лежать внутри конкретного договора. Выплата, размазанная по двум договорам, — это ровно то, к чему у ФНС появляются вопросы. Поэтому мы валидируем жёстко, а деление на две выплаты — ваша сторона (вы знаете, какая часть суммы к какой неделе относится, мы — нет).

Рекомендация для 1С: заложить деление по границе рамок прямо в генерацию платежей — граница всегда известна заранее (это даты рамок, которые вы сами и создали).


Слайд 12. Документы: что где скачать, кто что видит

PDF-документов в механике два (на рамку): договор и документ «Задание». Акты — по существующей механике, без изменений.

Вам (по API):

Что Как
PDF договора / PDF задания GET /api/v1/documents/{documentId} — существующий метод
Откуда взять id taskDocumentId — из ответа создания/редактирования рамки и из GET /frameworkagreements/...; id договора — там же

Вам (в кабинете компании): документ «Задание» появляется в общем разделе «Документы» автоматически, рядом с договором; также доступен из блока рамочных договоров в карточке исполнителя.

Исполнителю (в его кабинете):

Для проверок ФНС это значит: у исполнителя и у вас на руках одинаковый комплект — договор + задание на период + акты по фактическим выплатам.


Слайд 13. Жизнь на стыке периодов: две рамки одновременно

У исполнителя может одновременно существовать несколько рамок: действующая + будущая (отправленная заранее). Отправка будущей не останавливает текущую. Ограничение одно: периоды не пересекаются (встык — можно и нужно).

Рекомендуемый регламент для 1С (на примере месячных периодов):

День Действие
~за 2 дня до конца периода POST /frameworkagreements на следующий период (start = первый день следующего периода)
сразу после Исполнитель получает ссылку и подписывает будущую рамку заранее — текущая продолжает работать
до конца 1-го дня нового периода Контроль: пришёл ли FrameworkAgreementAccept по новой рамке. Не пришёл — ждём FrameworkAgreementExpired и пересоздаём
весь период Выплаты создаются с датами работ — попадание в нужную рамку автоматическое, думать не нужно

Почему «за 2 дня», а не раньше/позже: раньше — исполнитель забудет про ссылку; позже — рискуете не успеть до дедлайна первого дня. Двое суток — практический баланс, но это ваш регламент, технических ограничений на «за сколько дней» нет.


Слайд 14. Сводная шпаргалка по API и вебхукам

Вы дёргаете нас:

Задача Метод Комментарий
Создать рамку + задание POST /api/v1/frameworkagreements + условия задания в теле; ответ содержит taskDocumentId
Изменить условия до подписания PUT /api/v1/frameworkagreements/{id}/task Полная замена условий; после подписания — 400
Статусы рамок исполнителя GET /api/v1/frameworkagreements/employees/{employeeId}/projects/{projectId} state, даты периода, дата подписания, taskDocumentId
Создать выплату POST /api/v1/task/internal Обязательные taskStarts/taskEnds; рамка ищется по датам; Idempotency-Key
Скачать PDF (договор, задание) GET /api/v1/documents/{documentId} Существующий метод
Подписаться на события POST /api/v1/webhook/Subscribe Один раз при настройке

Мы дёргаем вас (вебхуки на ваш URL):

Событие Тип Когда Ваша реакция
Исполнитель подписал рамку FrameworkAgreementAccept (существующий) В момент подписания Открыть создание выплат по периоду
Рамка не подписана в срок FrameworkAgreementExpired (новый) После дедлайна первого дня Создать новую рамку

Авторизация, форматы ошибок, идемпотентность — как во всех остальных методах нашего API; отдельной авторизации для этой механики нет. Всё включается на уровне вашего проекта: для других ваших процессов и других клиентов YouDo поведение API не меняется.


Слайд 15. Границы ответственности и риски — проговариваем честно

  1. План в задании ≠ факт в актах — это допустимо, и это ваш риск. В задании фиксируется плановый объём (условно «500 штук за 2 500»), по факту актов может быть «10 000 за 5 000» — самозанятый волен работать больше или меньше (заболел, подработал). Позиция юристов: при вопросах ФНС расхождение объясняется актами. После подписания задание не редактируется — если ваша позиция «план обязан биться с фактом», скажите об этом до старта разработки: механика «поправить задание задним числом» обсуждалась и отложена, вернуть её в скоуп можно.
  2. Backdated без ограничения срока — тоже ваша зона. Технически мы не ограничиваем, как долго после окончания рамки можно создавать в неё выплаты. Юридическая разумность сроков («платить за год назад — странно») — на вашей стороне.
  3. Суммы считаете вы. Мы не пересчитываем, не валидируем «похожесть» сумм на план и не делаем перерасчётов — что прислали в выплате, то и платится (в рамках обычных проверок платёжного контура).
  4. Исполнители-нерезиденты. Частые короткие договоры = частые уведомления МВД о заключении договоров ГПХ. Нам нужен ваш ответ: как вы сегодня подаёте уведомления МВД по иностранцам и сколько их у вас в этом контуре. От ответа зависит, нужен ли для нерезидентов отдельный поток, — это блокер для запуска по нерезидентам, по гражданам РФ не блокирует ничего.

Слайд 16. FAQ

1. Можно ли в одной рамке несколько документов «Задание» (например, рамка на квартал + задания помесячно)? Нет. Одна рамка = одно задание = одна подпись. Нужен другой шаг периодичности — делаем короче саму рамку (настройка шаблона).

2. Можно ли задать разный срок рамки для разных проектов? Да: срок — настройка шаблона per-проект. Один проект — две недели, другой — месяц. Меняется через нас.

3. Исполнитель подписал рамку в первый день вечером, а смена была утром — законно? Да, правило «подписать до конца первого дня включительно» согласовано юристами именно под это.

4. Рамка протухла (expired), мы пересоздали, исполнитель подписал новую. Можно ли заплатить за первые дни периода? Выплата должна попадать в период подписанной рамки. Пересоздать рамку можно на тот же период — тогда после подписания новой рамки выплата за первые дни попадёт в неё. Если пересоздаёте со сдвинутым стартом — дни до старта новой рамки не покрыты ни одной подписанной рамкой, и выплату за них провести нельзя. Точная механика дедлайна подписания для пересозданной рамки (период которой уже начался) фиксируется в ТЗ — но практический вывод в любом случае один: пересоздавайте тем же периодом и добивайтесь подписания быстро.

5. Как понять, к какой рамке привязалась выплата? Привязка детерминирована датами: рамка, чей период покрывает taskStarts..taskEnds. Периоды рамок не пересекаются, значит подходящая рамка всегда ровно одна (или ноль — тогда ошибка, выплата не создаётся).

6. Что будет, если отправить выплату до того, как исполнитель подписал будущую рамку? Ошибка 400 «нет подписанного рамочного договора». Выплата не создаётся и не «зависает в ожидании» — повторите запрос после подписания (сигнал — вебхук FrameworkAgreementAccept).

7. Уведомляется ли исполнитель о каждой выплате? Выплаты приходят исполнителю без каких-либо действий с его стороны; документы появляются в кабинете автоматически. Никаких подписаний на выплату нет — в этом весь смысл механики.

8. Что происходит с договором по окончании периода? Придёт ли исполнителю «договор расторгнут»? Нет. Окончание периода — не расторжение: статус становится ended, уведомления о расторжении не отправляются, задним числом в рамку можно платить.

9. Мы уже работаем по 35-му протоколу. Что произойдёт с текущими выплатами при переключении? Переключение — на уровне проекта, делаем мы. Уже созданные выплаты со своими по-контрактными заданиями доживают по старым правилам (протухание, оплата — всё работает). Новые рамки и выплаты после переключения идут по новой механике. Совмещать оба режима на одном проекте нельзя.

10. Есть ли пакетное создание (реестры) для этой механики? Нет, в этой итерации — только поштучные вызовы API. При еженедельной пачке выплат — просто серия POST /task/internalIdempotency-Key на каждый).

11. Можно ли расторгнуть рамку досрочно (исполнитель уволился)? Существующая механика остановки договора сохраняется. Нюанс: по расторгнутой рамке выплаты блокируются — закройте долги по выплатам до расторжения.


Слайд 17. Кто что делает — итог одним экраном

YouDo:

Вы (1С):

Ваши исполнители:


Слайд 18. Следующие шаги

  1. Вы подтверждаете схему (или присылаете вопросы — лучше все сразу).
  2. Вы отвечаете: (а) нерезиденты и МВД-уведомления — как сейчас; (б) нужна ли правка задания задним числом (план=факт) или расхождение закрываем актами; (в) желаемая длина периода по каждому проекту.
  3. Мы: разработка ~1–2 недели после подтверждения.
  4. Тестовый контур: даём доступ к методам → вы прикручиваете вызовы в 1С → совместно гоняем сценарии (включая стык рамок, протухание, backdated).
  5. Пилот на одном проекте → раскатка.