Entities with Books. When the Entity has at least one Book,
GET /partners/pages requires a bookId query parameter — the openReceivable and openPayable totals on the page rows are then computed inside that Book. GET /partners and the Partner rows returned by create, update, and delete stay outside the rule and surface open totals across every Book. GET /partners/counts, GET /partners/options, and GET /partners/:partnerId carry no open totals and take no bookId.Partners belong to the Organization
A Partner belongs to the Organization, not to one Entity. One real-world party is one Partner, whichever Entities of the Organization deal with it. An Entity starts using a Partner when something names it in that Entity: a create, an Invoice, a Ledger Line, a Bank Movement, a Payment Order, or a sync. You can also use an existing Partner explicitly. The routes under/api/entities/:entityId/partners serve the Partners that Entity uses. A Partner the Entity doesn’t use answers 404. What a change reaches depends on the field:
For example, when one Entity corrects a supplier’s legal name, every other Entity sees the new name. When it sets a Default Purchase Account for that supplier, the other Entities keep their own.
Roles
A Partner has no type. Whether an Entity buys from a Partner or sells to it is read from that Entity’s books, so the same Partner can be a supplier of one Entity and a customer of another. Theroles field of a Partner row lists what this Entity’s books say:
A Partner can have both roles, or none. In the app, Contactos filters by Relación (Proveedor or Cliente).
Representing Partners
Each Entity is represented by one Partner of its Organization. That Partner carries the Entity’s tax identity (country and taxId), and its representsEntityId is the Entity’s id. Sintropix creates it with the Entity. The other Entities of the Organization use it to name that Entity as their counterparty, for example for what they owe each other.
- An Entity never uses the Partner that represents it. A write that names it in that Entity is refused with
422andPARTNER_REPRESENTS_ENTITY_ERROR, withparams.partnerIdandparams.entityId. This applies to creating or using the Partner, and to naming it on a Ledger Line, an Invoice, a Bank Movement, or a Payment Order. - A bank feed lands a Movement whose counterparty is the Entity itself with no Partner. A Source Feed document addressed to the Entity itself is rejected alone, with
PARTNER_REPRESENTS_ENTITY_ERROR, and the rest of the sync lands. - Its
countryandtaxIdare the Entity’s. Correct them on the Entity. Changing them on the Partner is refused with422andPARTNER_REPRESENTS_ENTITY_TAX_IDENTITY_ERROR.
GET /partners
List every Partner the Entity uses, each row enriched with this Entity’s Open Item totals (unsettled AR and AP balances). The list includes Merged Partners. To keep only active Partners, drop rows where mergedIntoPartnerId is not null.
Response: an array of Partner objects.
An open line on the other side of the account, such as a payment on account or an open credit note, is never netted against these totals. It stays open until an Allocation applies it.
GET /partners/pages
Paginated listing of the Partners the Entity uses, for UI use. Merged Partners are never listed.
Query parameters. Unknown parameters are rejected with 400.
Response
The page carries no counts. Read them from
GET /partners/counts.
Each element of partners is a Partner row: every field of the Partner object above, plus:
The type of
group.value depends on group.by:
GET /partners/counts
Count the Partners the Entity uses, for the tabs of a Partner listing. Merged Partners are never counted. The counts don’t depend on a search or any filter other than role, so read them once per tab, not on every page.
Query parameters. Unknown parameters are rejected with 400.
Response
GET /partners/options
Search the Partners the Entity uses, a short page at a time, to fill a Partner picker or filter. Each option carries only what identifies the Partner. Use it instead of GET /partners when you need to offer a choice of Partners: it reads no open totals and doesn’t return every Partner at once.
It answers in one of two ways:
- Search. Without
partnerIds, it lists Partners in name order, a page at a time. A search never finds a Merged Partner. - By id. With
partnerIds, it returns those Partners, in name order, on one page, so a field that already holds Partners can show them. Merged Partners are included. An id the Entity doesn’t use is left out.cursor,limit, andsearchare ignored.
400.
Response
Show the Partner’s logo next to an option when its
website is set.
GET /partners/:partnerId
Read one Partner the Entity uses, with this Entity’s settings for it. Use it, for example, to read the defaultPurchaseAccountId a bill booking should propose.
Response: the Partner’s shared fields (id, organizationId, representsEntityId, name, legalName, country, taxId, website, aliases, mergedIntoPartnerId, createdAt, and updatedAt), plus this Entity’s entityId, defaultPurchaseAccountId, and booksAutomatically. It carries no open totals and no roles. Each field is described under GET /partners.
A Partner the Entity doesn’t use answers 404 with PARTNER_NOT_FOUND_ERROR.
POST /partners
Create a Partner in the Organization and start using it in this Entity.
Body. Unknown keys are rejected with 400.
A
country and taxId pair belongs to one Partner of the Organization:
- When another Partner of the Organization already holds it, the create is refused with
409andPARTNER_TAX_IDENTITY_ALREADY_EXISTS_ERROR.params.partnerIdnames that Partner. Use it in this Entity instead. In the app, the refusal offers Usar with the existing Partner’s name. - The Entity’s own tax identity belongs to its representing Partner, so it is refused with
422andPARTNER_REPRESENTS_ENTITY_ERROR.
201): the created Partner row, as GET /partners/pages would list it.
PUT /partners/:partnerId
Use a Partner of the Organization in this Entity. Call it when a create is refused with PARTNER_TAX_IDENTITY_ALREADY_EXISTS_ERROR, or to pick a Partner another Entity already uses. Using a Partner the Entity already uses changes nothing, so you can retry safely. No request body.
Response: the Partner row, as GET /partners/pages lists it.
PATCH /partners/:partnerId
Update Partner attributes. A change to name, legalName, country, taxId, website, or aliases reaches every Entity of the Organization. A change to defaultPurchaseAccountId or booksAutomatically reaches this Entity only.
Body: any subset of the fields below. At least one is required; unknown keys are rejected with 400. Send null to clear a nullable field.
A Merged Partner cannot be updated (
409, PARTNER_MERGED_ERROR). A tax identity another Partner of the Organization holds is refused as on create. On a representing Partner, country and taxId can’t change (422, PARTNER_REPRESENTS_ENTITY_TAX_IDENTITY_ERROR).
Response: { "partner": <Partner row>, "previousPartner": <Partner row> }, the row after and before the update.
DELETE /partners/:partnerId
Stop using the Partner in this Entity. Sintropix also deletes the Partner itself when no other Entity uses it and it represents no Entity. Otherwise the Partner stays for the Entities that use it.
A Partner this Entity’s records still reference, such as Ledger Lines with Open Items, is refused (409, PARTNER_IN_USE_ERROR). A Merged Partner is never deleted (409, PARTNER_MERGED_ERROR).
Response: the deleted Partner row, as GET /partners/pages listed it.
GET /api/organizations/:organizationId/partners/:partnerId/logo
Read the Partner’s logo: a 64 × 64 PNG that Sintropix takes from the icon of the Partner’s website. The app shows it in place of the Partner’s initial.
The logo belongs to the Organization, like the Partner and its website, so this route lives under the Organization. There is no logo route under /api/entities/:entityId.
Response
200with the PNG itself (Content-Type: image/png). The response carriesCache-Control: private, max-age=31536000, immutable, so a browser keeps it for up to a year. The URL stays the same when thewebsitechanges, so a cached logo can outlive it. Add the website to the URL, for example?website=acme.cl, to fetch the new logo after a change.404withPARTNER_LOGO_NOT_FOUND_ERRORwhen the Partner has nowebsite, or its site shows no usable icon. A404carries no cache header. A site that could not be reached is tried again on the next request; a site that answered with no usable icon is not.
Organization Partners
GET /api/organizations/:organizationId/partners
List the Organization’s Partners in name order, each with the Entities that use it. Use it to find a Partner another Entity already uses before you create one. Merged Partners are never listed.
This route lives under the Organization, not under an Entity. It needs the books read permission in the Organization. An API key confined to one Entity can call it for that Entity’s Organization; any other Organization answers 404.
Query parameters. Unknown parameters are rejected with 400.
Response
Each element of
partners has the Partner’s shared fields: id, organizationId, representsEntityId, name, legalName, country, taxId, website, aliases, mergedIntoPartnerId, createdAt, and updatedAt. It also has entities, the { id, name } of each Entity that uses the Partner, in name order. A representing Partner never lists the Entity it represents. A row carries no open totals and no per-Entity settings: read those from the Entity routes.
Aliases
An Alias is another name that finds a Partner. Use Aliases when one counterparty appears under several spellings, such asAMAZON WEB SERVICES and Amazon Web Services, Inc..
- Two names count as the same name when they differ only in case, accents, punctuation, or spacing.
- Each name belongs to at most one Partner per Organization. An Alias that matches another Partner’s display name or Alias is refused with
409(PARTNER_ALIAS_TAKEN_ERROR). The errorparamshold thealias, plus thepartnerIdandpartnerNameof the Partner that already has it. - An Alias needs at least one letter or digit (
400). - Partner search on
GET /partners/pages,GET /partners/options, and in the app’s Partner pickers matches Aliases. - An Alias never sets a Partner on a Bank Movement.
55555555-5, so Sintropix finds a foreign Partner by the name the provider states. It first looks for the Partner that holds that name as an Alias. It then looks for a Partner whose display name is the same name, and takes the oldest if several match. It never picks a Merged Partner. Add a spelling as an Alias to route future documents with that spelling to the right Partner.
Set Aliases with the aliases field of PATCH /partners/:partnerId. The list replaces the current Aliases:
Merge Partners
Merge a duplicate Partner into the Partner you want to keep. Both belong to the same Organization, and the merge runs in every Entity that uses the duplicate. The duplicate becomes a Merged Partner, and its name and Aliases become Aliases of the kept Partner. In the app, use the Fusionar row action on the Partners page.POST /api/organizations/:organizationId/partners/:partnerId/merge
Merge the Partner in the path into targetPartnerId, the Partner that stays. The merge runs all-or-nothing across every Entity, and the Audit Trail records every row it changes. There is no merge route under /api/entities/:entityId.
The route needs the books write permission in the Organization. An API key confined to one Entity can merge only a Partner that no other Entity uses, because a merge moves the books of every Entity that uses it. Otherwise it gets 403 with PERMISSION_DENIED_ERROR.
Body. Unknown keys are rejected with 400.
Response (
200): { "partner": <Organization Partner row>, "mergedPartner": <Organization Partner row> }, in the shape GET /api/organizations/:organizationId/partners lists. partner is the kept Partner after the merge. mergedPartner is the merged one, with mergedIntoPartnerId set. The moved lines, Invoices, and Bank Movements are not included; read them back through their own endpoints.
What a merge moves
Every Entity that used the merged Partner now uses the kept Partner. In each of those Entities, Sintropix moves these records from the merged Partner to the kept Partner:- Every Ledger Line in an Entry dated after that Entity’s Lock Date, unless the Entry is deleted or cancelled.
- Every Invoice that is unbooked or whose booking entry holds a line that moves.
- Every Bank Movement that is unbooked or whose bank line moves.
country and taxId), legalName, and website. When the merged Partner represents an Entity, the kept Partner takes that role with the tax identity.
In each Entity, the kept Partner takes the merged Partner’s defaultPurchaseAccountId when it has none there. It takes the merged Partner’s Booking Template, with its documentKind, and booksAutomatically only when it has no template in that Entity. Otherwise, Sintropix removes the merged Partner’s template.
The kept Partner also takes every Payment Order and Expense Claim of the merged Partner, and its Bank Details when the kept Partner has none.
The merge also clears every Follow-up that names the merged Partner. A Partner merged earlier into the merged Partner now points at the kept Partner.
After a merge
A Merged Partner:- Does not appear in
GET /partners/pages, Partner search, or pickers.GET /partnersstill returns it, and so doesGET /partners/optionswhen you name it inpartnerIds. - Is never matched by a Source Feed.
- Cannot be edited, deleted, merged, used in another Entity, or given a Booking Template (
409,PARTNER_MERGED_ERROR). - Cannot be named on a new or updated Ledger Line, Invoice, or Bank Movement. Those writes return
409withLEDGER_ENTRY_LINE_PARTNER_MERGED_ERROR,INVOICE_PARTNER_MERGED_ERROR, orBANK_MOVEMENT_PARTNER_MERGED_ERROR. Use the Partner inmergedIntoPartnerIdinstead.
When a merge is refused
A merge is also refused when an Invoice without a DTE would collide with an Invoice of the kept Partner that has the same direction, kind, and number.
Bank Details
Bank Details state where a Partner receives a bank transfer. A Payment Batch pays each Partner to these details, and can’t be marked Ready while a payee has none. A Partner holds at most one set. The name and RUT the transfer carries are the Partner’s ownname and taxId.
Bank Details are shared by every Entity that uses the Partner. They appear as
bankDetails on every Partner row. When the Partner itself is deleted, they go too.
PUT /partners/:partnerId/bank-details
Set the Partner’s Bank Details. The body states the whole set and replaces any details the Partner already has.
Body
Response: the Partner row, as
GET /partners/pages lists it, with its bankDetails.
DELETE /partners/:partnerId/bank-details
Remove the Partner’s Bank Details. A Partner without them is refused with 404 and PARTNER_BANK_DETAILS_NOT_FOUND_ERROR.
Response: the Partner row, as GET /partners/pages lists it, with bankDetails: null.
Booking Templates
A Booking Template tells Sintropix how one Entity books a Partner’s purchase invoices. It states the Document Kind it books and an ordered list of lines. Each line takes one amount from the Invoice or its DTE and posts it to a Ledger Account on a side. With the Partner’sbooksAutomatically switch on in that Entity, Sintropix books each new purchase invoice of that Partner in that Entity when it is created, but only when the Invoice fits the template exactly.
Use a template for a vendor whose invoices you always book with the same entry shape, such as a hosting provider billed to one expense account plus IVA. Invoices that do not fit land unbooked, and you book them by hand with POST /invoices/:invoiceId/book.
Each Entity keeps its own template and switch for a Partner, so a template saved in one Entity never books another Entity’s invoices. Saving a template gives the Partner the vendor role in that Entity. The Partner’s default purchase account is unaffected.
Document kind
A template’sdocumentKind is invoice or tax_only:
- An
invoicetemplate books the Invoice’s total as a payable on its Control Line. - A
tax_onlytemplate books tax only, with no Control Line. The Invoice it books becomes atax_onlydocument. Use it for a vendor whose facturas de compra (type46) only declare the IVA of a purchase abroad, while the foreign vendor’s own Invoice holds the payable.
Template lines
A template needs at least 2 and at most 10,000 lines. An
invoice template has exactly one line that uses invoice_total: the Control Line. A tax_only template has none, and none of its lines may post to an account whose sub-type is payable, expense_rendition_payable, or receivable (409, TAX_ONLY_LINE_ON_CONTROL_ACCOUNT_ERROR). A wrong number of invoice_total lines is refused with 400.
On an invoice template, the Control Line must follow the control line rules of Book invoice for a payable invoice: a credit on an open-item payable liability account. Other lines may post to the Control Line’s account too. They book as ordinary open items of the Partner. Only the invoice_total line becomes the Invoice’s Control Line.
While a template uses an account as its Control Line, that account’s type, subtype, and tracking cannot change (LEDGER_ACCOUNT_FACT_PINNED_ERROR). An account any template line uses cannot be deleted.
When an Invoice is booked automatically
Sintropix books a new Invoice from the template only when all of these hold:- The create request sent no
bookingEntryWithLines. An explicit booking always wins. - The Invoice is created as
direction: "payable"anddocumentKind: "invoice". Credit notes are never booked automatically. With atax_onlytemplate, the Invoice becomestax_onlyin the same act that books it. - The same request creates the DTE. An Invoice whose DTE is attached later is not booked. A source-feed sync never books a DTE that lands with the Standing
claimed,annulment_requested, orannulled. - The Invoice and its DTE are in the Entity’s functional currency.
- The Partner has
booksAutomaticallyset totruein the Entity. - Every line’s source has a value on the DTE, and none is negative. A DTE that withholds no IVA gives a
dte_withheld_iva_amountline0. - On an
invoicetemplate, the Control Line amount is not0. Other lines with an amount of0are dropped. - At least two lines remain, and they balance exactly. There is no rounding tolerance.
tax_only template couldn’t book stays invoice. In POST /invoices/bulk and the source-feed sync, one Invoice that does not fit never blocks the others. Invoices that exist before you turn the switch on are not booked.
The Audit Trail credits an automatic booking to the system, with the declared actor booking-template.
GET /partners/:partnerId/booking-template
Read a Partner’s template.
Response: { "partner": <Partner row>, "documentKind": "invoice" | "tax_only", "lines": [<line>] }. The Partner row has the shape GET /partners/pages lists. lines is empty and documentKind is invoice when the Partner has no template.
PUT /partners/:partnerId/booking-template
Save a template. The body replaces the whole template; the order of lines is the order of the template.
Body
Unknown keys are rejected with
400.
Response: the saved template, in the shape GET answers.
total of 1190000 and a DTE stating netAmount 1000000 and taxAmount 190000 is booked. The net and tax lines are debited, and the payable is credited. A DTE whose amounts do not add up to the total leaves the Invoice unbooked.
To also book the vendor’s facturas de compra (type 46), add a credit line with dte_withheld_iva_amount on the withheld IVA account. A 46 with a total of 1000000, netAmount 1000000, taxAmount 190000, and withheldIvaAmount 190000 is booked with the withheld IVA credited. On a 33, which withholds no IVA, that line is 0 and is dropped, so the same template books both.
The
wasabil Source Feed lands every 46 with withheldIvaAmount null, because Wasabil no longer states which IVA is withheld. A dte_withheld_iva_amount line has no amount on these DTEs, so the entry does not balance and the Invoice lands unbooked. For a Wasabil vendor’s 46s, book the withheld IVA credit line from dte_tax_amount instead. That template books the vendor’s 46s with a total withholding, but not its 33s.tax_only template that debits the IVA account and credits the withheld IVA account, both from dte_tax_amount:
taxAmount of 190000 lands as a booked tax_only document: IVA debited 190000, withheld IVA credited 190000, and nothing owed.
Then turn the switch on:
DELETE /partners/:partnerId/booking-template
Remove the template. This also turns booksAutomatically off and sets documentKind back to invoice.
Response: the Partner, documentKind: "invoice", and its now empty lines, in the shape GET answers.
Error codes
A Control Line on the wrong side or on an account Book invoice refuses as a payable control account is answered with the same error Book invoice returns.

