# API implementation and compatibility
This page is for contributors adding or changing Greenfield endpoints. Integrators should use the getting-started guide and the OpenAPI reference.
# Endpoint implementation
- Add the endpoint and every public schema to the manually maintained OpenAPI 3 document under
BTCPayServer/wwwroot/swagger/v1/. The server merges those files at/swagger/v1/swagger.json. - Select the correct
AuthenticationSchemes.Greenfieldauthorization policy. Add a permission only when no existing policy expresses the access being granted. - Prefer resource-oriented routes and HTTP semantics:
POSTfor creation or actions,PUTfor full replacement,PATCHfor partial updates, andDELETEfor deletion or archival. - Keep JSON conversion rules on the model through attributes. Follow the repository's Newtonsoft.Json conventions.
- Represent values such as high-precision decimals and large integers as strings when JSON number precision or overflow would make clients unsafe. Accept the prior representation when compatibility requires it.
- Add endpoint tests for authorization, store scoping, validation, serialization, and documented responses.
Use 422 Unprocessable Entity for request-model validation errors:
[
{
"path": "propertyName",
"message": "Human-readable message"
}
]
Use 400 Bad Request for a request that is structurally valid but cannot be completed by business logic:
{
"code": "stable-error-code",
"message": "Human-readable message"
}
Keep error codes stable so clients can branch on code rather than parsing message.
# Compatibility rules
Changing a property type or removing a property is a breaking change. Version the endpoint rather than silently changing its contract. A permissive input converter does not preserve compatibility if responses still change type.
Adding an optional response property is normally safe for tolerant clients. Adding a required request property, or an optional property whose absence changes existing update behavior, can break clients. When extending a request:
- Define an explicit default for create operations.
- On updates, distinguish an omitted property from a property explicitly set to its type's default or to
null. - Preserve the stored value when omission means no change.
- Version the endpoint if old and new intent cannot be distinguished safely.
To detect omission, inspect the raw JSON object in the controller or use a Newtonsoft.Json serialization callback to record which properties were absent. Do not infer omission from the deserialized CLR default alone.
Before merging a change, compare both request and response OpenAPI schemas, generated-client behavior, authorization scope, status codes, and webhook payloads. Compatibility includes semantics, not only JSON shape.