API contract revision
This version makes input validation stricter and fixes several responses so they match what is documented. Review the list of changes that can affect your integration first.
Changes that can affect your integration
These are changes where a request that used to pass (or returned5xx) now returns 4xx, or where a response value your code might be reading changes.- Strict booleans in
POST /v2/debtsandPOST/PATCH /subscriptions:allowOverduePayment,allowPartialPayments,autopay, andenforcePaymentOrderonly accepttrue/false."true",1, etc. return400withdetails[].descriptionmust be a string (400). See API conventions. additionalDatainPOST /v2/debts,POST /payment-links, andPOST/PATCH /subscriptions: it must be a flat object and cannot use reserved keys (description,paymentMethods,productName, etc.). Otherwise,400. See API conventions.POST /payment-links: anexternalClientIdthat does not match a contact returns422 BUSINESS_RULE_VIOLATION(the link used to be created anyway). See Payment links.POST/PATCH /payment-links:expiresAtmust be an RFC 3339 date-time (2026-12-31 23:59or a date alone return400). In thePATCH,expiresAt: nullreturns400(it used to be500; links always expire),metadatanullor not an object returns400, and an emptydescriptionreturns400. See Payment links.PATCH /subscriptions/{id}: validates types, thepaymentMethodsenum, and the exclusion betweenautopay: trueandpaymentMethods(400). ACANCELLEDorENDEDsubscription returns422(it used to be200). See Subscriptions.POST /subscriptions:intervalUnitis case-sensitive (MONTHreturns400) and, if the scheduling is invalid, neither the product nor the inline contact is created. See Subscriptions.PATCH /contacts/{id}:phones: []returns400(it used to be200with no effect). See Contacts.GET /contacts:identifierandexternalClientIdwith different values return400. See Contacts.GET /products: anactivevalue other thantrue/falsereturns400(it used to be read asfalse). See Products.GET /payment-links:createdAtFrom/createdAtTowith an invalid format return400(they used to be compared as text). See Payment links.GET /subscriptions:externalClientIdnow filters (it used to be ignored and returned subscriptions of other contacts). Empty or blank returns400. See Subscriptions.GET /debts/{id},PATCH /debts/{id},POST /debts/{id}/cancel: a canceled debt can be read (200,status: CANCELLED); canceling it again or sending aPATCHreturns422(it used to be404). See Debts.POST /v2/debts: new valueautopayReason: "NO_PRODUCT". If you validateautopayReasonagainst a closed list, add it. See Direct debit.- Dates in contacts, debts, and link payments:
date-timevalues are returned in UTC with milliseconds andZ(2026-09-24T21:09:41.835Z). They used to come without a zone, with+00:00, or with microseconds. See API conventions. PATCH /debts/{id}:dueDatein the response becomesYYYY-MM-DD(it used to be a date-time). See Debts.POST /payment-linkswithout a debtor:paymentUrlbecomes the short URL (it no longer contains theidentifierValue) and can benullif its generation fails. Treat it as an opaque URL. See Payment links.- Payment links, every response:
expiresAtis always returned in UTC with milliseconds andZ(2026-12-31T23:59:59.000Z), even if it was sent with an offset (-06:00). Older links stored with a date alone (2026-12-01) come out as the start of that UTC day (2026-12-01T00:00:00.000Z). See Payment links. - Payment links without an external key, all responses:
externalPaymentLinkIdisnullwhen the link was created withoutexternalPaymentLinkIdor anIdempotency-Keyheader (it used to return aplk_<uuid>value equal to thepaymentLinkId). See Payment links. GET /debtsandGET /payment-links/{id}/payments:createdAtToas a date alone now includes that day (it used to filter up to its start). If you sent the next day to compensate, you now get one extra day.createdAtFromlater thancreatedAtToreturns400with the messagecreatedAtFrom must be earlier than or equal to createdAtTo.See Debts.
Fixes
PATCH /debts/{id}andPATCH /subscriptions/{id}: thePATCHno longer resetsallowPartialPaymentstofalse, andamountPaidcomes out correctly (notnull). See Debts.GET /debts/{id}andGET /debts:descriptionappears in reads. See Debts.POST /v2/debtsandPOST /subscriptions:contact.contactIdcomes with thecon_prefix also when the contact is created inline. See Direct debit.GET /contacts:identifierfilters, andcontactCodeaccepts thecon_prefix. See Contacts.- Contacts: contacts without an email created inline return
email: null(it used to be the text"null"), also when reading existing ones. See Contacts. GET /payment-links?externalPaymentLinkId=: no longer returns500. See Payment links.POST /payment-links: a repeatedexternalPaymentLinkIdreturns409without creating the debt. A link with a debtor no longer fails with500if the portal configuration does not respond. See Payment links.PATCH /payment-links/{id}:expiresAtalso updates the due date of the link’s debt. If that debt was already cancelled, only the link is updated (thePATCHused to fail). See Payment links.- Payment link response: always carries
externalPaymentLinkId,expiresAt,successUrl,metadata,identifierValue,contact, andproduct, withnullwhen there is no value. See Payment links. POST /products: returns what was stored (timestamps,externalProductId,active) instead of echoing the request. See Products.PATCH /products/{id}:active: falsedeactivates the product; renaming to a name already in use, including one used by an inactive product, returns409(it used to be500); invalid types return400(they used to be500). See Products.POST /subscriptions:paymentUrlis no longernull, andscheduling.billingDayis inferred fromstartDate(formonthandyear). See Subscriptions.GET /debtsandGET /payment-links/{id}/payments:createdAtFrom/createdAtToaccept an RFC 3339 date-time in addition to a date. The same date in both returns that day’s debts (it used to be400), and a futurecreatedAtFromwithoutcreatedAtToreturns an empty page (it used to be400). See Debts.PATCHof contacts, products, payment links, subscriptions, and debts:companyCodein the body is taken as context and is no longer rejected as a non-editable field. See API conventions.POST /v2/debts(batch): each error indetails[]carriesfield. See Direct debit.PATCH /debts/{id}: impossible dates (2026-02-30) return400. See Debts.POST /v2/debts,POST /payment-links, and subscriptions:additionalDatasent as an object is stored on the debt (it used to be lost in debts and links). See API conventions.PATCH /subscriptions/{id}: if updating one of the subscription’s debts fails, the response is207witherror.code: PARTIAL_UPDATE(it used to be500 INTERNAL_ERROR). The subscription is updated. See Subscriptions.paymentUrlin debts, subscriptions and payment links: if your company has no private links configuration,paymentUrlis no longernull: it returns your company’s portal URL. Still treat it as an opaque URL. See Debts.

