# Cardda banking API Documentation > Documentation for Cardda banking API ## Guides - [Countries and Institutions](https://docs.cardda.com/docs/countries-and-institutions.md) - [How to filter results 🔍](https://docs.cardda.com/docs/filters.md) - [Getting started 👋](https://docs.cardda.com/docs/getting-started.md) - [Verification Codes via Webhook 🔐](https://docs.cardda.com/docs/plh-verification-codes.md) - [Card Allocations 💳](https://docs.cardda.com/docs/card-allocations.md) - [The company-id header 🏢](https://docs.cardda.com/docs/company-id.md) - [Errors ⚠️](https://docs.cardda.com/docs/errors.md) - [Pagination 📄](https://docs.cardda.com/docs/pagination.md) - [Rate limits ⏱️](https://docs.cardda.com/docs/rate-limits.md) - [Tutorial: Emit a payroll and reconcile it](https://docs.cardda.com/docs/tutorials-emit-payroll.md) - [Tutorial: Filter transactions](https://docs.cardda.com/docs/tutorials-filter-transactions.md) - [Tutorial: Issue a bill from a USD transaction](https://docs.cardda.com/docs/tutorials-issue-bill.md) - [Tutorial: Create and manage bank recipients](https://docs.cardda.com/docs/tutorials-bank-recipients.md) - [Tutorial: Pagination and backoff for large result sets](https://docs.cardda.com/docs/tutorials-pagination-backoff.md) - [Tutorial: Request and enroll a physical card](https://docs.cardda.com/docs/tutorials-physical-card.md) - [Tutorial: Verify webhook signatures](https://docs.cardda.com/docs/tutorials-verify-webhook.md) - [Tutorials 📚](https://docs.cardda.com/docs/tutorials.md) - [Webhooks 🪝](https://docs.cardda.com/docs/webhooks.md) - [Amounts and currency 💱](https://docs.cardda.com/docs/amounts-and-currency.md) - [Bank transfer description rules 📝](https://docs.cardda.com/docs/bank-transfer-description-rules.md) - [API Keys 🔑](https://docs.cardda.com/docs/api-keys.md) ## API Reference - [Welcome to Cardda 👋](https://docs.cardda.com/reference/getting-started.md) - [How to filter results 🔍](https://docs.cardda.com/reference/filters.md) - [Bank account](https://docs.cardda.com/reference/bank-account.md) - [List Bank Accounts](https://docs.cardda.com/reference/listbankaccounts.md): Returns a paginated list of bank accounts that the current user has access to through their bank keys. ## Common Use Cases ### Finding Your Company's Bank Account (for sender_id) To find your company's bank account for making payments: ``` GET /v1/banking/bank_accounts?rut=771234568 ``` Where `771234568` is your company's RUT. ### Filtering by Account Number To find a specific account by number: ``` GET /v1/banking/bank_accounts?number=987654321 ``` ### Filtering by Bank To list all accounts from a specific bank: ``` GET /v1/banking/bank_accounts?bank_id=cl_banco_santander_chile ``` ### Pagination Use `_start` and `_end` parameters to control pagination: ``` GET /v1/banking/bank_accounts?_start=0&_end=10 ``` ## Important Notes - You can only see accounts you have authorization to operate through bank keys - The `id` field in the response is what you'll use as `sender_id` when creating transactions - Account balance is updated when transactions are synchronized ## Bank IDs Reference Common Chilean bank identifiers: - `cl_banco_de_chile` - Banco de Chile - `cl_banco_bci` - BCI - `cl_banco_santander_chile` - Santander Chile - `cl_banco_itau` - Itaú - `cl_banco_bice` - BICE - `cl_banco_scotiabank` - Scotiabank - `cl_banco_security` - Banco Security - `cl_banco_estado` - BancoEstado - [Retrieve one](https://docs.cardda.com/reference/showbankaccount.md): Returns a bank accounts given it's id - [Pre Authorize Bank Transactions](https://docs.cardda.com/reference/preauthorizebanktransactions.md): Some banks need to pre authorize their transactions using an authorization method. > ❗️ Allowed banks > The following banks require pre authorization: > * Banco de Chile > > If you pre authorize transactions from another bank, you will receive an error. - [Authorize Bank Transactions](https://docs.cardda.com/reference/authorizebanktransactions.md): Authorize bank transactions of a bank account - [Dequeue Bank Transactions](https://docs.cardda.com/reference/dequeuebanktransactions.md): Dequeue bank transactions that belong to a bank account - [Synchronize Bank Account's recipients](https://docs.cardda.com/reference/synchronizerecipients.md): Synchronize recipients of a bank account async, so it may take a while to complete. - [Synchronize Bank Account's transactions](https://docs.cardda.com/reference/synchronizetransactions.md): Synchronize transactions of a bank account async, so it may take a while to complete. - [Authorize Bank Account's recipients](https://docs.cardda.com/reference/authorizerecipients.md): Some banks allow authorization of several recipients. > ❗️ Allowed banks > The following banks allow the authorization of several recipients: > * Banco de Chile > * Banco BCI > If you authorize recipients from another bank, you will receive an error. - [Bank recipient](https://docs.cardda.com/reference/bank-recipient.md) - [List Bank Recipients](https://docs.cardda.com/reference/listbankrecipients.md): Returns a paginated list of bank recipients (beneficiaries) configured for your bank accounts. > 🚧 **Recipients are per bank account, not per company.** A recipient belongs to exactly one > `bank_account` (its `owner_id`). The same person enrolled in two of your accounts is two > different recipients, with two different ids. Before creating a transfer, look the recipient > up **scoped to the account that pays** — `?owner_id={sender_id}` — never by name alone: > passing a recipient from another account fails with > `422 "Recipient must belong to same account as transaction"`. The per-field operators in [Filters](https://docs.cardda.com/docs/filters) — `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$ne`, `$regex` — are supported on the columns listed in **Query parameters**, passed as the value of that column (`?alias={"$regex":"proveedor"}`). The set is the same for every listable resource; the inclusive comparisons `$gte` / `$lte` are available here too, they are just of little use on this resource's mostly-textual columns. A bare value is an **exact match**; use `{"$regex": "..."}` for partial, case-insensitive matching. `$or` is **not** a per-field operator: it is a separate top-level query parameter taking an array of filter objects (`?$or=[{"alias":{"$regex":"abc"}},{"name":{"$regex":"abc"}}]`), so it does not belong inside a field filter — see the `$or` parameter below and [Logical OR operations](https://docs.cardda.com/docs/filters). ## Common Use Cases ### Finding a Recipient by Name or Alias To find recipients by their alias (commonly used identifier): ``` GET /v1/banking/bank_recipients?alias=proveedor-abc ``` ### Finding Recipients by RUT To find all recipients with a specific RUT: ``` GET /v1/banking/bank_recipients?rut=761234567 ``` ### Finding Recipients for a Specific Bank Account To list recipients associated with a specific bank account: ``` GET /v1/banking/bank_recipients?owner_id=456e7890-a12b-34c5-d678-901234567890 ``` ### Finding Recipients by Status To filter by approval status: ``` GET /v1/banking/bank_recipients?status=approved ``` ### Finding Recipients by Bank To list all recipients from a specific bank: ``` GET /v1/banking/bank_recipients?bank_id=cl_banco_estado ``` ### Pagination and Sorting ``` GET /v1/banking/bank_recipients?_start=0&_end=50&_order=desc&_field=created_at ``` ## Important Notes - The `id` field in the response is what you'll use as `recipient_id` when creating transactions - `owner_id` is the bank account this recipient belongs to. A transfer only accepts a recipient whose `owner_id` equals the transfer's `sender_id` - Recipients must be in `approved` status to receive individual transfers; a payroll transfer accepts any status except `deleted` - Some banks require authorization tokens when creating recipients - `recipient_account_id` is an internal field returned only to Cardda administrators; company users won't see it in the `index`/`show` responses ## Recipient Status Values - `draft` - Recipient created but not enrolled in bank - `enrolled` - Enrolled at the bank - `preauthorized` - Preauthorized, awaiting final authorization - `deleted` - Soft-deleted recipient - `approved` - Ready to receive transfers - [Create Bank Recipient](https://docs.cardda.com/reference/createbankrecipient.md): Creates a new bank recipient (beneficiary) for transfers. Recipients must be created before you can send them payments. ## Recipient Creation Flow ### Basic Flow (Most Banks) 1. Create recipient with account details 2. Recipient is automatically enrolled at the bank 3. Once approved, recipient can receive transfers ### Banco de Chile Flow Requires authorization token or device: 1. Create recipient with authorization method 2. Provide token or device_id 3. Recipient is enrolled and approved ### Draft Recipients (for Payrolls) Set `transition: null` to create as draft: 1. Create draft recipient 2. Associate with payroll 3. Authorize along with payroll ## Examples ### Standard Recipient Creation ```json { "owner_id": "456e7890-a12b-34c5-d678-901234567890", "account_number": "123456789", "account_type": "corriente", "rut": "761234567", "name": "Proveedor ABC SpA", "alias": "proveedor-abc", "email": "pagos@proveedor.cl", "bank_id": "cl_banco_estado" } ``` ### Banco de Chile with Token ```json { "owner_id": "456e7890-a12b-34c5-d678-901234567890", "account_number": "987654321", "account_type": "corriente", "rut": "772345678", "name": "Empresa XYZ", "alias": "empresa-xyz", "email": "finanzas@xyz.cl", "bank_id": "cl_banco_de_chile", "authorization_method": "digipass", "token": "123456" } ``` ## Important Notes - The `owner_id` must be a bank account you have access to - RUT format must include only numbers and verification digit - Email is used for transfer notifications at some banks - Alias should be unique within your recipients for easy identification - [Retrieve one](https://docs.cardda.com/reference/showbankrecipient.md): Returns a bank recipient given it's id - [Update one](https://docs.cardda.com/reference/updatebankrecipient.md): Updates a bank recipient given it's id - [Authorize one](https://docs.cardda.com/reference/authorizebankrecipient.md): Some banks allow authorization of recipients. > ❗️ Allowed banks > The following banks allow the authorization of a single recipient: > * Banco BCI > > If you authorize recipients from another bank, you will receive an error. - [Enroll one](https://docs.cardda.com/reference/enrollbankrecipient.md): This endpoint is meant to be used when a bank recipient fails to be enrolled or was deleted in the bank and returns to a 'draft' or 'deleted' status with a null transition, so this endpoint can be used to re enroll that same recipient which will update the null transition once again to 'enroll'. - [Parse recipient from clipboard](https://docs.cardda.com/reference/parsebankrecipient.md): Extracts structured bank-recipient fields from a free-text blob (e.g. the typical "datos de transferencia" a payee pastes from WhatsApp or email) using an AI parser. Returns the best-effort recipient fields; any field the parser could not confidently extract is returned as `null`. The result is a suggestion to prefill a recipient form — it does not create a recipient. This endpoint does not require a company scope. It is rate-limited to 30 requests per minute per credential. - [Delete one](https://docs.cardda.com/reference/deletebankrecipient.md): Soft-deletes a bank recipient. The recipient is marked as `deleted` (it is not physically removed) and the resulting record is returned in the response body. Deletion is rejected when the recipient still has pending or in-process transfers. - [Bank transaction](https://docs.cardda.com/reference/bank-transaction.md) - [List bank transactions](https://docs.cardda.com/reference/listbanktransactions.md): Returns a paginated list of bank transactions for authorized accounts, with filtering, sorting and pagination (`_start` / `_end`, default 25 items). Each transaction embeds its related entities: **recipient** (with bank details), **sender**, **bank_errors**, **payables** (if the Pay product is activated) and **payroll** (if applicable). ## Authorization - Regular users can only view transactions from accounts they have access to through a bank key. - The `company-id` header also drives **wallet-transaction visibility**: wallet transactions inscribed by other users are hidden unless you hold `wallet_transactions_view_all` in the company set on the header. The scope applies this rule in SQL (`with_wallet_visibility`), so the same request under a different `company-id` can return a different set of wallet transactions. ## Filtering The per-field operators in [Filters](https://docs.cardda.com/docs/filters) — `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$ne`, `$regex` — work on every column listed in **Query parameters**, passed as the value of that column (`?amount={"$gte":100000}`). A field name that is not a real column is rejected with `400` (`{"type": "invalid_query", "error": "Unknown field: …"}`) — check the list below before inventing one. `$or` is **not** a per-field operator: it is a top-level query parameter of its own, taking an array of filter objects (`?$or=[{"status":"draft"},{"amount":{"$gt":100000}}]`). Writing it inside a field — `?amount={"$or":…}` — does not do what you expect. See [Logical OR operations](https://docs.cardda.com/docs/filters). `amount` is an integer in the **minor unit of the account's currency**, which for CLP is the whole peso — see [Amounts and currency](https://docs.cardda.com/docs/amounts-and-currency). - [Create bank transaction](https://docs.cardda.com/reference/createbanktransaction.md): Creates a bank transaction that transfers money from one of your accounts to a recipient enrolled in it. ## Workflow - **Individual transfer** (no `bank_payroll_id`): created with status `draft` and transition `enqueue`, automatically enqueued for processing at the bank, which approves or declines it. Email notifications are sent based on company settings. - **Payroll transfer** (`bank_payroll_id` set): created as `draft` with no transition, dispatched only when the whole payroll is authorized — never individually. - `transition: null` creates a draft that stays put (see the `transition` field). ## Prerequisites 1. **`sender_id`** — an account reachable through a bank key, with sufficient funds (`GET /v1/banking/bank_accounts`). 2. **`recipient_id`** — a recipient **enrolled in the sending account** (`recipient.owner_id == sender_id`): `GET /v1/banking/bank_recipients?owner_id={sender_id}`. 3. **`bank_key_id`** *(optional)* — defaults to the account's highest-priority approved key (`GET /v1/banking/bank_keys`). Every validation rule is documented on its request-body field — read `amount` (minor unit per currency, per-bank interbank ceilings), `description` (base character set, per-bank caps) and `recipient_id` (status requirements) before building the payload. **CLP has no subunit — send `1000` for $1.000**. See [Amounts and currency](https://docs.cardda.com/docs/amounts-and-currency). - [Retrieve one](https://docs.cardda.com/reference/showbanktransaction.md): Returns a bank transaction given it's id - [Re-enqueue one](https://docs.cardda.com/reference/retryenqueuebanktransaction.md): This endpoint is meant to be used when a bank transaction fails to be enqueued in the bank and returns to a 'draft' status with a null transition, so this endpoint can be used to retry to enqueue that same transaction, which will update the null transition once again to 'enqueue'. - [Dequeue one](https://docs.cardda.com/reference/deletebanktransaction.md): Dequeues a bank transaction - [Get receipt](https://docs.cardda.com/reference/getbanktransactionreceipt.md): Returns a URL to download the receipt for a specific bank transaction - [Retry retrieval of receipt](https://docs.cardda.com/reference/retryreceiptbanktransaction.md): This endpoint is meant to be used when a bank transaction fails to retrieve a receipt and has already been approved. - [Update one](https://docs.cardda.com/reference/updatebanktransaction.md): Updates the editable fields of a bank transaction. For company users only `comments` and `metadata` can be modified — every other field (amount, recipient, status, ...) is managed by the banking flow and is immutable here. - [List bank keys](https://docs.cardda.com/reference/listbankkeys.md): Returns a paginated list of bank keys — the credentials Cardda holds on behalf of a company to operate against a bank's online portal. A bank key is what lets Cardda actually move money: it grants Cardda the rights to **list** bank accounts, **enroll** recipients, **create** transactions, and **pull** statements/transactions from the bank. Without an `approved` bank key for a given bank, the rest of the Banking API has no upstream connection. ## When you'll use this endpoint - Show the user "which banks are linked" in your dashboard. - Detect that a key needs re-authentication (`status: declined`) — most often because the user changed their bank password. - Pick the right `user_id` before issuing a `POST /v1/banking/bank_keys/{id}/confirm` (re-validation flow). A credential is no longer tied to a single company — see the `companies` array in the response. ## Response structure Each item is a **filtered** view of the bank key — sensitive fields (`password`, `secrets`, `auth_seed`, `card`) are stripped automatically. You get: | Field | Description | | --- | --- | | `id` | UUID. | | `user_id` | Firebase user id of the person who provided the credentials. | | `companies` | Per-company KYC status. A credential can be shared across several companies (razones sociales); each entry carries `id`, `name`, `identifier` (RUT) and `kyc_completed`. Replaces the removed single-company `holder_id`. | | `source_key_id` | If this key was cloned from a parent key (used for multi-account banks where one set of credentials grants access to multiple accounts), the parent's id. | | `type` | STI subclass — bank-specific behavior (e.g. `Banking::Cl::BancoDeChile::Key`, `Banking::ItauKey`). | | `aux_type` | Auxiliary classification, used by some banks to differentiate business / personal / corporate flows. | | `status` | Lifecycle status (see enum). | | `rut` | Tax id of the credential's account. Format `XXXXXXXX-Y`. | | `email` | Notification email registered at the bank. | | `authorization_method` | Second factor pinned on this credential (`token`, `digipass`, `device`, `multipass`, `santander_pass`, `bice_pass`, `itau_pass`). Almost always `null`: the method is normally chosen per operation and sent in the authorize/preauthorize body, not stored here. | | `priority` | Sort order when multiple keys share the same company + `bank`. Higher wins. | | `bank_errors` | Recent errors (auth failures, captcha challenges, scheduled maintenance). | | `accounts` | Bank accounts visible through this key. | | `kyc_completed` | Whether KYC was completed for the user that owns the key. | ## Common queries The list is scoped to the credentials owned by the caller (by `user_id`); the company link now lives in each key's `companies` array, not a queryable `holder_id` column. ```bash # Keys for a specific person (the dashboard's pattern) GET /v1/banking/bank_keys?\ user_id=&\ _order=desc&_field=created_at&_start=0&_end=60 # Only declined keys that need re-auth GET /v1/banking/bank_keys?\ status=declined # Filter by RUT GET /v1/banking/bank_keys?\ rut=76123456-7 # Filter by bank type (Banco de Chile only) GET /v1/banking/bank_keys?\ type=Banking::Cl::BancoDeChile::Key ``` ## Security note Bank-key sensitive fields (`password`, `auth_seed`, `card`, `secrets`) are **never** exposed by this endpoint. Cardda exposes them only through a separate, internal-by-default reveal flow that requires a dedicated permission plus a fresh second-factor confirmation; if your integration needs that flow, contact your Cardda account manager. All operators in [Filters](https://docs.cardda.com/docs/filters) are supported on the columns listed below. - [Create a bank key](https://docs.cardda.com/reference/createbankkey.md): Stores a new set of bank credentials for the company. Cardda encrypts the secrets at rest; this is the only entry point that accepts plain-text credentials. Upon creation Cardda runs an asynchronous validation against the bank — the key starts as `pending`; poll the resource until `status` flips to `approved` (or `declined`). A credential can be shared across several companies. If you re-enter a credential you already own (same `user_id` + `type`, plus `rut` for CL/MX or `email` for US) and associate it to another company, Cardda attaches that company to the existing key instead of creating a duplicate — the response is **`200`** carrying the existing key (vs `201` for a brand-new key). - [Retrieve one](https://docs.cardda.com/reference/showbankkey.md): Returns a bank key given it's id - [Update one](https://docs.cardda.com/reference/updatebankkey.md): Receives new credentials to update a bank key - [Delete one](https://docs.cardda.com/reference/deletebankkey.md): Deletes a bank key (banking credential) and detaches it from every company it was associated with. The deleted key is returned in the response body. Note: deletion can be blocked at the database level when the credential is still referenced by other banking records (e.g. in-flight transactions). In that case the request fails and the credential is preserved. - [Sync bank key](https://docs.cardda.com/reference/syncbankkey.md): Enqueues a background job that re-fetches the bank accounts exposed by this credential and refreshes their capability data. Use it to repopulate stale account/permission information without deleting and recreating the key. The job runs asynchronously — this endpoint only acknowledges the enqueue and responds `202 Accepted`. Requests are debounced: if a sync was already enqueued for this key within the last 30 seconds, the request is a no-op and the response carries `enqueued: false` (still `202`). This protects the upstream bank from rapid retries. - [Bank payroll](https://docs.cardda.com/reference/bank-payroll.md) - [Retrieve one](https://docs.cardda.com/reference/showbankpayroll.md): Returns a bank payroll given it's id - [Destroy one](https://docs.cardda.com/reference/deletebankpayroll.md): Deletes a `draft` bank payroll together with all its attached bank transactions. The teardown runs **asynchronously**: eligibility is checked synchronously (so an ineligible payroll still gets an immediate `422`) and the deletion itself is handed to a background job. A successful call therefore answers **`202 Accepted`** with the payroll as it was *before* the teardown — it is not yet `deleted` in that body. Poll `GET /v1/banking/bank_payrolls/{bank_payroll_id}` to observe the final state. Only a clean draft can be deleted: `status: draft`, no transition in flight, and no already-processed (terminal) transfers. - [List bank payrolls](https://docs.cardda.com/reference/listbankpayrolls.md): Returns a paginated list of bank payrolls — the batches of wire-transfer transactions Cardda submits to a single bank account. A payroll groups multiple `transactions` so they can be authorized at the bank with a single TOTP / coordinate / signature challenge. Use this endpoint to: - Show "month-end vendor batches" in your dashboard, sorted newest-first. - Audit the lifecycle of a batch (`draft` → `enrolled` → `preauthorized` → `approved` / `declined`). - Reconcile each line item: the response includes `transactions` for every payroll, so you don't need a second round-trip per row. - Pull the receipt (`receipt` is `true` once the bank returns the proof of payment). ## Response structure Each payroll exposes: | Field | Description | | --- | --- | | `id` | UUID. | | `name` | Free-form label (e.g. "April vendor batch"). | | `status` | Lifecycle status (see enum below). | | `transition` | Currently-running async transition, when applicable (`enroll`, `preauthorize`, `authorize`, `delete`). | | `payment_date` | Scheduled payment date (date only). | | `category` | Optional grouping key set by the company. | | `online` | Payment timing flag — `true` for same-day payrolls, `false` for deferred payrolls (a future `payment_date` is required). | | `holder_id` | UUID of the company (multi-tenancy). | | `sender_id` | UUID of the source `bank_account`. | | `bank_id` | Bank where the payroll lives (e.g. `cl_banco_de_chile`, `cl_santander`). | | `external_id` | Identifier returned by the bank once the payroll is accepted. | | `number_of_transactions` | Count of line items in the batch. | | `total` | Sum of `amount` across all `transactions`. | | `transactions` | Embedded array of line items. | | `receipt` | Whether a downloadable receipt exists. Pull it from `GET /v1/banking/bank_payrolls/{id}/receipt/url`. | ## Common queries ```bash # Most recent 60 payrolls of a company (the dashboard's default) GET /v1/banking/bank_payrolls?\ holder_id=&_order=desc&_field=created_at&_start=0&_end=60 # Only payrolls awaiting authorization (the "to-do" inbox) GET /v1/banking/bank_payrolls?\ status={"$in":["enrolled","preauthorized"]}&\ holder_id= # Search by name GET /v1/banking/bank_payrolls?\ name={"$regex":"april"}&holder_id= # Batch fetch by id GET /v1/banking/bank_payrolls?id={"$in":["",""]} # Payrolls of a specific source account GET /v1/banking/bank_payrolls?sender_id= ``` All operators in [Filters](https://docs.cardda.com/docs/filters) (`$gt`, `$lt`, `$in`, `$regex`, `$or`, `$ne`, …) are supported across every column listed in **Query parameters**. - [Create a bank payroll](https://docs.cardda.com/reference/createbankpayroll.md): Creates an empty bank payroll in `draft` state. The request body takes a `name` and the `sender_id` (UUID of the source `bank_account`), plus the optional `online` flag (`true` — the default — for same-day payrolls, `false` for deferred), `payment_date` (required when `online` is `false`) and `category`. Line items are not part of this request — attach them by creating each transaction via `POST /v1/banking/bank_transactions` with the new payroll's id passed as `bank_payroll_id`. Once the line items are in place, walk the lifecycle: 1. `POST /v1/banking/bank_payrolls/{id}/enroll` — mandatory first step; requires `status: draft`, no transition in flight, and **at least one** attached transaction. The call answers `200` while the payroll is still `transition: enroll`; the bank settles it asynchronously into either `enrolled` or `pending_validation` (the branch step 2 covers), or `enroll_failed`. Poll the show endpoint for the landing state. 2. `POST /v1/banking/bank_payrolls/{id}/validate` — **conditional branch**, only when enrollment left the payroll in `pending_validation` (recipients the bank still needs validated). Requires `token` **and** `verification_code`. 3. `POST /v1/banking/bank_payrolls/{id}/preauthorize` — requires `status: enrolled`. 4. `POST /v1/banking/bank_payrolls/{id}/authorize` — final step; the payroll ends `approved` or `declined`. See [Tutorial: Emit a payroll and reconcile it](https://docs.cardda.com/docs/tutorials-emit-payroll). - [Enroll one](https://docs.cardda.com/reference/enrollbankpayroll.md): This endpoint enrolls a Payroll on the corresponding bank. - [Remove one](https://docs.cardda.com/reference/removebankpayroll.md): Returns an enrolled bank payroll to draft - [Preauthorize one](https://docs.cardda.com/reference/preauthorizebankpayroll.md): Preauthorizes a Bank Payroll. Banco BCI and Banco de Chile require this step. However, Banco BCI does not require the authorization method to be sent - [Authorize one](https://docs.cardda.com/reference/authorizebankpayroll.md): Authorizes a Bank Payroll - [Authorize all payroll recipients](https://docs.cardda.com/reference/authorizebankpayrollrecipients.md): Authorizes all recipients associated with the payroll not previously authorized. To do this, the payroll's status must be pending_validation. - [Sync payroll](https://docs.cardda.com/reference/syncpayroll.md): Syncs the payroll and its transactions with the bank's current status - [Get receipt](https://docs.cardda.com/reference/getbankpayrollreceipt.md): Returns a URL to download the receipt for a specific bank payroll - [Retry retrieval of receipt](https://docs.cardda.com/reference/retryreceiptbankpayroll.md): This endpoint is meant to be used when a bank payroll fails to retrieve a receipt and has already been approved. - [Download a Bank Payroll Formatted File](https://docs.cardda.com/reference/downloadbankpayrollfile.md): This endpoint will allow you to download a Bank Payroll file in the format that the bank requires. This file is the one that you will upload to the bank's website to make the payment. - [Update one](https://docs.cardda.com/reference/updatebankpayroll.md): Updates the editable fields of a bank payroll (its name, scheduled payment date, category, whether it is paid online/same-day, and the sending account). - [Bank device](https://docs.cardda.com/reference/bank-device.md) - [List all](https://docs.cardda.com/reference/listbankdevices.md): Returns a list of bank devices - [Retrieve one](https://docs.cardda.com/reference/showbankdevice.md): Returns a bank device given it's id - [Update one](https://docs.cardda.com/reference/updatebankdevice.md): Receives names or configurations for the a bank device - [Reveal OTP](https://docs.cardda.com/reference/revealbankdeviceotp.md): Returns the current bank device one time password (OTP) - [List Banks](https://docs.cardda.com/reference/listbanks.md): Returns the list of banks Cardda supports. This is **global reference data**: it is not scoped to a company, returns the same list to every caller, and **requires no authentication** — this endpoint accepts requests with no `Authorization` bearer token and no `company-id` header. Use each bank's `id` (a stable slug such as `cl_banco_estado`) as the `bank_id` value when creating bank recipients, reading balances, or filtering by bank. Results are paginated and support the standard `_start`/`_end`/`_order`/`_field` window, and the response carries `X-Total-Count` / `Content-Range` headers. - [List Convenios](https://docs.cardda.com/reference/listconvenios.md): Returns every payment agreement ("convenio") configured on a bank account, ordered by `codigo`. Readable by any member of the company that owns the account. This endpoint is **not** paginated — it returns the full list. - [Sync Convenios](https://docs.cardda.com/reference/syncconvenios.md): Triggers an asynchronous job that re-fetches the account's convenios from the bank. Returns immediately once the job is enqueued. Requires a `bank_key_id` selecting the approved bank key (crawler credential) whose manager links to this account. Available to members of the account's company. - [Vendor card](https://docs.cardda.com/reference/vendor-card.md) - [List vendor cards](https://docs.cardda.com/reference/listvendorcards.md): Returns a paginated list of vendor cards (corporate cards issued by Cardda). Each row in the response represents a single physical or virtual card and exposes its current status, spending limits, balance, and the user it is assigned to. The result is scoped per-caller across every company the caller has permission in (via `policy_scope`), **not** by the `company-id` header — the header is not consulted for this endpoint, and omitting it still returns `200` with the caller's full permitted scope across companies. To narrow the results, filter explicitly; `user_id` is a **cardholder** filter (it returns only cards assigned to that user), not a per-company restriction. - **Admins** see every card in their permitted scope. - **Company members** with the `vendor_cards_manage` permission see every card of the companies they manage. - Regular users see only cards assigned to them (`user_id` matches their Firebase user id). The `type` field (issuing vendor / STI sub-class) is returned to **every** caller: it is the model's Single Table Inheritance discriminator column, so it always serializes into the row (the controller's `methods.push(:type) if admin?` is a no-op — `type` is already a column, not a computed method). ## Response structure Each item is a `VendorCard` plus the following computed fields: | Field | Description | | --- | --- | | `spent` | Amount spent in the current spending interval, as an integer in the minor unit of the transactions' currency (whole pesos for CLP). Sign-flipped from the negative `amount_cents` of the spends. | | `remaining_balance` | Funds still available on the card, as a decimal string in the card currency (not cents). | | `preference_restricted_spendable` | Spendable amount taking active preferences into account. | | `spent_in_vendor_interval` | Amount spent in the vendor's billing interval. | | `fees_in_vendor_interval` | Fees accrued in the vendor's billing interval. | | `limit_amount` | Hard spending limit (`limit_based` strategy). | | `limit_amount_preference` | Pending limit change (waiting to be pushed to the vendor). | | `allocated_amount` | Funds currently loaded onto the card (`allocation_based` strategy). | | `allocated_amount_preference` | Pending allocation change. | ## Filtering grammar Every column documented below accepts the MongoDB-style operators described in [Filters](https://docs.cardda.com/docs/filters): `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$ne`, `$regex`, `$or`. Combine them on a single field (`created_at={"$gte":"2026-01-01T00:00:00Z","$lt":"2026-02-01T00:00:00Z"}`) or across fields (`status=active&user_id=...`). ## Common queries ```bash # Active + inactive + pending cards of a specific user (the dashboard's default) GET /v1/vendor_cards?\ $or=[{"status":"active"},{"status":"inactive"},{"status":"pending"}]&\ user_id=&\ _order=desc&_field=created_at&_start=0&_end=25 # Search by name OR last4 (cardholder lookup) GET /v1/vendor_cards?\ $or=[{"name":{"$regex":"maria"}},{"last4":{"$regex":"^4242"}}]&\ _start=0&_end=50 # Cards assigned to a specific person, with allocation-based control GET /v1/vendor_cards?\ user_id=&\ spending_control_strategy=allocation_based # Cards by id (batch lookup, e.g. to refresh a dashboard view) GET /v1/vendor_cards?id={"$in":["Q2FyZDoxMDIwNjQ5Mw==","Q2FyZDoxMDIwNjQ5NA=="]} ``` - [Retrieve sensitive data](https://docs.cardda.com/reference/retrievevendorcard.md): Returns the sensitive information of the card (PAN, CVC, expiry). Authorized for admins or the cardholder the card belongs to. This is the only endpoint that exposes the full card number — the list and show endpoints redact it. - [Update a card](https://docs.cardda.com/reference/updatevendorcard.md): Updates the specified card. Use this endpoint to: - Activate or deactivate a card - Allocate funds to a card - Configure recurring allocations - Set spending limits ## Permissions | Action | Required permission | |--------|-------------------| | Change `status_preference` or `name` | Card owner, admin, or `vendor_cards_manage` permission | | Change allocation params | Admin or `vendor_cards_manage` permission | | Change spending limit params | Admin or `vendor_cards_manage` permission | ## Top-up If you send `allocated_amount_preference_cents` with the **same value** the card already has, but the card has spent some of those funds (i.e. the actual balance is lower), the system will automatically **top-up** the card back to the requested amount. This is useful for refilling a card to its original balance after spending. **Example:** A card was allocated 50,000 CLP. The user spent 20,000 CLP, so the actual balance is 30,000 CLP. Sending `{"allocated_amount_preference_cents": 50000}` again will top-up the card back to 50,000 CLP. For a complete guide with examples, see [Card Allocations](/reference/card-allocations). - [Retrieve one](https://docs.cardda.com/reference/showvendorcard.md): Returns a single vendor card by id, including its current limits, allocations, and balances. Visible to admins, holders of the `vendor_cards_view` / `vendor_cards_manage` permission, or the cardholder the card belongs to. In addition to the base card fields, the detail response exposes computed fields not present on the list endpoint: `spent_in_interval_with_limit_currency`, `vendor_max_spending_limits`, `vendor_max_allocation`, `non_sensitive_information`, `last_allocation_transaction_status`, `last_allocation_transaction_created_at`, and `allocation_priority_stats`. When the caller can read the company balance, `company_expendable_balance_in_limit_currency` is also included. The sensitive `vendor_data` blob is always excluded — use the `retrieve` endpoint for PAN/CVC. - [Change card PIN](https://docs.cardda.com/reference/updatevendorcardpin.md): Sets a new 4-digit PIN on a physical card. Authorized for admins, holders of the `vendor_cards_manage` permission, or the cardholder. The `pin` parameter is **required** (missing → `412`, from `params.require(:pin)`). It must match `^\d\d\d\d$` and the card's vendor must support PIN updates; otherwise the endpoint returns `422` with `{ "error_code": "vendor_cards/pin_not_supported" }`. Vendor-side failures return `500` with the vendor's message. - [Reprint (re-issue) a card](https://docs.cardda.com/reference/reprintvendorcard.md): Re-issues a card, producing a new `VendorCard` (for example after a physical card is lost or damaged). Authorized for admins or the cardholder. Flow: - The card's vendor must support re-issuing (`can_reprint?`), otherwise `412`. - Shipping fields (`recipient_name`, `shipping_address`, `contact_phone`) are only valid for **physical** cards; sending them for a virtual card returns `422`. - If the card is not already canceled, it is first canceled for reprint; if the cancellation cannot complete, the endpoint returns `412`. - On success the newly issued card is returned. The request body is optional; provide shipping details to redirect the reprinted physical card. - [Close card account](https://docs.cardda.com/reference/closevendorcardaccount.md): Closes the underlying account for the card at the issuing vendor. Authorized for admins or the cardholder. Takes no request body and returns an empty `200` on success. - [List card issuing requests](https://docs.cardda.com/reference/listcardissuingrequests.md): Returns a paginated list of card issuing requests for the company. A card issuing request is what the dashboard creates when a user asks for a card: it captures the requested budget, interval, and (for physical cards) the shipping details, and is later approved by Cardda — producing the actual `VendorCard` and setting `vendor_card_id`. Authorization is `index? = admin? || in_company?`. A **non-admin** caller must therefore resolve a company they belong to — supplied via the `company-id` header (or a `company_id` query param). With neither present the caller has no company membership, fails the gate, and the request returns **401**. Admins bypass the gate. Once authorized, the result is scoped per-caller via `policy_scope`. That scope is not limited to the resolved company: it spans every company where the caller holds the `card_issuing_requests_manage` permission, plus the caller's own requests. Roles within that scope: - **Admins** see every request. - **Managers** (`card_issuing_requests_manage` permission) see every request of the companies they manage. - Regular users see only their own requests (`user_id` matches their Firebase user id). Each row includes the computed fields `kyc_completed` (whether the company finished KYC) and `shipping_municipality_name` (municipality resolved from the shipping address). All operators in [Filters](https://docs.cardda.com/docs/filters) are supported on the columns below. - [Create a card issuing request](https://docs.cardda.com/reference/createcardissuingrequest.md): Creates a card issuing request. Requires the caller to be a member of the target company **and** either an admin or hold the `card_issuing_requests_manage` permission. On creation the request runs an eligibility check (`Cards::CardIssuingEligibilityChecker`); if it fails, the endpoint returns `422` with `{ "message": , "errors": [...] }`. For physical CLP cards, `recipient_name` and `shipping_address` are required (model validation). `budget_cents` must be ≥ 1 and `budget_currency` a valid ISO-4217 currency. - [Retrieve one](https://docs.cardda.com/reference/showcardissuingrequest.md): Returns a single card issuing request by id. Visible to the request's owner, a manager (`card_issuing_requests_manage`), or an admin. Includes the computed fields `kyc_completed` and `shipping_municipality_name`. - [Update one](https://docs.cardda.com/reference/updatecardissuingrequest.md): Updates a card issuing request. The owner, a manager, or an admin may edit the base fields. Certain fields are role-gated and, if present without the required role, the whole request is rejected with `401`: - `user_id`, `company_id`, `budget_cents`, `budget_currency` → require the caller to act as a **manager** (admin or `card_issuing_requests_manage`). - `tracking_number`, `tracking_url`, `estimated_delivery_date`, and the milestone timestamps `printing_at` / `sent_at` / `delivered_at` → **Cardda staff-only**. - `status` is only permitted for admins. `physical` cannot be changed after creation, and shipping fields cannot be blanked on physical CLP requests (model validations → `422`). - [Confirm delivery](https://docs.cardda.com/reference/confirmdeliverycardissuingrequest.md): Lets the cardholder self-confirm receipt of a physical card: flips a dispatched (`sent`) request to `delivered`, which unlocks activation without needing Cardda staff. Authorized for the request's owner, a manager, or an admin (same as update). Behavior: - Only applies to requests that require a shipping address (physical **CLP** / PLH requests). Others return `422`. - **Idempotent**: if the request is already `delivered`, it is returned as-is with `200`. - If the request is not in `sent` status, returns `422`. No request body is required. - [List merchants](https://docs.cardda.com/reference/listmerchants.md): Returns a paginated list of merchants (normalized payees) linked to the company's transactions. Access requires an admin or one of the `transactions_rules_view` / `transactions_rules_manage` permissions. The result is scoped to the merchants referenced by the company's ledger transactions. Merchants are used to group and label card spend (e.g. resolving "AMZN MKTP US" to "Amazon") and to power transaction rules. All operators in [Filters](https://docs.cardda.com/docs/filters) are supported on the columns below. - [Retrieve one](https://docs.cardda.com/reference/showcardtransaction.md): Returns a single card transaction by id. Visible to admins, holders of the `card_transactions_manage` permission, or the cardholder the transaction belongs to. The response includes the transaction's `transaction_labels` and the computed fields `commission_id`, `type`, `amount_formatted`, and `target_amount_formatted`. The internal `embedding` vector is never exposed. **Multi-provider note.** Amounts are Cardda's own reconstruction across issuing partners (Slash, PLH, Pomelo, etc.): `amount_in_clp` is the CLP reconversion at settlement, and for some vendors the balance/decline context is derived from the vendor payload rather than a native field. Decline reasons surface in `status_reason`. - [Update one](https://docs.cardda.com/reference/updatecardtransaction.md): Updates a card transaction. For company users the **only** editable field is `comments` (the rendición note): if the request body does not include `comments` and the caller is not a Cardda superadmin, the request is rejected with `401`. The fields `merchant_id`, `issuing_statement_id`, `status`, and `exchange_rate` are **admin-only** and ignored for non-admin callers. The transaction's rendición custom-column values live on the transaction and are protected by two immutability gates; they are not editable through this endpoint. - [List card transactions](https://docs.cardda.com/reference/listcardtransactions.md): Returns a paginated list of card transactions — every authorization, capture, refund, fee, and adjustment that touched any of the company's vendor cards. The endpoint excludes the internal `StripeAuthorization` rows (those are partial pre-auths that get superseded by a final `CardTransaction`). The result is scoped per-caller across every company the caller has permission in (via `policy_scope`); the `company-id` header is **not** consulted, and omitting it still returns `200` with the caller's full permitted scope. To restrict results to one company, filter explicitly with the `company_id` query parameter. ## When you'll use this endpoint - Show the "transactions feed" in your dashboard. - Build per-user / per-card / per-merchant spend reports. - Audit pending vs. approved transactions ahead of month-end close. - Reconcile each row with its legacy `Invoice` (when set via `invoice_id`). Note: `invoice_id` points to the internal `Invoice` UUID — it is **not** a `FiscalInvoice` / SII DTE id. To match a transaction against a SII DTE you have to cross the merchant + amount + date against `GET /v1/fiscal_invoices`. ## Response structure Each row exposes: | Field | Description | | --- | --- | | `id` | Vendor-prefixed string (base64 encoded for some vendors). | | `vendor_card_id` | The `VendorCard.id` that incurred the transaction. | | `user_id` | Firebase user id of the cardholder. | | `company_id` | UUID of the company. | | `amount_cents` / `currency` | Transaction amount in the merchant's currency. | | `target_amount_cents` / `target_currency` | Settled amount in the company's accounting currency. | | `amount_in_clp` | Amount converted to CLP at settlement time (Chile-specific reporting). | | `amount_in_limit_currency` | Amount converted to the card's `limit_currency`. | | `exchange_rate` | FX rate applied at settlement. | | `status` | Lifecycle (see enum). | | `kind` | Transaction kind (`purchase`, `refund`, `fee`, `adjustment`, etc.). | | `merchant` (`merchant_name`, `cleaned_merchant_name`, `merchant_image_url`, `merchant_id`) | Merchant info. | | `description` | Free-form description from the vendor or the cardholder. | | `comments` | Internal notes (e.g. "client meeting Q1 review"). | | `transaction_labels` | Tags applied by the company. | | `invoice_id` | Legacy `Invoice` UUID (internal billing record kept for backwards compatibility). **Not** a `FiscalInvoice` / SII DTE id — fiscal invoices use the composite `--` format and are exposed via `GET /v1/fiscal_invoices`. | | `superseding_transaction_id` | When a pending transaction is replaced by the final one, the new id. | | `superseding_reason` | Why it was superseded. | | `completed_at` / `settled_at` / `created_at` | Lifecycle timestamps. | | `target_amount_formatted`, `amount_formatted` | UI-ready strings. | | `card` | Embedded vendor-card summary. | ## Common queries ```bash # Most recent transactions of a single card, excluding superseded rows GET /v1/card_transactions?\ vendor_card_id=Q2FyZDoxMDIwNjQ5Mw==&\ status={"$ne":"superseded"}&\ _order=desc&_field=created_at&_start=0&_end=25 # Approved transactions in the last 30 days, by status GET /v1/card_transactions?\ status=approved&\ created_at={"$gte":"2026-04-01T00:00:00Z"}&\ _order=desc&_field=created_at # Pending transactions of a specific user (declines and pre-auths) GET /v1/card_transactions?\ user_id=&\ status=pending # Search by merchant name (regex) GET /v1/card_transactions?\ merchant_name={"$regex":"AWS"} # By kind — purchases/refunds only, excluding fees GET /v1/card_transactions?\ kind={"$in":["purchase","refund"]} # USD-denominated transactions that haven't been linked to a legacy `Invoice` yet GET /v1/card_transactions?\ currency={"$ne":"CLP"}&\ invoice_id=null ``` All operators in [Filters](https://docs.cardda.com/docs/filters) are supported on the columns listed below. - [Payable](https://docs.cardda.com/reference/payable.md) - [List all](https://docs.cardda.com/reference/listpayables.md): Returns a list of payables the caller can access across their permitted companies. The deprecated `company_id` query parameter is still accepted and, when present, filters the results to those company id(s). The `company-id` header and the `company_id` query parameter are not compared against each other, so there is no mismatch error. - [Create one](https://docs.cardda.com/reference/createpayable.md): Creates a new payable. This endpoint skips user authentication (it can be used by unauthenticated flows). The company is identified by the `company_id` field in the request body; send the same company UUID in the required `company-id` header. - [Retrieve one](https://docs.cardda.com/reference/showpayable.md): Returns a bank accounts given it's id - [Update one](https://docs.cardda.com/reference/updatepayable.md): Updates a payable - [Update many](https://docs.cardda.com/reference/updatemanypayable.md): Updates many payable - [Create Bank Transaction for Payable](https://docs.cardda.com/reference/createpayabletransactions.md): Creates one or more bank transactions to pay a payable. This endpoint handles the creation of bank transfers from your company's bank account to a recipient's account, linking them to a specific payable. ## Important Notes - The payable id is passed as a URL parameter in `/v1/erp/payouts/payables/{id}/create_transactions` - Multiple transactions may be created if the amount exceeds bank limits - Transactions are automatically linked to the payable for tracking ## Prerequisites 1. **Bank Account (sender_id)**: Your company must have a bank account configured 2. **Bank Recipient (recipient_id)**: The recipient must be registered and approved 3. **Bank Key**: User must have authorization to operate the bank account 4. **Payable**: The payable must exist and not be overpaid ## Authorization Flow After creating transactions, they typically follow this status flow (may vary depending on bank): - `draft` → `enqueued` → `preauthorized` → `approved` `approved` is the terminal success state — there is no `authorized` or `completed` status. (`authorize` is the name of the *transition* that lands a transfer in `approved`.) A rejected transfer ends in `dequeued` or `declined`; a leg paid inside a payroll ends in `payroll_authorized`. Poll on `status`, not on `transition`. ## Example Workflow ``` 1. GET /v1/banking/bank_accounts to find your sender account 2. GET /v1/banking/bank_recipients to find or create recipient 3. POST /v1/erp/payouts/payables/{id}/create_transactions to create payment 4. Use banking authorization endpoints in /v1/banking/bank_accounts to approve the transaction ``` - [List payables for export](https://docs.cardda.com/reference/listpayablesforexport.md): Lean, export-oriented listing of payables. Returns only the fields the spreadsheet export consumes, folds each payable's comments inline, and can optionally include signed document URLs. Set `include_document_urls=true` to embed signed `urls` for each payable's user documents. When enabled the result set is capped at 500 rows; exceeding it returns `422` with error code `payables/export_document_urls_limit`. Accepts the same filter and pagination parameters as the standard payables list. - [List payables with their document URLs](https://docs.cardda.com/reference/listpayablesuserdocuments.md): Returns, for each payable matching the current filters, its id and the signed URLs of its user documents (valid for 7 days). Used to bulk-fetch attachment links for export. Returns `404` when no matching payables have documents. - [Verify a company for payment](https://docs.cardda.com/reference/verifycompany.md): Looks up a company by id and returns its public identity plus whether it requires a refund document. Used by the (unauthenticated) refund/payment flow to confirm the counterpart company before continuing. This endpoint skips user authentication and identifies the company via the `company_id` field in the request, not the `company-id` header. - [Emit a purchase invoice (factura de compra)](https://docs.cardda.com/reference/createbuyinvoice.md): Emits a purchase invoice to the SII (or via SimpleFactura, depending on the emitting user's approved integration key) for a source document identified by `source_id` / `source_type`. The source must belong to the current company and be in CLP or USD. Emission is routed by the emitting user's approved key: if a SimpleFactura key exists it is used, otherwise the user's SII signature key is used. Returns `200` on success (no body). - [List a payable's audit logs](https://docs.cardda.com/reference/listpayablelogs.md): Returns a paginated audit trail for the payable, including changes to the payable itself and its associated records (custom columns, rules, reviewers). Each entry embeds the changed `auditable` record and the acting `user`. - [Upload documents to a payable](https://docs.cardda.com/reference/uploadpayableuserdocument.md): Attaches one or more files as user documents on the payable. Send the files under the `files` key (single file or array) as `multipart/form-data`. Invalid attachments are rejected and purged, returning `422`. This endpoint skips user authentication so a provider (via the portal) can upload supporting documents; it is scoped by the payable id in the path, not by the company. - [Delete a payable document](https://docs.cardda.com/reference/deletepayableuserdocument.md): Removes a user document from the payable. The attachment blob is purged asynchronously. Returns `204 No Content` on success. - [Get a signed URL for a payable document](https://docs.cardda.com/reference/getpayableuserdocumenturl.md): Returns a short-lived signed URL for downloading a specific user document attached to the payable. The URL expires per the ActiveStorage service configuration. - [Delegate a payable to another company](https://docs.cardda.com/reference/delegatepayable.md): Delegates payment of the payable to another company where the user is an admin or owner. Splits the payable into the original, a net payable owned by the target company, and an optional reimbursement payable. - [Revert a payable delegation](https://docs.cardda.com/reference/revertpayabledelegation.md): Reverts a previously delegated payable, restoring the original payable and declining the payables created by the delegation. - [Refresh a payable's cession status](https://docs.cardda.com/reference/refreshpayablecession.md): Queries the SII (RPETC) synchronously to refresh the cession (factoring) status of a payable backed by a cedible received invoice, and returns the fresh cession block. If the live check fails, the last known data is preserved and returned with `stale: true` instead of erroring. - [Enable the provider chat for a payable](https://docs.cardda.com/reference/enablepayablechat.md): Manually starts the provider chat for the payable: ensures a portal access token exists for the business partner (creating it if needed, preserving the fixed portal URL), sends the invitation email with the access code, and enables the chat on the payable. - [Toggle the provider chat for a payable](https://docs.cardda.com/reference/togglepayablechat.md): Enables or disables the provider chat on the payable by setting its `active_chat` flag. - [Get a payable document](https://docs.cardda.com/reference/showpayableuserdocument.md): Returns a single user document attached to the payable, including its embedded blob metadata. - [Reviewer](https://docs.cardda.com/reference/reviewer.md) - [List all](https://docs.cardda.com/reference/listreviewers.md): Returns a list of reviewer - [Create one](https://docs.cardda.com/reference/createreviewer.md): Creates a new reviewer - [Delete a reviewer](https://docs.cardda.com/reference/destroyreviewer.md): Removes a reviewer assignment from its tradable (payable or purchase order). Accessible to company admins, owners, and users with the finance role. - [Review](https://docs.cardda.com/reference/review.md) - [List all](https://docs.cardda.com/reference/listreviews.md): Returns a list of review - [Create one](https://docs.cardda.com/reference/createreview.md): Creates a new review - [List purchase orders](https://docs.cardda.com/reference/listpurchaseorders.md): Returns a paginated list of purchase orders for the company. This endpoint provides comprehensive filtering, sorting, and pagination capabilities to help you query purchase order history effectively. ## Key Features - **Pagination**: Control result size with `_start` and `_end` parameters (default: 25 items) - **Sorting**: Sort by any field in ascending or descending order - **Filtering**: Apply complex filters on multiple fields including amounts, types, statuses, and dates - **Relationships**: Automatically includes related entities (business partners, items, payables) ## Authorization - Regular users can only view purchase orders from companies they are members of. - Admin users can view all purchase orders. ## Response Structure The response includes the purchase order details along with nested relationships: - **business_partner**: Complete vendor/supplier information - **items**: List of purchase order items with approval status and linked invoices - **payables**: Related fiscal invoices (when items are linked) - **type**: The specific purchase order type (AgainstInvoice, ByMilestone, or ByPercentage) ## Purchase Order Types 1. **AgainstInvoice**: Single invoice purchase order (exactly 1 item at 100%) 2. **ByMilestone**: Multiple named deliverables with percentages (e.g., Design 30%, Development 70%) 3. **ByPercentage**: Multiple payment stages with percentages (e.g., 30% advance, 70% final) ## Common Use Cases 1. **Get recent purchase orders**: Use default pagination without filters 2. **Find high-value orders**: Filter by amount range 3. **Check approval status**: Filter by item review status 4. **Audit trail**: Sort by `created_at` or `updated_at` with date filters 5. **Vendor reconciliation**: Filter by `business_partner_id` 6. **Budget tracking**: Filter by type and sum amounts - [Create purchase order](https://docs.cardda.com/reference/createpurchaseorder.md): Creates a new purchase order to track purchase commitments before invoices are received. This endpoint handles three types of purchase orders with comprehensive validation and automatic folio generation. ## Purchase Order Types ### 1. Against Invoice Single invoice purchase order with exactly one item at 100%. **Use case**: Simple purchases with a single invoice expected. **Example**: Purchasing office equipment for $10,000 CLP. ### 2. By Milestone Multiple named deliverables with individual percentages. **Use case**: Projects with defined stages and separate invoicing for each stage. **Example**: Software project with Design (30%), Development (50%), Testing (20%). ### 3. By Percentage Multiple payment stages with percentages (no names required). **Use case**: Service contracts with payment schedule. **Example**: Consulting service with 30% advance, 50% mid-project, 20% final payment. ## Prerequisites Before creating a purchase order, you need: 1. **Business Partner**: The vendor/supplier for this purchase - Must be pre-registered and approved - Find partners: `GET /v1/erp/payouts/business_partners` 2. **Company**: The company making the purchase - User must be a member with appropriate role - Required roles: admin, owner, or member ## Validation Rules ### General Rules (All Types) - **amount_cents**: Integer, `>= 0`, in the **minor unit of `currency`** — not always a hundredth. `CLP` → whole pesos (`10000` is $10.000). `USD` → cents (`99000` is US$990). `UF`/`CLF` → **ten-thousandths of a UF** (`400000` is 40 UF). See [Amounts and currency](https://docs.cardda.com/docs/amounts-and-currency). - **description**: Required field for purchase reference - **currency**: Must be exactly one of `CLP`, `UF`, `CLF`, `USD` — **case-sensitive**, so `clp` or `uf` is rejected. `UF` is normalized to its ISO code `CLF` on save, which is what reads back. - **items**: Must have at least one item - **percentages**: Item percentages must sum to exactly 100% ### Type-Specific Rules **AgainstInvoice:** - Must have exactly 1 item - Item percentage must be 100% - Item name is optional (not required) **ByMilestone:** - Must have at least 1 item - Each item must have a name - Item percentages must sum to 100% **ByPercentage:** - Must have at least 2 items - Item names are optional (not required) - Item percentages must sum to 100% ## Automatic Features ### Folio Generation System automatically generates a `folio`: a per-company sequential **integer** (1, 2, 3, ...), unique within the company. It is not a formatted string. ### Item Amount Calculation System automatically calculates item amounts based on percentages: - Formula: `item.amount_cents = (total_amount_cents × percentage / 100).round` - Automatically recalculated when total amount changes ### Creator Tracking System automatically assigns current authenticated user as creator (`user_id`). ## Workflow 1. Purchase order is created with status `draft` 2. Admin/creator assigns reviewers to items (if approval required) 3. Reviewers approve or reject items independently 4. When fiscal invoice arrives, it's linked to approved items 5. Linked items can be paid via bank transactions 6. When all items are paid, purchase order is considered complete ## Important Notes - Regular users can only create purchase orders for companies they are members of - All amounts are integers in the minor unit of the order's `currency`: whole pesos for CLP, cents for USD, ten-thousandths for UF/CLF. See [Amounts and currency](https://docs.cardda.com/docs/amounts-and-currency) - Item amounts are automatically calculated from percentages - Full audit trail is maintained for all changes - [Get purchase order details](https://docs.cardda.com/reference/showpurchaseorder.md): Returns detailed information about a specific purchase order including all items, linked invoices, and business partner information. ## Response Structure The response includes complete purchase order details with: - **business_partner**: Full vendor/supplier information - **items**: All purchase order items with approval status - **payables**: All fiscal invoices linked to any item in this purchase order ## Authorization - User must be a member of the company that owns the purchase order - [Update purchase order](https://docs.cardda.com/reference/updatepurchaseorder.md): Updates an existing purchase order's description, amount, currency, or items. When the total amount changes, item amounts are automatically recalculated based on their percentages. ## Important Notes - Purchase order must not be approved or completed - User must have admin or owner role - Item percentages must sum to 100% after update - When amount_cents changes, all item amounts are recalculated - Items can be created, updated, or deleted using nested attributes ## Authorization - User must be admin or owner of the company - Purchase order cannot be approved or completed ## Nested Item Updates You can create, update, or delete items in the same request: - **Create**: Include item without `id` field - **Update**: Include item with existing `id` field - **Delete**: Include item with `id` and `_destroy: true` - [Delete purchase order (not currently operational)](https://docs.cardda.com/reference/destroypurchaseorder.md): **Not currently operational.** Once the caller is authorized, this endpoint attempts a soft-delete that the application cannot perform: the purchase order does not support discarding (there is no `discarded_at` column and no discard behaviour on the model), so the delete raises server-side and returns **500 Internal Server Error**. There is no soft-delete or restore capability for purchase orders. Do not rely on this endpoint until it is fixed. ## Authorization - Authorization is checked first (Pundit); an unauthorized caller gets a 401 with an empty body before the 500 path is reached. - [List a purchase order's audit logs](https://docs.cardda.com/reference/listpurchaseorderlogs.md): Returns a paginated audit trail for the purchase order, including changes to the order and its associated records. Each entry embeds the changed `auditable` record and the acting `user`. - [Download a purchase order PDF](https://docs.cardda.com/reference/getpurchaseorderpdf.md): Generates and returns the purchase order as a PDF attachment. Only approved purchase orders can be downloaded; otherwise a `422` is returned. - [List purchase order items](https://docs.cardda.com/reference/listpurchaseorderitems.md): Returns a list of items for a specific purchase order. Each item represents a portion of the total purchase amount and can be independently approved and linked to invoices. ## Key Features - **Item Details**: Full information about each item including name, percentage, and calculated amount - **Approval Status**: Current review status and approval history - **Invoice Linking**: Shows which items are linked to fiscal invoices - **Reviewer Information**: Lists assigned reviewers and their approval levels ## Authorization - User must be a member of the company that owns the purchase order ## Response Structure The response includes detailed item information along with: - **payable**: Linked fiscal invoice details (if item is linked to an invoice) - **reviewers**: List of users assigned to review this item - **reviews**: Complete approval/rejection history for the item ## Common Use Cases 1. **Check approval status**: View which items are pending, approved, or rejected 2. **Track invoice linking**: See which items have been linked to received invoices 3. **Monitor review progress**: Check which reviewers have approved each item 4. **Audit trail**: Review complete history of approvals and rejections - [Update purchase order item](https://docs.cardda.com/reference/updatepurchaseorderitem.md): Updates a purchase order item's name, number, or percentage. The item amount is automatically recalculated when the percentage changes. ## Important Notes - Changing the percentage will trigger automatic recalculation of the item amount - The total of all item percentages must still sum to 100% after the update - Items can only be updated if the purchase order is not in completed status - For ByMilestone type purchase orders, the name field is required - The number must remain unique within the purchase order ## Authorization - User must be a member of the company that owns the purchase order - User must have appropriate permissions (admin, owner, or member) ## Use Cases 1. **Adjust percentages**: Rebalance payment stages 2. **Update item names**: Clarify milestone descriptions 3. **Reorder items**: Change item numbers - [List business partners](https://docs.cardda.com/reference/listbusinesspartners.md): Returns a paginated list of the company's business partners (vendors/suppliers). Each entry embeds its underlying `partner` (Person) and `company`. Requires the `erp_business_partners_view` or `erp_business_partners_manage` permission (company admins always have access). - [Create a business partner](https://docs.cardda.com/reference/createbusinesspartner.md): Creates a business partner for the company. Provide either an existing `partner_id` or a nested `partner` object with an `identifier`; when the identifier does not yet match an existing Person, a new Person is created and linked. Requires the `erp_business_partners_manage` permission (or company admin). - [Associate recipients to business partners](https://docs.cardda.com/reference/associatebusinesspartnerrecipients.md): Enqueues a background job that links the company's existing bank recipients to their matching business partners. Returns immediately; the association happens asynchronously. Requires the `erp_business_partners_manage` permission (or company admin). - [Replicate business partners to other companies](https://docs.cardda.com/reference/replicatebusinesspartners.md): Copies the given business partners (with their bank accounts and partner records) into one or more target companies within the same corporate group. The caller must be authorized on every company involved (source and targets). Requires the `erp_business_partners_manage` permission on the involved companies. - [Get a business partner](https://docs.cardda.com/reference/showbusinesspartner.md): Returns a single business partner including its `partner`, `company`, and `business_partner_bank_accounts` (each embedding its `bank_account`, `bank_recipients`, and `bank_recipient_ids`). Requires the `erp_business_partners_view` or `erp_business_partners_manage` permission (or company admin). - [Update a business partner](https://docs.cardda.com/reference/updatebusinesspartner.md): Updates a business partner's attributes, its nested `partner`, and/or its bank accounts. Requires the `erp_business_partners_manage` permission (or company admin). - [List business partner activity](https://docs.cardda.com/reference/listbusinesspartneractivity.md): Returns a paginated, chronological activity feed for the business partner: the union of its payables and the bank transactions that pay them. Each entry carries the source record `type` and its current `status`. Requires the `erp_business_partners_view` or `erp_business_partners_manage` permission (or company admin). - [Get portal link status](https://docs.cardda.com/reference/getbusinesspartnerportallinkstatus.md): Returns whether a provider-portal access token currently exists for the business partner, together with the stable portal URL. Used by the frontend to choose between the "create link" flow and the regular chat interface. Requires the `erp_business_partners_view` or `erp_business_partners_manage` permission (or company admin). - [Get business partner summary](https://docs.cardda.com/reference/getbusinesspartnersummary.md): Returns aggregate counters and amounts for the business partner (number of payables and bank transactions, and paid / due / overdue totals). Requires the `erp_business_partners_view` or `erp_business_partners_manage` permission (or company admin). - [List credit notes](https://docs.cardda.com/reference/listcreditnotes.md): Returns a paginated list of the company's credit notes (notas de crédito). Each entry embeds its `counterpart_company`, `business_partner`, `linked_tradable`, and `source`. The internal `embedding` vector is always omitted. - [List debit notes](https://docs.cardda.com/reference/listdebitnotes.md): Returns a paginated list of the company's debit notes (notas de débito). The listing scopes to records whose document type is a debit-note type and whose STI class is `Erp::Payouts::DebitNote` or `Erp::Payouts::Payable`. Each entry embeds its `counterpart_company`, `business_partner`, `linked_tradable`, `source`, and its `type`. The internal `embedding` vector is always omitted. - [Convert a debit note into a payable](https://docs.cardda.com/reference/debitnotebecomepayable.md): Converts a debit note into a payable so it can be paid. Fails if the record is already a payable. Requires the `erp_business_partners`-style debit-note access (company member or admin). - [List imprest funds](https://docs.cardda.com/reference/listimprestfunds.md): Returns a paginated list of the company's imprest funds (fondos por rendir). Each entry embeds its assigned `user` and the computed `paid_amount`, `reported_amount`, and `custom_column_values`. - [Create an imprest fund](https://docs.cardda.com/reference/createimprestfund.md): Creates an imprest fund assigned to `user_id` (who must be a member of the company). An initial company-refund payable is created alongside it; supply `initial_amount` and an optional `bank_account` to fund the assignee's reimbursement. Requires the `erp_imprest_funds_create` permission (or company admin). - [Get an imprest fund](https://docs.cardda.com/reference/showimprestfund.md): Returns a single imprest fund including its assigned `user` and its `creator`. Accessible to company admins, holders of the `erp_imprest_funds_manage` permission, and the fund's own assignee. - [List payable comments](https://docs.cardda.com/reference/listpayablecomments.md): Returns a paginated list of payable comments the user has access to, newest first. Filter by `payable_id` to fetch a single payable's chat thread. - [Create a payable comment](https://docs.cardda.com/reference/createpayablecomment.md): Posts a comment to a payable's provider chat thread. The payable must have a business partner, and that partner must already have a portal link. The first comment on a payable auto-enables its chat. - [Link a bank transaction to a payable](https://docs.cardda.com/reference/createpayabletransaction.md): Creates a payable transaction that links an existing bank transaction to a payable for the given amount. This records that a specific bank transfer pays (part of) a payable; it does not itself move money. - [List rules](https://docs.cardda.com/reference/listrules.md): Returns a paginated list of the company's automation rules, each embedding its `attribute_change_effects`, `custom_column_change_effects`, and `reviewer_assigner_effects`. Override rules are excluded. Rules are partitioned by `applicable_model` (defaults to `tradables`). Filter by `kind` (`approval` rules have reviewer effects; `categorization` rules do not), `business_partner_id`, `inheritable`, and `applicable_model`. - [Create a rule](https://docs.cardda.com/reference/createrule.md): Creates an automation rule with its constraints and effects. `applicable_model` is set once here and is immutable afterwards. - [List inherited rules](https://docs.cardda.com/reference/listinheritedrules.md): Returns the paginated corporate-group (inherited) rules visible to the current company, each augmented with its `translated_constraints`, `related_partners`, and the current company's `override` (if any). Filter by `kind` and `applicable_model`. - [Get a rule](https://docs.cardda.com/reference/showrule.md): Returns a single rule with its effects and its `related_partners` (business partners referenced by the rule's constraints). - [Update a rule](https://docs.cardda.com/reference/updaterule.md): Updates a rule's attributes, constraints, and effects. `applicable_model` is ignored on update (immutable after creation). - [Delete a rule](https://docs.cardda.com/reference/destroyrule.md): Deletes a rule. - [Override an inherited rule](https://docs.cardda.com/reference/overriderule.md): Creates or updates the current company's override of an inherited (corporate-group) rule identified by `{id}`. Returns the inherited rule with its updated `override` block. Pass `inherit_override` to control whether the override itself propagates to child companies. Include the standard rule fields (`name`, `enabled`, effects, `constraints`) to define the overriding behavior. - [Fetch and store a tradable receipt from the SII](https://docs.cardda.com/reference/getpdftradable.md): Downloads the receipt/PDF for a tradable from the SII and stores it on the record, then returns the tradable. The target tradable is selected by the `id` query parameter (this is a collection route). Accessible to company admins and members of the tradable's company. - [Download a tradable receipt](https://docs.cardda.com/reference/gettradablereceipt.md): Downloads the receipt file attached to a tradable (payable/receivable) as an attachment. Returns a JSON message if the tradable has no receipt attached. Accessible to company admins and members of the tradable's company. - [Download a tradable PDF](https://docs.cardda.com/reference/gettradablepdf.md): Downloads the PDF attached to a tradable (payable/receivable) as an attachment. Returns a JSON message if the tradable has no PDF attached. Accessible to company admins and members of the tradable's company. - [List fiscal invoices](https://docs.cardda.com/reference/listfiscalinvoices.md): Returns a paginated list of fiscal invoices (DTEs — Documentos Tributarios Electrónicos) the company has issued or received in Chile via the SII. Cardda mirrors the company's SII inbox/outbox locally, so this endpoint serves as the integrator-facing source of truth for VAT recovery, accounts payable / receivable reconciliation, and month-end reporting. The data is updated automatically from the SII; you should treat it as read-mostly. ## Scoping The `company-id` header gates access (you must be a member of the company it references, otherwise `401`), **but it does not narrow the result set**. Results span the fiscal invoices of **every** company the caller is a member of. To restrict the list to a single company, pass an explicit `company_id` filter (query parameter) — see below. ## When you'll use this endpoint - Build accounts-payable dashboards (filter `issue_type=received`). - Build accounts-receivable dashboards (filter `issue_type=issued`). - Sync to your accounting/ERP — pull every invoice updated since the last sync watermark. - Find pending payments (`payment_status=non_paid` plus an `expiration_date` filter). ## Identifier format Fiscal-invoice ids are **strings**, not UUIDs, and follow the composite pattern `id = "#{issuer_id}-#{document_type}-#{number}"`, where `issuer_id` is the issuer's RUT and **already contains its own hyphen** before the verifier digit (e.g. `76123456-7`). The full id therefore looks like `76123456-7-33-1234` — split it as `(issuer_id="76123456-7", document_type="33", number="1234")`, **not** as four `-`-separated tokens. This is the value to store and the value to pass to `GET /v1/fiscal_invoices/{fiscal_invoice_id}`. Unique lookups should combine `issuer_id`, `document_type`, and `number`. > Heads-up: the `invoice_id` field on a card transaction is **not** a > fiscal-invoice id. It is a UUID pointing to a separate, legacy `Invoice` > model kept for backwards compatibility, and is unrelated to SII DTEs. ## Document types Chilean SII codes used in `document_type`: | Code | Name | Notes | | ---- | ---- | ----- | | 33 | Factura electrónica | Standard sales invoice (afecta IVA). | | 34 | Factura exenta electrónica | Exempt invoice. | | 39 | Boleta electrónica | Receipt-style document, retail. | | 41 | Boleta exenta electrónica | Receipt, exempt. | | 43 | Liquidación-factura | Settlement invoice for consignment. | | 46 | Factura de compra electrónica | Buy-invoice (tax-withheld imports). | | 52 | Guía de despacho | Shipment doc (DTE, but not a tax doc). | | 56 | Nota de débito electrónica | Increases the value of a referenced invoice. | | 61 | Nota de crédito electrónica | Decreases / reverses a referenced invoice. | | 110 | Factura de exportación electrónica | Export invoice. | | 111 | Nota de débito de exportación | Export debit note. | | 112 | Nota de crédito de exportación | Export credit note. | ## Common queries ```bash # Most-used pattern (real production traffic): incremental sync of credit notes. # Walk one 100-row page at a time — _end - _start is capped at 2 000 server-side # (anything larger returns 416). See https://docs.cardda.com/docs/pagination for the iteration recipe. GET /v1/fiscal_invoices?\ _start=0&_end=100&\ _order=ASC&_field=updated_at&\ updated_at={"$gt":"2026-05-03T00:00:00.000Z"}&\ document_type=61 # All invoices ever received from a single supplier GET /v1/fiscal_invoices?\ issuer_id=76123456-7&issue_type=received # Unpaid invoices (account payable backlog) GET /v1/fiscal_invoices?\ issue_type=received&payment_status=non_paid # All invoices by document type group (debit + credit notes) GET /v1/fiscal_invoices?document_type={"$in":[56,61]} # Last 7 days of issued invoices, sorted newest-first GET /v1/fiscal_invoices?\ issue_type=issued&\ created_at={"$gte":"2026-04-22T00:00:00Z"}&\ _order=DESC&_field=created_at ``` ## Timezone gotcha The Chilean SII timestamps are in **Chile local time** (UTC−3 / UTC−4 depending on DST). When you filter by `created_at`, `updated_at`, `issue_date`, `reception_date`, etc., **the server treats values as UTC**. To filter "since 2026-01-01 00:00 Chile time", convert: `2026-01-01T03:00:00Z`. Plan accordingly during DST transitions. - [Get one](https://docs.cardda.com/reference/getfiscalinvoice.md): Returns a single fiscal invoice (DTE) by its composite id. The response includes the inline `issuer` and `receiver` projections (`id`, `name`, `identifier`), the derived `tradable` and `due_date`, and the SII event fields (`sii_event_state`, `sii_event_status`). See the id format notes on `GET /v1/fiscal_invoices` — the id looks like `76123456-7-33-1234` and is a string, not a UUID. - [Accept a received invoice (SII event)](https://docs.cardda.com/reference/acceptfiscalinvoicesiievent.md): Registers an **acceptance** event for a received invoice with the SII (Registro de Aceptación/Reclamo). Cardda submits the event synchronously using the company's own approved SII credential, then persists the outcome on the fiscal invoice. ## Action codes `action_code` is optional; when omitted it defaults to `ACD`. If provided, it must be one of the accept codes: | Code | Meaning | | ---- | ------- | | `ACD` | Aceptación del contenido del documento. | | `ERM` | Otorga recibo de mercaderías o servicios. | | `ERG` | Recibo de mercaderías / servicios (variante). | ## Idempotency The event is reserved under a row lock: the invoice moves to `sii_event_state: submitting`, then `submitted` on success. A second call while an event is already in flight or recorded returns `409`. Requires the `erp_tradables_manage` permission on the invoice's own company (checked against the invoice, not the `company-id` header). - [Reject a received invoice (SII event)](https://docs.cardda.com/reference/rejectfiscalinvoicesiievent.md): Registers a **rejection** event for a received invoice with the SII (Registro de Aceptación/Reclamo). Cardda submits the event synchronously using the company's own approved SII credential, then persists the outcome on the fiscal invoice. ## Action codes `action_code` is optional; when omitted it defaults to `RCD`. If provided, it must be one of the reject codes: | Code | Meaning | | ---- | ------- | | `RCD` | Reclamo al contenido del documento. | | `RFP` | Reclamo por falta parcial de mercaderías. | | `RFT` | Reclamo por falta total de mercaderías. | ## Idempotency The event is reserved under a row lock: the invoice moves to `sii_event_state: submitting`, then `submitted` on success. A second call while an event is already in flight or recorded returns `409`. Requires the `erp_tradables_manage` permission on the invoice's own company (checked against the invoice, not the `company-id` header). - [List SII keys](https://docs.cardda.com/reference/listsiikeys.md): Returns a paginated list of **SII keys** — the digital-certificate credentials Cardda holds on behalf of a company to operate against Chile's Servicio de Impuestos Internos (SII). An SII key is what lets Cardda authenticate to the SII to **sync** the company's issued/received electronic documents (DTEs), pull PDFs, and submit acceptance/rejection events. A key becomes usable once its `status` is `approved`; it can additionally **issue** documents once a certificate password is present (`can_issue?`). ## Response structure Sensitive fields (`password`, `certificate_password`) are **never** exposed by this endpoint — they are stripped from every serialization. Each item adds two computed fields: | Field | Description | | ----- | ----------- | | `can_issue?` | `true` when `status` is `approved` and a certificate password is stored. Serialized literally with the trailing `?`. | | `company_ids` | UUIDs of the companies the key manages. | ## Scoping Results are scoped to the keys the caller can see: keys the caller owns (`user_id` == caller) plus keys whose managed companies grant the caller the `sii_keys_view` or `sii_keys_manage` permission. - [Create an SII key](https://docs.cardda.com/reference/createsiikey.md): Stores a new SII credential for the caller. Cardda encrypts `password` and `certificate_password` at rest; this is the only entry point that accepts them in clear text. On creation Cardda runs a synchronous company sync against the SII — on success the key flips to `approved` and its managed companies are resolved; if the SII rejects the credentials the key ends up `declined`. Company users must set `user_id` to their own Firebase uid, otherwise the request is rejected with `401`. - [Retrieve one](https://docs.cardda.com/reference/showsiikey.md): Returns a single SII key by id. Sensitive credential fields (`password`, `certificate_password`) are stripped; the response includes the computed `can_issue?` and `company_ids` fields. - [Update one](https://docs.cardda.com/reference/updatesiikey.md): Rotates the credentials of an SII key. All fields are optional; send only what changes. When the update touches a key that is not already `approved`, Cardda re-runs the company sync asynchronously afterwards. The response omits `company_ids` (it includes `can_issue?`). - [Delete one](https://docs.cardda.com/reference/deletesiikey.md): Deletes an SII key and its manager associations. Returns the id of the removed key. - [Sync invoices for a period](https://docs.cardda.com/reference/syncsiikeyinvoices.md): Triggers a synchronous sync of the company's electronic documents (DTEs) from the SII for the tax periods in `[from, to]` (both `YYYY-MM`, inclusive). The call authenticates with this key, walks each month in the range, and upserts the resulting fiscal invoices. The range is validated server-side: `from` and `to` must both match `YYYY-MM`, `from` must be ≤ `to`, and the span must not exceed **24 months** — otherwise the request fails with `422` (`sii/invalid-range`). Because CxP payables ingestion relies on the company's own certificate, this is how you backfill or refresh a company's SII inbox/outbox on demand. The call is synchronous and can take a while for wide ranges. - [List companies](https://docs.cardda.com/reference/listcompanies.md): Returns the paginated list of companies the authenticated user belongs to (for Cardda staff, all companies). This is the **non-company-scoped** discovery endpoint — it does **not** require the `company-id` header, because it is exactly how a client discovers which companies (and therefore which `company-id` values) it may operate on. Each item is augmented with the computed counters `n_users`, `n_cards`, `n_virtual_cards` and `owner_id`. The financial `balance` method is added only for Cardda staff. Supports the standard list query parameters (`_start`, `_end`, `_order`, `_field`) plus MongoDB-style filters passed as query params (e.g. `identifier`, `name`, `verification_status`), where each value may be a plain value or a JSON operator object such as `{"$in":["..."]}`. - [Retrieve a company](https://docs.cardda.com/reference/showcompany.md): Returns a single company by id, including its members, related people, custom columns and collector account. The company must be one the authenticated user belongs to (Cardda staff can read any). The `balance_cents` and `wallets` attributes (and the computed `balance` / `total_allocated_funds`) are returned only to users with the balance permission; other members receive the company without them. User attachment URLs are included only for users allowed to view them (admins or `companies_manage`). - [Update a company](https://docs.cardda.com/reference/updatecompany.md): Updates a company. The set of writable attributes depends on the caller's role and the company's `verification_status`: - Company owners/admins can update `name`, `address`, `interests`, referral fields, and (while KYC is `pending`/`rejected`/unset) the KYC document and profile fields (`fantasy_name`, `commercial_business`, `contact_phone`, `contact_email`, `commercial_type`, `constitution_date`, `legal_address`, `economic_activities`, and the KYC file fields). - Once `verification_status` is `approved`, only the signed-contract flags (`plh_contract_file_signed`, `plh_kyc_file_signed`, `plh_alliance_file_signed`) remain writable by company users. - Members can also submit nested `company_memberships` updates (role, legal representative, powers, partner, participation rate). - A large set of commercial/financial attributes is writable **only by Cardda staff** and is intentionally omitted here. Non-privileged callers receive an empty permitted set (no-op update). - [Get a company file URL](https://docs.cardda.com/reference/getcompanyfile.md): Returns a short-lived presigned URL for a file stored in Active Storage for the company (e.g. a KYC document). The attachment is selected by the **required** `file_name` query parameter, which must be one of the company's allowed attachment keys. The allowed set depends on the company's country: for Chile (and other non-MX countries) `tax_folder`, `incorporation_document`, `registration_certificate`, `power_structure`, `rut_certificate`, `plh_contract_file`, `plh_kyc_file`, `plh_alliance_file`, `plh_contract_file_signed`, `plh_kyc_file_signed`, `plh_alliance_file_signed`; for Mexico (`MX`) `incorporation_document`, `address_file`, `cif_file`, `majority_ownership_incorporation_file`. - [Get KYC auto-review result](https://docs.cardda.com/reference/getcompanykycautoreview.md): Returns the stored automatic KYC review result for the company — the list of per-check `reviews` produced by the auto-approval service on the last run. Returns an empty `reviews` array if the company has never been auto-reviewed. - [Check KYC prerequisites](https://docs.cardda.com/reference/getcompanykycprerequisites.md): Evaluates whether the company meets the prerequisites required before its KYC can be sent to review. Returns `all_passed` and, when it is `false`, the list of `missing` issues (each serialized as a hash describing the failing prerequisite). - [Get PLH signing status](https://docs.cardda.com/reference/getcompanyplhsigningstatus.md): Returns the ZapSign signing status for the three PLH-related document flows — `kyc`, `uaf` and `alliance`. For each flow the response exposes `status`, `sign_url`, `sent_at` and `signed_at` (any of which may be null before the document is generated/sent). - [Generate PLH contracts](https://docs.cardda.com/reference/generatecompanyplhcontracts.md): Generates the PLH contract documents for the company and emails them for signing. Requires the company to have `plh_enabled` true and its KYC `verification_status` to be `approved`; otherwise a `400` with an `error_code` is returned. - [Get reimbursement usage](https://docs.cardda.com/reference/getcompanyreimbursementusage.md): Returns the company's Reembolsos (reimbursements) usage for the current period — the same `ReimbursementUsage` query object used by Sofia and the WhatsApp bot, so the counter is identical across channels. Powers the in-app "X of 15 free this month" view and the freemium/Pro upgrade banners. The exact fields depend on whether the company is on the free quota, grandfathered, or subscribed to Pro; common fields are shown below. - [Spending by merchant](https://docs.cardda.com/reference/getcompanyspendingpermerchant.md): Returns the company's spending aggregated by merchant for a given product over the requested month range. The `product` query param selects the source: `cards`, `transfers` or `pay`. An unrecognized `product` yields an empty array. Amounts are integers in the record's currency (currency codes are returned upper-cased). - [Spending summary by period](https://docs.cardda.com/reference/getcompanyspendingsummary.md): Returns the company's spending aggregated by time period for a given product. Granularity is `day` when `start_month` equals `end_month`, otherwise `month`. The `product` query param selects the source: `cards`, `transfers` or `pay`. An unrecognized `product` yields an empty array. Amounts are integers in the record's currency (currency codes are returned upper-cased). - [Send KYC to review](https://docs.cardda.com/reference/sendcompanykyctoreview.md): Transitions the company's KYC into the `awaiting_review` state and enqueues the auto-approval job. Only allowed when the current `verification_status` is `pending` or `rejected`, and only when all KYC prerequisites pass (otherwise a `422` lists the `missing` prerequisites). - [List company roles](https://docs.cardda.com/reference/listcompanyroles.md): Returns the custom roles defined for the company, each with its permissions (only `id` and `name` per permission). Supports the standard list query parameters. - [Create a company role](https://docs.cardda.com/reference/createcompanyrole.md): Creates a new custom role for the company with an optional set of permissions (passed as an array of permission ids). - [Update a company role](https://docs.cardda.com/reference/updatecompanyrole.md): Updates a company role's `name`/`description` and, when a `permissions` array is supplied, replaces the role's permission set. If any supplied permission id does not exist a `404` is returned. - [Retrieve a company role](https://docs.cardda.com/reference/showcompanyrole.md): Returns a single company role belonging to the company, including its permissions (only `id` and `name` per permission). - [Delete a company role](https://docs.cardda.com/reference/deletecompanyrole.md): Deletes a custom company role. A role that is still assigned to one or more memberships cannot be deleted and returns `422`. - [Get company settings](https://docs.cardda.com/reference/showcompanysettings.md): Returns the settings record for the current company (resolved from the `company-id` header / policy scope). Covers the refund-document requirement, the review-reminder cadence and external notification preferences. - [Update company settings](https://docs.cardda.com/reference/updatecompanysettings.md): Updates the self-service company settings. Only `requires_refund_document`, `review_reminder_cadence` and `external_notification_preferences` are writable — the review-reminder age guardrails (`review_reminder_max_age_days` / `review_reminder_min_age_days`) are server-side and cannot be changed here. - [List company memberships](https://docs.cardda.com/reference/listcompanymemberships.md): Returns the memberships of a company (users and pending email invitations), each including its permissions (`id` and `name` only). The company is resolved from the `company_id` request parameter; the caller only sees memberships of companies where they hold the `members_management` permission (Cardda staff see all). - [Create a company membership (invite)](https://docs.cardda.com/reference/createcompanymembership.md): Creates a membership for a company, generating an invitation token and sending the invitation email. When the invitee already exists they are linked; otherwise a pending invitation (no `user_id`) is created for the email. - [Update a company membership](https://docs.cardda.com/reference/updatecompanymembership.md): Updates a membership's KYC attributes (`legal_representative`, `has_powers_to_act`, `partner`, `partner_type`, `participation_rate`, `is_indirect_participation_corporate`). While the company's `verification_status` is `pending`/`rejected`, the KYC file fields (`identification_file`, `power_file`, `pep_file`, `pep_file_template`) are also writable. `role` is writable only by callers holding the `members_management` permission. - [Remove a company membership](https://docs.cardda.com/reference/deletecompanymembership.md): Removes a member from the company by marking the membership `canceled`. Any of the member's `pending` cards for that company are unassigned. The request fails with `422` if the member still has active or inactive (non-canceled, non-pending) cards — those must be canceled first. - [Check an invitation](https://docs.cardda.com/reference/checkcompanymembershipinvitation.md): Looks up a pending invitation by its `invitation_token` and returns the invitee email, the inviting company (name/country), a resolved `user_id` if the email already has an account, and the list of all companies covered by that token (bulk invitations share one token). **No authentication required** — this endpoint is reachable before the invitee has logged in, so it declares `security: []`. It is not scoped to a company. - [Get notification preferences](https://docs.cardda.com/reference/getmembershipnotificationpreferences.md): Returns the notification preferences for the authenticated user's membership in the current company (resolved from the `company-id` header). If the user has no membership in that company a `404` is returned. - [Update notification preferences](https://docs.cardda.com/reference/updatemembershipnotificationpreferences.md): Updates the authenticated user's notification preferences for their membership in the current company. The `preferences` object maps each known notification type to a channel map. Valid channels are `in_app` and `email`; valid modes are `immediate`, `daily`, `weekly`, `disabled`. Unknown types, channels or modes return `422`. - [Get a membership file URL](https://docs.cardda.com/reference/getmembershipfile.md): Returns a short-lived presigned URL for a file stored in Active Storage for the membership (e.g. an identification or powers document). The attachment is selected by the **required** `file_name` query parameter, which must be one of the membership's allowed attachment keys: `identification_file`, `power_file`, `pep_file`, `pep_file_template`. - [Bulk-invite a member across companies](https://docs.cardda.com/reference/createmanycompanymemberships.md): Invites the same email (with one role) to multiple companies at once, sharing a single invitation token. All target companies must be authorized for the caller and must define the requested role; assigning the `owner` role requires the caller to be an owner of each company. A maximum of 50 companies per request is enforced. Conflicts (email already a member somewhere) return `422` with the offending company ids. - [Accept an invitation (existing user)](https://docs.cardda.com/reference/useracceptcompanymembershipinvitation.md): Accepts all pending invitations bound to the given `invitation_token` for the already-authenticated user, activating the memberships (sets the user, clears the token, marks them `active`). Use this when the invitee already has a Cardda account and is logged in. - [Resend an invitation](https://docs.cardda.com/reference/resendcompanymembershipinvitation.md): Resends the invitation email for a pending membership. Rate-limited by a 5-minute cool-down (returns `400` with `reason: cool_down` if invoked again too soon), and only valid while the membership is still `pending` (otherwise `400` with `reason: user_already_accepted`). If the invitation token covers several companies, the bulk invitation email is resent. - [List users](https://docs.cardda.com/reference/listusers.md): Returns the list of users visible to the caller. For a normal user this is scoped to **their own account only**; Cardda staff see all users. Each item is augmented with computed methods (`milestone_ids`, `n_companies`, `company_role`, capability flags, `plh_profile_complete`, `missing_plh_profile_fields`, `needs_password_setup`). This endpoint is **not company-scoped** — visibility comes from the user policy, not the `company-id` header. - [Create a user](https://docs.cardda.com/reference/createuser.md): Creates the authenticated Firebase user's Cardda account. The identity (id and email) is taken from the verified Firebase ID token — **not** from the body. This endpoint authenticates via a Firebase ID token (the normal bearer session is skipped); the token is supplied in the `Authorization` header. Optional `pomelo_user` details provision a Pomelo (Mexico) card user; if that provisioning fails a `400` is returned. - [Retrieve a user](https://docs.cardda.com/reference/showuser.md): Returns a single user by id (the Firebase UID). A normal user can only fetch their own record; Cardda staff can fetch any. Includes the user's memberships and computed profile methods. This endpoint is **not company-scoped** (it is on the `company-id` header whitelist). - [Update a user](https://docs.cardda.com/reference/updateuser.md): Updates the user's profile. `user_type` and `identifier` cannot be changed once set (unless by staff). `email` is writable only by the owner of the record; a range of financial/role attributes is writable only by Cardda staff. An optional nested `company` object can create or update the user's owned company. Not company-scoped (self-service, on the whitelist). - [Delete a user](https://docs.cardda.com/reference/deleteuser.md): Deletes the user record. Not company-scoped (on the whitelist). - [Get a user file URL](https://docs.cardda.com/reference/getuserfile.md): Returns a short-lived presigned URL for a file stored in Active Storage for the user (e.g. their identification document). Access is gated by the user file policy (the user themselves, or admins / `companies_manage`). The specific attachment is selected by the `attachment` query parameter. - [Create an owned company for a user](https://docs.cardda.com/reference/createuserownedcompany.md): Creates (or claims by identifier) a company and makes the user its `owner`. If a company with the given identifier already has memberships, the request fails with `422` (identifier already taken). - [Send an email verification link](https://docs.cardda.com/reference/senduserverificationemail.md): Generates a Firebase email-verification link for the user and emails it. Rate-limited to 1 request per minute. Returns `{ success: true }` on success, or `422` if the verification link could not be generated. - [Send a password reset email](https://docs.cardda.com/reference/sendpasswordresetemail.md): Sends a Firebase password-reset link to the given email. **No authentication required** (`security: []`) — it is called from the public "forgot password" flow. It is not company-scoped. To avoid account enumeration the endpoint always responds `{ success: true }` when the email is unknown or when Firebase rejects it. Rate-limited to 1 request per minute. - [Get user settings](https://docs.cardda.com/reference/showusersettings.md): Returns the authenticated user's settings (notification toggles and low-balance alert threshold). The raw `low_balance_threshold_cents` is not returned; the amount is exposed via `low_balance_threshold_amount`. This is a **per-user** resource and is not company-scoped. - [Update user settings](https://docs.cardda.com/reference/updateusersettings.md): Updates the authenticated user's notification toggles and low-balance alert threshold. The threshold is provided as `low_balance_threshold_amount` (a whole-currency amount) plus `low_balance_threshold_currency`; the server converts it to cents. An unknown currency returns `422`. - [Create user settings](https://docs.cardda.com/reference/createusersettings.md): Creates the settings record for the authenticated user (notification toggles and low-balance alert currency). This is a **per-user** resource and is not company-scoped. - [List permissions](https://docs.cardda.com/reference/listpermissions.md): Returns the catalog of permissions that can be attached to company roles and memberships. This is global reference data — it is **not company-scoped** and does not require the `company-id` header (it is on the whitelist). - [List notifications](https://docs.cardda.com/reference/listnotifications.md): Returns the authenticated user's visible in-app notifications for the current company (resolved from the `company-id` header), most recent first. - [Get unread notification count](https://docs.cardda.com/reference/getnotificationsunreadcount.md): Returns the number of unread notifications for the authenticated user in the current company (resolved from the `company-id` header). - [Get unread counts grouped by company](https://docs.cardda.com/reference/getnotificationsunreadcounts.md): Returns unread notification counts for the authenticated user grouped by company id. **No `company-id` header is required** — this endpoint is deliberately cross-company so the UI can show a per-company badge in one call. - [Mark all notifications as read](https://docs.cardda.com/reference/markallnotificationsasread.md): Marks every unread notification for the authenticated user in the current company (resolved from the `company-id` header) as read. Returns no content. - [Mark a notification as read](https://docs.cardda.com/reference/marknotificationasread.md): Marks a single notification (of the current company, resolved from the `company-id` header) as read. - [Mark a notification as unread](https://docs.cardda.com/reference/marknotificationasunread.md): Marks a single notification (of the current company, resolved from the `company-id` header) as unread. - [Retrieve a notification](https://docs.cardda.com/reference/shownotification.md): Returns a single notification of the current company (resolved from the `company-id` header). - [List transactions](https://docs.cardda.com/reference/listtransactions.md): Returns a paginated list of accounting-ledger transactions for the company. Each row is a unified projection of a card transaction, bank transfer, payment, commission, invoice or balance correction, and carries its rendición (expense-tracking) custom-column values. ## Key features - **Pagination**: `_start` / `_end` (default 25 items). `Content-Range` and `X-Total-Count` headers describe the window. - **Sorting**: `_field` / `_order`. Sortable virtual fields include `cartola_date` (the default), `merchant_name`, `card_name`, `card_last4`, `amount`, `target_amount`, `cumulative_balance` and `created_at`. - **Filtering**: any column can be filtered with a plain value or a JSON operator string (e.g. `{"$gte": ...}`, `{"$in": [...]}`, `{"$regex": "..."}`). There is no `$like` / `$ilike` operator — partial matching is `$regex`. - **Cumulative balances**: pass `_with_cumulative_balances=true` to inject running balances (`target_cumulative_balance_with_commission`). This requires a resolvable company. - **Hide commissions**: pass `_hide_commissions=true` to omit commission rows. ## Amount encoding Most monetary fields are serialized as **strings of integers in the minor unit** of the field's currency — for CLP that is the whole peso, since CLP has no subunit (see [Amounts and currency](https://docs.cardda.com/docs/amounts-and-currency)). `exchange_rate` is a human-formatted string; use `exchange_rate_value` for a machine-parseable rate. ## Authorization Non-admin callers see only transactions of companies where they hold the `transactions_view` permission, plus their own transactions. Scoping is per-user across the caller's permitted companies (via policy scope); the `company-id` header is **not** used to scope this list and an absent/mismatched header does not by itself produce a `401`. - [Download transactions CSV](https://docs.cardda.com/reference/downloadtransactionscsv.md): Exports the company's transactions as a CSV file (`text/csv`, `Content-Disposition: attachment`). The same filtering and sorting query parameters as the list endpoint apply. The export always computes cumulative balances and appends one column per company custom column plus an "Archivos" column listing attached file references. The CSV header is in Spanish: `Fecha, Fecha autorización, Descripción, Proveedor, Nombre Tarjeta, Tarjeta, Monto, Estado, Moneda origen, Cambio, Egresos, Ingresos, Moneda destino, Saldo, Etiquetas, Comentarios`, followed by the custom-column labels and `Archivos`. - [Retrieve one transaction](https://docs.cardda.com/reference/showtransaction.md): Returns a single transaction by its accounting-ledger id (`accounting_ledger_tx_id`). The response additionally includes the attached `transaction_labels`, `merchant_details` and `payables` (the latter two only for `banking_bank_transactions`, and payables only when the Pay product is active). **Note:** `show` returns a *different, narrower* projection than the list endpoint. It does not compute the labeled ledger fields (`transaction_type`, `status`, `charge`, `deposit`, `amount`, `exchange_rate`, `target_cumulative_balance_with_commission`, commission fields, etc.) that `GET /v1/transactions` adds — those are list/CSV-only. The plain `cumulative_balance` / `target_cumulative_balance` keys are the exception: they are virtual attributes aliased to the persisted ledger value, so they are present on **both** the list and the show responses. See the response schema. - [List transaction files](https://docs.cardda.com/reference/listtransactionfiles.md): Lists the files attached to a transaction's documentation. The transaction is resolved from its accounting-ledger id, and both the concrete and STI base documentation records are searched so legacy attachments remain retrievable. Returns an empty array when no documentation exists. - [Upload transaction files](https://docs.cardda.com/reference/uploadtransactionfiles.md): Attaches one or more files to a transaction's documentation, creating the documentation record on first upload. Send the request as `multipart/form-data` with a `files` field (single file or array). Returns the most recently attached file. - [Retrieve one transaction file](https://docs.cardda.com/reference/showtransactionfile.md): Returns a single attached file (with its blob) by attachment id. Responds `404` when the file does not belong to the transaction's documentation. - [Delete a transaction file](https://docs.cardda.com/reference/deletetransactionfile.md): Purges an attached file from the transaction's documentation. Responds `404` when the file does not belong to the documentation, otherwise `204 No Content`. - [Get a transaction file URL](https://docs.cardda.com/reference/gettransactionfileurl.md): Returns a temporary, time-limited URL to download an attached file. Responds `404` when the file does not belong to the transaction's documentation. - [List cartolas](https://docs.cardda.com/reference/listcartolas.md): Returns a paginated list of the company's cartolas (monthly account statements). By default results are ordered by year and month descending. Each item reports whether a generated statement document is currently attached (`document_attached`). Requires the `transactions_view` permission on the company. - [Retrieve one cartola](https://docs.cardda.com/reference/showcartola.md): Returns a single cartola by id, including the ids of the accounting-ledger transactions assigned to it (`cardda_transaction_ids`). Requires the `transactions_view` permission. - [Get a cartola document URL](https://docs.cardda.com/reference/getcartoladocument.md): Returns a temporary, time-limited URL to download the cartola's generated statement document. Responds `404` when no document is attached. Requires the `transactions_view` permission. - [List custom columns](https://docs.cardda.com/reference/listcustomcolumns.md): Returns a paginated list of custom columns for the companies the caller belongs to. Custom columns define the configurable rendición (expense-tracking) fields attached to transactions and other applicable models. Results are scoped to the caller's company memberships. - [Create a custom column](https://docs.cardda.com/reference/createcustomcolumn.md): Creates a custom column. Requires the `custom_columns_create` permission on the company. - [Update a custom column](https://docs.cardda.com/reference/updatecustomcolumn.md): Updates a custom column. The caller must be a member of the company that owns the column. All fields are optional; only the provided fields are changed. - [Set a custom column value](https://docs.cardda.com/reference/updatecustomcolumnvalue.md): Sets the value of a custom column on a specific source record (identified by `source_id` — for a transaction this is its `accounting_ledger_tx_id`). The caller must belong to the record's company. For option-type columns, `value` must be one of the column's option keys. Returns the updated source record with its recomputed custom-column values. **Note:** only an unknown `custom_column_id` yields a `404`. An unknown/mismatched `source_id` is not currently guarded and results in a `500` (server error) rather than a `404` — this is a known server-side bug, not the intended contract. - [List custom column option condition sets](https://docs.cardda.com/reference/listcustomcolumnoptionconditionsets.md): Returns a paginated list of custom-column option condition sets for the caller's companies. Each set constrains, based on its `conditions`, which option keys of dependent custom columns are allowed — enabling conditional/dependent dropdowns for rendición metadata. Each item includes its `custom_column_dependencies`. - [List reconciliation matches](https://docs.cardda.com/reference/listreconciliationmatches.md): Returns a paginated list of reconciliation matches for the company. Each match links two reconciliation records (e.g. a payable and the bank transaction that paid it) and embeds both records (`record_a`, `record_b`) without their embedding vectors. The `type` field is the STI subtype derived from the linked pair. Non-admin callers only see matches whose payable they can access. - [Create a reconciliation match](https://docs.cardda.com/reference/createreconciliationmatch.md): Links two reconciliation records into a match. Both records must exist and be reconcilable with each other; the concrete match subtype is determined automatically from the pair. **Note:** the create response returns the bare match, including its `type` (a persisted STI column, always present; the list endpoint's `methods: [:type]` is redundant). Only the embedded `record_a` / `record_b` records are list-only — they are not populated on this create response. - [Delete a reconciliation match](https://docs.cardda.com/reference/deletereconciliationmatch.md): Removes a reconciliation match, unlinking the two records. Returns the deleted match. - [Retrieve one reconciliation record](https://docs.cardda.com/reference/showreconciliationrecord.md): Returns a single reconciliation record by id, including its matches (`matches_as_a`, `matches_as_b`), the records it is matched against (`matched_records`), the remaining `amount_to_be_reconciled`, and whether it is `exhausted`. The embedding vector is omitted. Non-admin callers only see records of their companies. **Note:** the record is looked up with `find_by` (not `find_by!`), so an unknown `record_id` does **not** return a `404` — the endpoint responds `200` with a `null` body. - [List reconcilable records for a record](https://docs.cardda.com/reference/listreconcilablerecords.md): Returns the records that can be reconciled against the given record (candidates for a match), paginated and with `amount_to_be_reconciled` / `exhausted` computed. Supports filtering via query parameters and sorting; when sorting by `reference_date`, NULL dates are sorted last. ## Pagination note For performance, the total count is **capped** at the maximum page size: the `Content-Range` / `X-Total-Count` headers report at most the cap (they read as "K+" once the cap is hit), and the exact total is intentionally not computed for this endpoint. Requesting a window whose end exceeds the cap (e.g. a large non-zero `_start`) is rejected with `416`. **Note:** the parent record is looked up with `find_by` (not `find_by!`), so an unknown `record_id` does **not** return a `404`; the subsequent call on a nil record currently raises and the endpoint responds with a `500` (server error). This is a known server-side bug. - [List reconciliation suggestions for a record](https://docs.cardda.com/reference/listreconciliationsuggestions.md): Returns suggested reconciliation records for the given record — the system's best candidates to match against it (e.g. semantically/amount-similar counterparts). The embedding vector is omitted from the response. **Note:** the record is looked up with `find_by` (not `find_by!`), so an unknown `record_id` does **not** return a `404`; the subsequent `.suggestions` call on a nil record currently raises and the endpoint responds with a `500` (server error). This is a known server-side bug. - [List recurring charges](https://docs.cardda.com/reference/listrecurringcharges.md): Returns a paginated list of the company's recurring charges (subscription-like expected charges), each including its `merchant` and `vendor_card` summaries and computed fields (`finalized?`, `days_since_expected`, `overdue?`, `amount`). Sorting by the virtual field `next_expected_at` is supported. Non-admin callers see charges they own, charges on their cards, or all company charges if they hold `card_transactions_manage`. - [List company merchants for recurring charges](https://docs.cardda.com/reference/listrecurringchargecompanymerchants.md): Returns the distinct merchants the company has card transactions with, ordered by name. Used to populate the merchant selector when creating a recurring charge. Requires access to the company's recurring charges. - [List a recurring charge's supporting transactions](https://docs.cardda.com/reference/listrecurringchargetransactions.md): Returns up to the 20 most recent card transactions that support the given recurring charge, each with its `merchant` and `vendor_card` summaries. Transactions are scoped by the card transaction policy — members without `card_transactions_manage` see only their own. - [List recurring charge suggestions](https://docs.cardda.com/reference/listrecurringchargesuggestions.md): Returns a paginated list of pending, auto-detected recurring-charge suggestions for the company, ordered by detection confidence (descending). Each suggestion includes its `merchant` and `vendor_card` summaries. Non-admin callers see suggestions for their cards or user, or all company suggestions if they hold `card_transactions_manage`. - [List transaction rules](https://docs.cardda.com/reference/listtransactionrules.md): Returns a paginated list of the company's transaction rules (automations that match transactions and apply custom-column change effects). Each rule includes its `custom_column_change_effects` and `related_merchants`. Optionally filter by `merchant_id`. Requires the `transactions_rules_view` or `transactions_rules_manage` permission; hidden rules are excluded for non-admins. - [Create a transaction rule](https://docs.cardda.com/reference/createtransactionrule.md): Creates a transaction rule. Requires the `transactions_rules_manage` permission. The `company_id` and `user_id` are taken from the authenticated context and `company-id` header. - [Update a transaction rule](https://docs.cardda.com/reference/updatetransactionrule.md): Updates a transaction rule and its custom-column change effects. Requires the `transactions_rules_manage` permission. All fields are optional. Effects can be updated (include `id`), added, or removed (`_destroy: true`). - [Retrieve one transaction rule](https://docs.cardda.com/reference/showtransactionrule.md): Returns a single transaction rule with its `custom_column_change_effects` and `related_merchants`. Requires the `transactions_rules_view` or `transactions_rules_manage` permission. - [Delete a transaction rule](https://docs.cardda.com/reference/deletetransactionrule.md): Deletes a transaction rule. Requires the `transactions_rules_manage` permission. Returns the deleted rule. - [List transaction labels](https://docs.cardda.com/reference/listtransactionlabels.md): Returns a paginated list of transaction labels available to the caller, scoped to the caller's company (members with owner/admin/finance/member roles). Labels are company-scoped tags that can be associated with transactions. - [List transaction label associations](https://docs.cardda.com/reference/listtransactionlabelassociations.md): Returns a paginated list of label-to-transaction associations, filterable by `cardda_transaction_id` or `transaction_label_id`. - [Associate a label with a transaction](https://docs.cardda.com/reference/createtransactionlabelassociation.md): Associates a label with a transaction. Provide `cardda_transaction_id` and either an existing `transaction_label_id` or a `label` name (a label is created for the caller's company when only `label` is given and none matches). The caller must own the transaction or have a role over its owner within the same company. - [Remove a label from a transaction](https://docs.cardda.com/reference/deletetransactionlabelassociation.md): Removes the association between a label and a transaction. This operates on the collection path — identify the association by `cardda_transaction_id` + `transaction_label_id` passed as query or body parameters (there is no id in the path). - [Update a transaction label](https://docs.cardda.com/reference/updatetransactionlabel.md): Updates a transaction label's `label` and/or `color`. The caller must be a member of the label's company. Returns the updated label. - [Delete a transaction label](https://docs.cardda.com/reference/deletetransactionlabel.md): Deletes a transaction label. The caller must be a member of the label's company. Returns the id of the deleted label. - [List bills](https://docs.cardda.com/reference/listbills.md): Returns a paginated list of the company's bills ("boletas/facturas de Cardda"): the monthly billing documents that aggregate Cardda's commission charges. ## Scope Company users only see bills for companies they are a member of (via their company memberships). Cardda staff see all bills. ## Filtering, sorting, pagination Supports the standard list controls: `_start`/`_end` for pagination, `_field`/`_order` for sorting, and per-field filters. A filter value can be a plain value (exact match) or a JSON string with an operator, e.g. `status={"$in":["issued","preissued"]}`. ## Response Each bill includes `charges_with_descriptions`, a human-readable breakdown of the per-product charges. - [Get a bill](https://docs.cardda.com/reference/getbill.md): Returns a single bill by id, including its `charges_with_descriptions` breakdown. Company users may only read bills for companies they belong to; requesting a bill outside that scope returns `404 Not Found`. - [List balance groups](https://docs.cardda.com/reference/listbudgets.md): Returns the company's active balance groups ("grupos de saldo" / budgets), each with its computed totals (`committable_cents`, `available_cents`, `consumed_balance_cents`), its embedded `manager`, and its bound `vendor_cards`. ## Access - Admin / finance users (permission `budgets_manage`) see every group in the company. - Other users only see the groups they manage (`manager_id` == their user id). The company is taken from the `company-id` header. This endpoint is not paginated — it returns all active groups in scope. - [Create a balance group](https://docs.cardda.com/reference/createbudget.md): Creates a balance group under the company from the `company-id` header. Requires admin or the `budgets_manage` permission. All fields are nested under a `budget` key. The name must be unique per company among active (non-dissolved) groups. - [Get a balance group](https://docs.cardda.com/reference/getbudget.md): Returns a single balance group by id, with its computed totals, embedded `manager`, and bound `vendor_cards`. Readable by admin / `budgets_manage` users and by the group's own manager. A group outside the caller's scope returns `404 Not Found`. - [Assign cards to a balance group](https://docs.cardda.com/reference/assigncardstobudget.md): Binds one or more cards to this balance group, moving each from any previous group (a card belongs to at most one group). A prepaid card carries its loaded balance with it, growing this group's pool. Requires admin or the `budgets_manage` permission. If the group has been dissolved, the request is rejected with `422`. Returns the updated group (reloaded). - [Get an exchange rate](https://docs.cardda.com/reference/getexchangerate.md): Returns today's conversion rate for a currency pair. The `id` path parameter is the 6-character pair (source + target, e.g. `usdclp`). The rate is resolved for the current date and the caller's company country; if none exists yet, Cardda fetches and stores one from the external provider. Any `id` whose length is not exactly 6 returns `400 Bad Request` with an empty body. - [List invoices](https://docs.cardda.com/reference/listinvoices.md): Returns a paginated list of invoices ("facturas de venta"). ## Access Access is scoped to the caller: a non-staff user must request their own invoices by passing their user id as the `user_id` filter (`user_id` must equal the authenticated user's id). Requests without a matching `user_id` are rejected with `401`. Cardda staff may query any invoices. ## Filtering, sorting, pagination Supports `_start`/`_end` pagination, `_field`/`_order` sorting, and per-field filters. A filter value can be a plain value or a JSON string with an operator, e.g. `company_id={"$in":[...]}`. ## Response Each invoice includes `paid_amount` (total paid to date) and its `account`. - [Update a payment](https://docs.cardda.com/reference/updatepayment.md): Updates a payment / deposit ("abono"). ## Permitted fields A non-staff company user (with access to the payment's company) may only edit `comments`. The request is rejected with `401 Unauthorized` only when `comments` is absent from the body; if `comments` is present, any other (staff-only) fields sent alongside it are silently dropped and the request succeeds with `200`. The full set of payment fields is editable only by Cardda staff (admin/superadmin). Unlike the list/detail endpoints, the update response returns the bare payment record: it does NOT include the `amount` money object or the `ppo_allocations` array. - [Create a refund request](https://docs.cardda.com/reference/createrefundrequest.md): Creates a refund request for a user. The caller must have the `companies_manage` permission in a company the target user (`user_id`) belongs to. On creation a confirmation token is generated server-side; the target user then confirms the request by email before it is processed. - [List integration keys](https://docs.cardda.com/reference/listintegrationkeys.md): Returns a paginated list of the caller's integration keys (stored third-party credentials). Keys are scoped to the authenticated user (Cardda staff see all). The secret fields `password` and `token` are never returned. Each key includes `company_ids`, the companies managed with it. Supports `_start`/`_end` pagination, `_field`/`_order` sorting, and per-field filters. - [Create an integration key](https://docs.cardda.com/reference/createintegrationkey.md): Creates an integration key against a service (`key_service_id`), owned by the calling user and enabled on creation. The required secret depends on the service's auth method: `token`-based services require `token`; `password`-based services require `password` and `identifier`. The `auth_method` and `identifier_type` are copied from the service. - [List integration key services](https://docs.cardda.com/reference/listintegrationkeyservices.md): Returns a paginated list of the available integration services that keys can be created against (e.g. an ERP or the SII). Each service describes how a key must authenticate (`auth_method`, `identifier_type`). Visible to any authenticated user. This is a distinct collection from `/v1/integrations/keys` (the stored credentials). Supports `_start`/`_end` pagination, `_field`/`_order` sorting, and per-field filters. ## Recipes - [Make your first BCI payroll](https://docs.cardda.com/recipes/make-your-first-bci-payroll.md) - [Make your first BCP transaction](https://docs.cardda.com/recipes/make-your-first-bcp-transaction-1.md)