---
title: "Create a framework agreement and signing link"
method: POST
path: "/public/framework-agreement/v1/create-framework-agreement"
tags: ["Framework Agreement"]
---

# Create a framework agreement and signing link

`POST /public/framework-agreement/v1/create-framework-agreement`

## Request

- Base URL: `https://api.maqqie.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.maqqie.app/public/framework-agreement/v1/create-framework-agreement`
- Auth: OAuth 2
  - Client credentials
  - Token URL: `https://maqqie.app/auth/realms/maqqie/protocol/openid-connect/token`
- TypeScript: <https://skmtc.dev/maqqie/apis/maqqie-public-api/docs/public/framework-agreement/v1/create-framework-agreement/post.ts> (a function with typed inputs; its response is checked against the schema)

Create a framework agreement and a signing link, for the given worker.
Once the agreement is signed, the FrameworkAgreementSignedEvent webhook is executed.

This endpoint is idempotent for retries: if an unsigned, non-expired framework agreement already exists for
the worker and the requested `isPayrollTaxReduction` matches the worker's stored setting, the existing agreement
and its signing link are returned instead of creating a new one. If the requested `isPayrollTaxReduction`
differs (the worker changes their setting), the pending agreement - including its Stiply signing request - is
cancelled and a new agreement reflecting the new setting is generated. A new agreement is likewise created when
there is no pending agreement (e.g. the previous one expired or was already signed); any obsolete unsigned
agreement is then replaced.

## Request body

- FrameworkAgreementCreationRequestV1
  - `workerId` string, uuid, required: The unique id of the worker, as returned from the /create-worker endpoint.
  - `isPayrollTaxReduction` boolean, required: true if the worker wants us to apply payroll tax reduction (Dutch: loonheffingskorting), false otherwise

## Response `200`

Successfully created the agreement

- FrameworkAgreementCreationResponseV1
  - `frameworkAgreementId` string, uuid, required
  - `signingUrl` string, uri, required: A URL to sign the framework agreement.
  - `signingUrlExpirationTimestamp` string, date-time, required: The timestamp (UTC) at which the signing URL will expire.

## Other responses

- `400`: The request could not be processed. This could be due to a number of reasons: * The request does not have all required data. * Data in the request is invalid. * Data in the request is inconsistent. * The operation is not allowed given the current state of the data.
- `401`: The request did not contain credentials identifying the caller, or the provided credentials were invalid.
- `403`: The data that the request referred to is inaccessible to the caller.

## Changes

- **2026-09-29** `f9510f3f4b22`: 5 breaking, 3 info
  - added the new required request property `isPayrollTaxReduction`
  - added the new required request property `workerId`
  - the request's body type changed from no type to `object`
  - the response's body type changed from no type to `object` for status `200`
  - …4 more
- **2026-09-29** `3352b56bb8fe`: 6 breaking, 2 warning, 2 info
  - the request's body type changed from `object` to no type
  - the response's body type changed from `object` to no type for status `200`
  - the response's body type changed from `string` to no type for status `400`
  - removed the required property `frameworkAgreementId` from the response with the `200` status
  - …6 more
- **2026-09-16** `ccf9834e5006`: 5 breaking, 3 info
  - added the new required request property `isPayrollTaxReduction`
  - added the new required request property `workerId`
  - the request's body type changed from no type to `object`
  - the response's body type changed from no type to `object` for status `200`
  - …4 more
- **2026-09-15** `8085d4c1ab80`: 6 breaking, 2 warning, 2 info
  - the request's body type changed from `object` to no type
  - the response's body type changed from `object` to no type for status `200`
  - the response's body type changed from `string` to no type for status `400`
  - removed the required property `frameworkAgreementId` from the response with the `200` status
  - …6 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/maqqie/apis/maqqie-public-api/changes/public/framework-agreement/v1/create-framework-agreement/post.md)

---

[API](https://skmtc.dev/maqqie/apis/maqqie-public-api.md) - [All operations](https://skmtc.dev/maqqie/apis/maqqie-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/maqqie/apis/maqqie-public-api/revisions/13ed331da2b2?raw)
