# Authentication Source: https://docs.layerfi.com/api-details/authentication Layer authenticates every API request with an OAuth 2.0 bearer token. This page covers Layer's environments, how to obtain a token for server-side API calls, and how to mint business-scoped tokens for client-side applications. ## Prerequisites Before calling Layer's API, you will need: * A Layer account. Reach out to your Layer contact or [contact our team](https://www.layerfi.com/contact). * Client credentials (`client_id` and `client_secret`) provided by Layer. Your `client_secret` grants full access to your Layer data. Keep it on your server and never expose it in client-side code. For browser or mobile apps, use [business-scoped access tokens](#business-scoped-access-tokens) instead. ## Environments Layer provides two environments for development and production use: | Environment | Base URL | OAuth Scope | | - | - | - | | **Sandbox** | `https://sandbox.layerfi.com` | `https://sandbox.layerfi.com/sandbox` | | **Production** | `https://api.layerfi.com` | `https://api.layerfi.com/production` | Use sandbox for development and testing. All examples on this page use the sandbox environment. Swap in the production base URL and scope when you go live. ## Authenticating API requests Layer uses OAuth 2.0's client credentials flow. Exchange your credentials for a short-lived access token, then send that token as a bearer token on every API request. To receive an access token, send a POST request to Layer's authorization server, passing your `client_id` and `client_secret` via HTTP Basic authentication. In the request body, include the `grant_type`, `scope`, and `client_id`. ```bash cURL theme={null} curl -X POST https://auth.layerfi.com/oauth2/token \ -u : \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "scope=https://sandbox.layerfi.com/sandbox" \ --data-urlencode "client_id=" ``` ```python Python theme={null} import requests from requests.auth import HTTPBasicAuth response = requests.post( "https://auth.layerfi.com/oauth2/token", auth=HTTPBasicAuth("", ""), headers={"Content-Type": "application/x-www-form-urlencoded"}, data={ "grant_type": "client_credentials", "scope": "https://sandbox.layerfi.com/sandbox", "client_id": "" } ) token_data = response.json() access_token = token_data["access_token"] ``` ```javascript Node.js theme={null} const axios = require('axios'); const getAccessToken = async () => { const response = await axios.post( 'https://auth.layerfi.com/oauth2/token', new URLSearchParams({ grant_type: 'client_credentials', scope: 'https://sandbox.layerfi.com/sandbox', client_id: '' }), { auth: { username: '', password: '' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); return response.data.access_token; }; ``` The authorization server will respond with your granted access token: ```json theme={null} { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` Extract the `access_token` value from the response. You'll use this in the `Authorization` header for all API requests. Include the access token as a bearer token in the `Authorization` header. You can confirm your credentials are working by calling the `/whoami` endpoint. ```bash cURL theme={null} curl https://sandbox.layerfi.com/whoami \ -H "Authorization: Bearer " ``` ```python Python theme={null} import requests response = requests.get( "https://sandbox.layerfi.com/whoami", headers={"Authorization": f"Bearer {access_token}"} ) print(response.json()) ``` ```javascript Node.js theme={null} const axios = require('axios'); const response = await axios.get( 'https://sandbox.layerfi.com/whoami', { headers: { 'Authorization': `Bearer ${accessToken}` } } ); console.log(response.data); ``` The API will respond with your client name and client id: ```json theme={null} { "data":{ "type":"whoami", "clientName":"Layer Example", "clientId":"018f1657-dc66-7482-917b-c0c0e532f52b" } } ``` Access tokens expire after 1 hour. To refresh your access token, make another call to Layer's authorization endpoint with your `client_id` and `client_secret`. We recommend refreshing tokens for new sets of requests rather than persisting access tokens. ## Business-scoped access tokens When you build client-side experiences (for example, embedding [Layer's React components](/guides/embedded-components)), you need a token that a browser or mobile app can safely hold. Rather than exposing your `client_secret` or a full-access token, mint a temporary token scoped to a single business on your backend and pass that to the client. ### Mint a business-scoped token From your backend, call the [Create business auth token](/api-reference/v1/create-business-auth-token) endpoint, authenticating with the bearer token from the [flow above](#authenticating-api-requests): ```bash cURL theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{businessId}/auth-token \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"session_duration": 3600}' ``` The response is an `AuthToken` containing an access token scoped to that business: ```json theme={null} { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` `session_duration` is optional and sets how long, in seconds, the token is valid. It defaults to 3600 (1 hour). ### Use the token in your client Pass the business-scoped `access_token` to your client-side application. With Layer's embedded components, provide it to `LayerProvider` as `businessAccessToken`: ```tsx theme={null} {...} ``` Because these tokens are short-lived and limited to a single business, refresh them from your backend as needed. See [LayerProvider context](/embedded-components/layerprovider-context) for the full component setup. # Idempotency Source: https://docs.layerfi.com/api-details/idempotency Creation operations to the Layer API are idempotent when an external ID is specified, such as the `external_id` field on a [Business](/api-reference/business/business) object. Others are indicated in the documentation. While these keys are not always required, use of idempotency keys is highly recommended whenever available. # JSON data Source: https://docs.layerfi.com/api-details/json-data Layer uses a standardized json structure across all endpoints. There are only 3 possible top level fields. ### Data Contains the requested data from the endpoint and can be either a JSON list or a JSON object. * Every top level object or item in an array will contain a `type` field indicating the entity type. * `data` will only be present if the result is successful, in which case there will be a `2**` status code and no `error` field. ```json theme={null} { "data":[ { "type":"Business", "id":"08cee9cc-389e-44ea-a42e-ffb12670f515", "external_id":"id-1", "legal_name":"Acme, Inc.", "us_state":"AZ", "entity_type":"LLC", "phone_number":"53924476123", "imported_at":"2023-07-13T17:25:59.292451Z", "updated_at":"2023-07-13T17:25:59.292451Z", "archived_at":null }, { "type":"Business", "id":"e348d217-1788-494c-9c1c-d8be13b89aba", "external_id":"id-2", "legal_name":"Acme, Inc.", "us_state":"AZ", "entity_type":"LLC", "phone_number":"69565771257", "imported_at":"2023-07-13T17:25:59.720376Z", "updated_at":"2023-07-13T17:25:59.720376Z", "archived_at":null } ], "meta":{ } } ``` ### Errors An array of `error` objects. `error` objects will contain the following fields. * `type`: One of a fixed set of categories. Helpful for categorizing & processing errors. * `description`: A human readable error description. * `error_enum`: A stable, machine-readable identifier for programmatically handling specific error conditions. Only present for `4**` client errors, not included for `5**` server errors. Use `error_enum` instead of parsing `description`, as enum values remain stable across API versions while descriptions may change. * `meta`: Optional additional information. `errors` will be present only if the request is unsuccessful, in which case there will be a `4**` or `5**` status code and no `data` field. ```json theme={null} { "errors": [ { "type": "Plaid", "description": "Plaid credentials must be set before you can add plaid items to businesses. See /v1/configure/plaid", "error_enum": "PlaidCredentialsNotConfigured" } ] } ``` ### Meta An optional object that may be used to communicate metadata about the request. Example use cases include: * Idempotency * Pagination * Rate limits # Pagination Source: https://docs.layerfi.com/api-details/pagination Listing endpoints, for example [List all Businesses](/api-reference/business/list) and [List all Bank Transactions](/api-reference/bank-transaction/list) support cursor-based pagination. Pagination can be controlled via query string parameters: * `sort_by` which supports some timestamp, integer and string keys. Valid sort keys are noted in documentation where applicable. Sort key is optional. * `sort_order` specifies either ASC or DESC ordering for the sort key. Optional, ASC by default. * `cursor` returned by the previous list request. Do not specify for the initial listing API call. * `limit` constrains the number of results to be returned. Defaults to 100 for most endpoints. * `show_total_count` causes the `total_count` field (total number of entities matching the query) to be returned in the pagination metadata. ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/businesses/{business_id}/bank-transactions?sort_by=date&sort_order=DESC&limit=50&show_total_count=true \ -H "Authorization: Bearer " ``` Responses to paginating endpoints will include pagination data in the meta response field. ```json Response theme={null} { "data": [ // Data omitted ], "meta": { "pagination": { "sort_by": "date", "sort_order": ASC, "cursor": "VGhhbmtzIGZvciByZWFsbHkgcmVhZGluZyB0aGUgZG9jdW1lbnRhdGlvbiE=" "has_more": true, "total_count": 456 } } } ``` When the `has_more` field is true, use the returned cursor in an additional request to fetch the next page of results. `show_total_count` has a performance cost, so it **defaults to false**. We recommend only setting this flag when specifically needed. # Rate limiting Source: https://docs.layerfi.com/api-details/rate-limiting Layer uses a single API-wide endpoint cost rate limiting system, where every endpoint contributes a cost towards a total budget. The budget follows a bucket model, where each API call uses tokens from a current bucket which is refilled every 1 second. ## Default Rate Limits Most endpoints use the following default rate limits: | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 100 requests | 1 second | 100 requests | | Production | 500 requests | 1 second | 100 requests | Some endpoints have custom rate limit policies with different limits. These are documented on the individual endpoint pages. ## Rate Limit Headers Rate limits should never be approached for normal customer read operations, and are only intended to limit heavy data ingestion processes, such as en-masse backfills of data. Nonetheless, we recommend adding retries on all Layer API calls. To assist in retries, the following headers are included in every successful API request: * `X-RateLimit-Limit`: a specified bucket capacity. * `X-RateLimit-Remaining`: the number of tokens remaining in a bucket. * `X-RateLimit-Reset`: a UTC timestamp (in seconds) that specifies the time of refilling a bucket. Any API calls that are rate limited will receive a response with: * Error code `429: Too Many Requests` * `Retry-After` header indicating (in seconds) how long to wait before retrying the request. During normal operations, adding enough retries that requests will retry 1 second later should be sufficient to avoid any rate limiting. # Webhooks Source: https://docs.layerfi.com/api-details/webhooks ## Setup Requirements Webhooks are how Layer notifies your application of events in real-time. At their core, they are HTTP POST requests sent to a pre-determined endpoint that you control. You can configure webhook endpoints from the Layer developer portal. Your endpoint will listen to the event types you specify, allowing you to react to changes in your customers' data as they happen. **Requirements for webhook endpoints:** * **Response Status**: Your endpoint must return an HTTP status code in the 2xx range (200-299) to indicate successful receipt. Any other status code will be treated as a failure and trigger the retry mechanism. * **Response Time**: Your endpoint must respond within 15 seconds. Requests that exceed this timeout will be considered failed and will be retried. * **CSRF Protection**: Disable CSRF (Cross-Site Request Forgery) protection for your webhook endpoint if your framework enables it by default, as webhook requests will not include CSRF tokens. * **Signature Verification**: Always verify the webhook signature to ensure the request is authentic. See the [signature verification section](#verifying-signatures) for implementation details. ## Adding an Endpoint To start receiving webhooks, you need to configure your endpoints in the Layer developer portal. Adding an endpoint is as simple as providing a URL that you control and selecting the event types you want to listen to. If you don't specify any event types, by default, your endpoint will receive all events, regardless of type. This can be helpful for getting started and for testing, but we recommend changing this to a subset later on to avoid receiving extraneous messages. ## Testing Endpoints Once you've added an endpoint, you'll want to make sure it's working correctly. The "Testing" tab in the Layer developer portal lets you send test events to your endpoint. After sending an example event, you can click into the message to view the message payload, all of the message attempts, and whether it succeeded or failed. ## Verifying Signatures Webhook signatures let you verify that webhook messages are actually sent by Layer and not a malicious actor. **You should always verify webhook signatures in production.** ### Signature Headers Every webhook request includes three headers: | Header | Description | | - | - | | `webhook-id` | Unique identifier for the message | | `webhook-timestamp` | Unix timestamp of when the message was sent | | `webhook-signature` | Space-delimited list of signatures for the message | These are the [Standard Webhooks](https://www.standardwebhooks.com/) header names. ### Verifying with the Svix Libraries Layer's webhook partner Svix offers a set of useful libraries that make verifying webhooks very simple. Pass through the headers exactly as you receive them. Here is an example using JavaScript: ```javascript theme={null} import { Webhook } from "svix"; const secret = "YOUR_WEBHOOK_SECRET"; // Get this from the Layer developer portal // These were all sent from the server const headers = { "webhook-id": "msg_p5jXN8AQM9LWM0D4loKWxJek", "webhook-timestamp": "1614265330", "webhook-signature": "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=", }; const payload = '{"test": 2432232314}'; const wh = new Webhook(secret); // Throws on error, returns the verified content on success const verifiedPayload = wh.verify(payload, headers); ``` For more instructions and examples in other languages (Python, Go, Ruby, Java, Rust, C#, PHP, Kotlin, Swift), check out the [Svix webhook verification documentation](https://docs.svix.com/receiving/verifying-payloads/how). ## Retry Schedule Layer attempts to deliver each webhook message based on a retry schedule with exponential backoff. ### The Schedule Each message is attempted based on the following schedule, where each period is started following the failure of the preceding attempt: | Attempt | Delay After Previous Failure | | - | - | | 1 | Immediately | | 2 | 5 seconds | | 3 | 5 minutes | | 4 | 30 minutes | | 5 | 2 hours | | 6 | 5 hours | | 7 | 10 hours | | 8 | 10 hours | If an endpoint is removed or disabled, delivery attempts to the endpoint will be disabled as well. For example, an attempt that fails three times before eventually succeeding will be delivered roughly 35 minutes and 5 seconds following the first attempt. ### Manual Retries You can use the Layer developer portal to manually retry each message at any time, or automatically retry ("Recover") all failed messages starting from a given date. ## Troubleshooting There are some common reasons why your webhook endpoint might be failing: ### Not Using the Raw Payload Body This is the most common issue. When generating the signed content, we use the raw string body of the message payload. If you parse the JSON and then re-serialize it (e.g., using `JSON.stringify()` in JavaScript), different implementations may produce different string representations of the JSON object, which can lead to discrepancies when verifying the signature. You must verify the signature using the exact raw request body bytes as received from Layer, not a re-serialized version. ### Missing the Secret Key From time to time we see people simply using the wrong secret key. Remember that keys are unique to endpoints. ### Sending the Wrong Response Codes When we receive a response with a 2xx status code, we interpret that as a successful delivery even if you indicate a failure in the response payload. Make sure to use the right response status codes so we know when messages are supposed to succeed vs fail. ### Responses Timing Out We will consider any message that fails to send a response within 15 seconds a failed message. If your endpoint is also processing complicated workflows, it may timeout and result in failed messages. We suggest having your endpoint simply receive the message and add it to a queue to be processed asynchronously so you can respond promptly and avoid getting timed out. ## Failure Recovery ### Re-enable a Disabled Endpoint If all attempts to a specific endpoint fail for a period of 5 days, the endpoint will be disabled. To re-enable a disabled endpoint, go to the Layer developer portal, find the endpoint from the list and select "Enable Endpoint". ### Recovering/Resending Failed Messages If your service experiences downtime or your endpoint was misconfigured, you can recover messages that failed during that period. The Layer developer portal provides several recovery options: **Single Message Replay** To resend an individual message: 1. Navigate to the message in the Layer developer portal 2. Click the options menu next to any of the delivery attempts 3. Select "Resend" to send the message to your endpoint again **Bulk Recovery from Service Outage** To replay all failed messages since a specific time: 1. Navigate to the endpoint's details page 2. Click "Options > Recover Failed Messages" 3. Select the time window from which to recover messages **Time-Based Granular Recovery** To recover all failed messages from a specific timestamp: 1. Navigate to any message on the endpoint page 2. Click the options menu for that message 3. Select "Replay..." and choose "Replay all failed messages since this time" # Webhooks event catalog Source: https://docs.layerfi.com/api-details/webhooks-event-catalog ## Event Types Data entity events follow `EntityName.operation` and generally use thin payloads. **Example payload:** ```json theme={null} { "id": "Customer_created_7bcef4fd-9458-49d0-a7e7-589f5e6f2683_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "Customer.created", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "entity_id": "7bcef4fd-9458-49d0-a7e7-589f5e6f2683", "entity_external_id": "cust_2001" } } ``` | Entity | Events | | - | - | | [BankTransaction](#events-with-additional-metadata) | `BankTransaction.created`, `BankTransaction.updated`, `BankTransaction.archived` | | Bill | `Bill.created`, `Bill.updated`, `Bill.archived` | | BillPayment | `BillPayment.created`, `BillPayment.updated`, `BillPayment.archived` | | Business | `Business.created`, `Business.updated`, `Business.archived` | | [BusinessTask](#events-with-additional-metadata) | `BusinessTask.created`, `BusinessTask.updated`, `BusinessTask.archived` | | Customer | `Customer.created`, `Customer.updated`, `Customer.archived` | | CustomerCredit | `CustomerCredit.created`, `CustomerCredit.updated`, `CustomerCredit.archived` | | CustomerPayout | `CustomerPayout.created`, `CustomerPayout.updated`, `CustomerPayout.archived` | | CustomerRefund | `CustomerRefund.created`, `CustomerRefund.updated`, `CustomerRefund.archived` | | GeneralLedgerAccount | `GeneralLedgerAccount.created`, `GeneralLedgerAccount.updated`, `GeneralLedgerAccount.archived` | | Invoice | `Invoice.created`, `Invoice.updated`, `Invoice.archived` | | InvoicePayment | `InvoicePayment.created`, `InvoicePayment.updated`, `InvoicePayment.archived` | | InvoiceWriteOff | `InvoiceWriteOff.created`, `InvoiceWriteOff.updated`, `InvoiceWriteOff.archived` | | TaxProfile | `TaxProfile.created`, `TaxProfile.updated`, `TaxProfile.archived` | | TimeEntry | `TimeEntry.created`, `TimeEntry.updated`, `TimeEntry.archived` | | Trip | `Trip.created`, `Trip.updated`, `Trip.archived` | | Vehicle | `Vehicle.created`, `Vehicle.updated`, `Vehicle.archived` | | Vendor | `Vendor.created`, `Vendor.updated`, `Vendor.archived` | | VendorCredit | `VendorCredit.created`, `VendorCredit.updated`, `VendorCredit.archived` | | VendorPayout | `VendorPayout.created`, `VendorPayout.updated`, `VendorPayout.archived` | | VendorRefund | `VendorRefund.created`, `VendorRefund.updated`, `VendorRefund.archived` | ### Events with additional metadata `BankTransaction` lifecycle webhooks include an optional `category` object on `data` when the transaction is categorized to a ledger account. `category` includes the account `id`, optional `stable_name`, and `display_name`. This is typically present on `BankTransaction.updated` after categorization. ```json theme={null} { "id": "BankTransaction_updated_7bcef4fd-9458-49d0-a7e7-589f5e6f2683_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "BankTransaction.updated", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "entity_id": "7bcef4fd-9458-49d0-a7e7-589f5e6f2683", "entity_external_id": "webhook-txn-1", "category": { "id": "00000000-0000-0000-0000-000000000002", "stable_name": "MATERIALS", "display_name": "Materials for Sold Goods" } } } ``` `BusinessTask` lifecycle webhooks include the current active task count for the business in addition to the standard lifecycle entity fields. ```json theme={null} { "id": "BusinessTask_created_7bcef4fd-9458-49d0-a7e7-589f5e6f2683_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "BusinessTask.created", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "entity_id": "7bcef4fd-9458-49d0-a7e7-589f5e6f2683", "entity_external_id": null, "open_task_count": 3 } } ``` User activity events use the `activity.*` namespace. **Example payload:** ```json theme={null} { "id": "activity_categorize_bank_transaction_44bb48bd-4af1-4e6f-a38a-fb24e5575dc7", "type": "activity.categorize_bank_transaction", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "transaction_id": "34db2910-5919-4985-8e7f-56dd83e76ed5", "categorization_method": "API", "categorization": null, "matchType": "INVOICE_PAYMENT", "created_at": "2026-03-31T16:42:11Z" } } ``` * `activity.categorize_bank_transaction` * `activity.load_pnl` * `activity.load_balance_sheet` * `activity.load_cashflow_statement` * `activity.create_custom_account` * `activity.archive_custom_account` * `activity.reactivate_custom_account` * `activity.upload_custom_account_csv` * `activity.export_pnl_csv` * `activity.export_pnl_excel` * `activity.export_pnl_comparison_csv` * `activity.export_pnl_month_over_month` * `activity.export_pnl_line_item_excel` * `activity.export_balance_sheet_csv` * `activity.export_balance_sheet_excel` * `activity.export_cashflow_csv` * `activity.export_cashflow_excel` * `activity.export_transactions_csv` * `activity.export_transactions_excel` * `activity.export_pnl_pdf` * `activity.export_trial_balance_excel` * `activity.export_ar_aging_excel` * `activity.export_business_expenses_excel` * `activity.export_business_income_excel` * `activity.export_business_mileage_excel` * `activity.export_personal_expenses_excel` * `activity.export_personal_income_excel` * `activity.export_personal_mileage_excel` * `activity.export_time_tracking_excel` * `activity.export_schedule_c_excel` * `activity.generate_tax_packet` SMS events use the `sms.*` namespace. **Example payload:** ```json theme={null} { "id": "sms_message_received_SM1234567890", "type": "sms.message_received", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "message_id": "SM1234567890", "direction": "RECEIVED", "body": "Classify this as utilities", "phone_number": "+15551234567", "delivery_status": null, "at": "2026-03-31T16:48:55Z" } } ``` * `sms.message_received` * `sms.message_delivered` * `sms.message_delivery_failed` Email events use the `email.*` namespace. `email.message_received` fires for a newly received, direct email from a known sender. **Example payload:** ```json theme={null} { "id": "email_message_received_7bcef4fd-9458-49d0-a7e7-589f5e6f2683", "type": "email.message_received", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "message_id": "7bcef4fd-9458-49d0-a7e7-589f5e6f2683", "thread_id": "03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "direction": "RECEIVED", "from_address": "person@example.com", "subject": "Question about my books", "at": "2026-03-31T16:48:55Z" } } ``` The payload does not contain the email body or attachments. The `id` is stable for the received message. * `email.message_received` Bookkeeping webhooks notify you about onboarding completion, first-month purchase date changes, and bookkeeping context events. A bookkeeping context event is a normalized audit-style event, so many bookkeeping actions share the same webhook type, `bookkeeping_event.created`; use `data.resource_type` and `data.action` to distinguish what happened. ## Event types * `bookkeeping_onboarding.completed` * `bookkeeping_purchase_date.update` * `bookkeeping_event.created` ## `bookkeeping_onboarding.completed` Sent at the end of a business's Layer bookkeeping onboarding call, when their bookkeeping configuration's `onboarding_date` is set for the first time. **Example payload:** ```json theme={null} { "id": "bookkeeping_onboarding_completed_a43f6b83-8932-4ced-b6b1-0199313274ca_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "bookkeeping_onboarding.completed", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "bookkeeping_configuration_id": "a43f6b83-8932-4ced-b6b1-0199313274ca", "onboarding_date": "2026-05-07", "first_month_purchased_date": "2026-01-01", "activation_at": "2026-01-01T05:00:00Z" } } ``` ### Payload Fields | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this webhook event | | `type` | string | Always `bookkeeping_onboarding.completed` | | `business_id` | string (UUID) | The Layer business ID | | `business_external_id` | string or null | Your external identifier for the business, if set | | `data.bookkeeping_configuration_id` | string (UUID) | The ID of the bookkeeping configuration that completed onboarding | | `data.onboarding_date` | string (date) | The date when bookkeeping onboarding was completed, in `YYYY-MM-DD` format | | `data.first_month_purchased_date` | string (date) or null | The business's first purchased bookkeeping month, in `YYYY-MM-DD` format. `null` when no first-month-purchased value is set on the bookkeeping configuration. | | `data.activation_at` | string (date-time) | The business's activation timestamp, in ISO 8601 format. Always present. | ### When This Webhook Fires The `bookkeeping_onboarding.completed` webhook fires when Layer updates the business's bookkeeping configuration at the end of their onboarding call. This webhook only fires when the `onboarding_date` transitions from unset (null) to a value. Subsequent updates to `onboarding_date` do not trigger additional webhooks. ## `bookkeeping_purchase_date.update` Sent when a business's first purchased bookkeeping month changes on its bookkeeping configuration. Use this to keep your records in sync when Layer sets or updates the `first_month_purchased_date`. **Example payload:** ```json theme={null} { "id": "bookkeeping_purchase_date_update_00000000-0000-0000-0000-000000000002_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "bookkeeping_purchase_date.update", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "bookkeeping_configuration_id": "00000000-0000-0000-0000-000000000002", "first_month_purchased_date": "2024-01-01" } } ``` ### Payload Fields | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this webhook event | | `type` | string | Always `bookkeeping_purchase_date.update` | | `business_id` | string (UUID) | The Layer business ID | | `business_external_id` | string or null | Your external identifier for the business, if set | | `data.bookkeeping_configuration_id` | string (UUID) | The ID of the bookkeeping configuration whose purchase date changed | | `data.first_month_purchased_date` | string (date) or null | The business's first purchased bookkeeping month, in `YYYY-MM-DD` format. `null` when the first-month-purchased value has been cleared. | ### When This Webhook Fires The `bookkeeping_purchase_date.update` webhook fires whenever a business's `first_month_purchased_date` changes. `first_month_purchased_date` can change more than once, so you may receive this event multiple times for the same business with each event having a unique `id`. ## `bookkeeping_event.created` Sent when Layer records a bookkeeping context event for a business, such as a transaction categorization, task update, period status change, connected account change, adjustment entry, or closing date update. **Example payload:** ```json theme={null} { "id": "bookkeeping_event_created_4d2df66e-ae15-4241-9f6b-9c4bdf19f83e", "type": "bookkeeping_event.created", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "id": "4d2df66e-ae15-4241-9f6b-9c4bdf19f83e", "resource_type": "BOOKKEEPING_PERIOD", "resource_id": "77d54b21-d7d7-4bfc-8f33-2845e4f8e07a", "action": "PERIOD_STATUS_CHANGED", "summary": "Bookkeeper status changed period", "actor": "MANUAL_BOOKKEEPER", "count": null, "event_at": "2026-03-31T16:52:44Z", "accounting_date": "2026-03-31T04:59:59.999999999Z", "previous_state": "TO_DO", "new_state": "DONE", "changed_fields": null } } ``` ### Bookkeeping context fields | Field | Description | | - | - | | `id` | Unique bookkeeping context event ID. | | `resource_type` | Bookkeeping resource affected by the event. | | `resource_id` | ID of the affected resource, when applicable. | | `action` | Specific bookkeeping action that occurred. | | `summary` | Human-readable event summary. | | `actor` | Actor that caused the event. | | `count` | Count associated with batch events, when applicable. | | `event_at` | Timestamp when the event occurred. | | `accounting_date` | Accounting-effective timestamp, when applicable. | | `previous_state` | Previous value or state, when applicable. | | `new_state` | New value or state, when applicable. | | `changed_fields` | Fields changed by the action, when applicable. Setting a bookkeeping start date returns `["bookkeeping_start_date"]`. | ### Bookkeeping context actions | Resource type | Actions | | - | - | | `BANK_TRANSACTION` | `CATEGORIZED`, `RECATEGORIZED` | | `BANK_TRANSACTION_BATCH` | `BATCH_CATEGORIZED` | | `TASK` | `TASK_CREATED`, `TASK_ANSWERED`, `TASK_COMPLETED` | | `BOOKKEEPING_PERIOD` | `PERIOD_STATUS_CHANGED` | | `BOOKKEEPING_STEP` | `STEP_COMPLETED` | | `CONNECTED_ACCOUNT` | `ACCOUNT_CONNECTED`, `ACCOUNT_DISCONNECTED`, `ACCOUNT_NEEDS_REPAIR`, `ACCOUNT_REPAIRED`, `ACCOUNT_CREATED`, `ACCOUNT_ARCHIVED`, `ACCOUNT_REACTIVATED` | | `ADJUSTMENT_ENTRY` | `CUSTOM_ENTRY_CREATED`, `CLOSING_ACTION_CREATED` | | `ACCOUNTING_CONFIGURATION` | `CLOSING_DATE_UPDATED` | | `BOOKKEEPING_CONFIGURATION` | `BOOKKEEPING_START_DATE_UPDATED` | ### Actors `actor` can be `USER`, `AI_BOOKKEEPER`, `MANUAL_BOOKKEEPER`, `SYSTEM`, or `UNKNOWN`. External account events use the `external_accounts.*` namespace. These events include the current count of external accounts that need repair for the business. **Example payload:** ```json theme={null} { "id": "external_accounts_account_connected_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "external_accounts.account.connected", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "provider": "plaid", "at": "2026-03-31T16:50:29Z", "link_id": "719b0d31-ba7b-4f1b-982a-c6334b0a544b", "external_link_id": "plaid_item_123", "account_ids": [ "92762148-f10b-42a5-b37f-b1e23fa3faca" ], "external_account_ids": [ "plaid_account_456" ], "accounts_needing_repair_count": 0 } } ``` ### Payload Fields | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this webhook event. | | `type` | string | The external account event type (e.g., `external_accounts.account.connected`). | | `business_id` | string (UUID) | The Layer business ID | | `business_external_id` | string or null | Your external identifier for the business, if set | | `data.provider` | string | The external account provider (e.g., `plaid`). | | `data.at` | string (date-time) | ISO 8601 timestamp when the event occurred. | | `data.link_id` | string (UUID) | Layer's internal ID for the external account link. | | `data.external_link_id` | string | The provider's ID for the link (e.g., Plaid Item ID). | | `data.account_ids` | array | Layer IDs of the affected external accounts. | | `data.external_account_ids` | array | Provider IDs of the affected external accounts. | | `data.accounts_needing_repair_count` | integer | Number of external accounts across the business that currently need repair. Only counts accounts where the parent bank account has `notify_when_disconnected` enabled. Excludes archived accounts. | ### Event types * `external_accounts.link.connected` * `external_accounts.link.disconnected` * `external_accounts.link.archived` * `external_accounts.link.reactivated` * `external_accounts.link.needs_repair` * `external_accounts.link.repaired` * `external_accounts.account.connected` * `external_accounts.account.archived` * `external_accounts.account.reactivated` * `external_accounts.account.needs_repair` * `external_accounts.account.repaired` Plaid-specific events use the `plaid.*` namespace. **Example payload:** ```json theme={null} { "id": "plaid_link_token_created_Aim3b8jJC9eRyfy", "type": "plaid.link.token_created", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "created_at": "2026-03-31T16:50:29Z", "plaid_request_id": "Aim3b8jJC9eRyfy" } } ``` * `plaid.link.token_created` ### Payload Fields | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this webhook event. Suffixed with the Plaid request id. | | `type` | string | Always `plaid.link.token_created` | | `business_id` | string (UUID) | The Layer business ID | | `business_external_id` | string or null | Your external identifier for the business, if set | | `data.created_at` | string (date-time) | When the link token was created | | `data.plaid_request_id` | string | The Plaid `request_id` returned by Plaid for the link-token-create call. Useful when correlating with Plaid logs or support tickets. | ### When This Webhook Fires The `plaid.link.token_created` webhook fires whenever Layer mints a Plaid link token for a business. This corresponds to the user initiating the Plaid Link flow (e.g. clicking "Add Account" or starting an update-mode reconnect). The event fires before the user selects an institution or completes the flow, so it can be used as a click-level signal. To know when a connection is actually established, listen for `external_accounts.link.connected`. Call booking events use the `call_booking.*` namespace. They notify you when a call booked through Calendly is scheduled, rescheduled, or canceled. **Example payload:** ```json theme={null} { "id": "call_booking_scheduled_00000000-0000-0000-0000-000000000001_03f6c94f-574d-42ca-a6cd-fecf2a2aeccb", "type": "call_booking.scheduled", "business_id": "8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "business_external_id": "biz_101", "data": { "calendly_event_uri": "https://api.calendly.com/scheduled_events/76b3fb2d-b5d8-4d60-b969-cef8bd2900de", "event_type_uri": "https://api.calendly.com/event_types/8a30f193-5ca9-4c2a-8718-420d43fda157", "invitee_name": "Jane Provider", "invitee_email": "jane@example.com", "event_start_at": "2024-01-15T12:00:00Z", "event_end_at": "2024-01-15T12:30:00Z", "purpose": "BOOKKEEPING_ONBOARDING", "previous_calendly_event_id": null, "tracking": { "utm_source": "layer", "utm_content": "business_id:8e7a359e-7af5-4f6e-b786-6ddfd1807c32", "utm_term": "partner-reference-42" } } } ``` ### Event types * `call_booking.scheduled` * `call_booking.rescheduled` * `call_booking.canceled` ### Payload Fields | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this webhook event. | | `type` | string | The call booking event type (for example, `call_booking.scheduled`). | | `business_id` | string (UUID) or null | Always included. The Layer business ID if the booking is made for a specific business. Null when no business is identified at the time of booking. | | `business_external_id` | string or null | Your external identifier, if set, when the booking is made for a specific business. Null when no business is identified at the time of booking. | | `data.calendly_event_uri` | string or null | Calendly scheduled-event API URI for the call. | | `data.event_type_uri` | string or null | Event type API URI identifying the kind of booking. Always included; null for older bookings without a stored URI. Reschedules use the new booking's event type. | | `data.invitee_name` | string or null | Name of the invitee who booked the call. Contains personally identifiable information (PII). | | `data.invitee_email` | string or null | Email of the invitee who booked the call. Contains PII. | | `data.event_start_at` | string (date-time) | ISO 8601 start time of the call. Required. | | `data.event_end_at` | string (date-time) or null | ISO 8601 end time of the call. | | `data.purpose` | string | Purpose of the call: `BOOKKEEPING_ONBOARDING` or `ADHOC`. Required. | | `data.previous_calendly_event_id` | string or null | Calendly event ID of the booking that was replaced. Populated only on `call_booking.rescheduled`. | | `data.tracking` | object or null | Provider tracking data captured when this booking was made. Always included; null when no tracking data is available. | Calendly bookings can include `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`, and `salesforce_uuid` in `data.tracking`. Arbitrary query parameters are not available. To pass your own reference through a Calendly booking link, use one of these available UTM parameters. ### When This Webhook Fires * `call_booking.scheduled` fires for a new booking. * `call_booking.rescheduled` fires when an existing booking moves to a new time. * `call_booking.canceled` fires when an existing booking is canceled without being rescheduled. Business-specific fields (`business_id` and `business_external_id`) will be populated if a call booking can be identified as that specific business via parameters on the call booking URL. `business_external_id` is populated only if the business has an external ID. Both fields will be null if the business cannot be identified. A reschedule is delivered as a single `call_booking.rescheduled` event. Layer does not also send `call_booking.canceled` and `call_booking.scheduled` events for the same reschedule. Export events use the `export.*` namespace and notify you when an [async export](/guides/async-reports) finishes. These events are **client-scoped**: the payload includes `id`, `type`, and `data`, and does not include top-level `business_id` / `business_external_id`. **Example payload:** ```json theme={null} { "id": "export_completed_00000000-0000-0000-0000-000000000006", "type": "export.completed", "data": { "export_id": "00000000-0000-0000-0000-000000000006", "business_id": null, "export_type": "billing_report", "status": "completed", "error": null } } ``` * `export.completed` * `export.failed` After `export.completed`, call [Fetch export](/api-reference/v1/fetch-export) to retrieve the `download_url`. # Asset object Source: https://docs.layerfi.com/api-reference/asset/asset An Asset represents a fixed asset a Business owns: such as a vehicle, a piece of equipment, a right-of-use asset, or goodwill. Creating an asset opens a dedicated ledger account for it (under Fixed Assets by default), so its value and any changes flow through the Business's books. Once an asset exists, you record changes to its carrying value over time with **value updates**: depreciation, improvements, impairments, and revaluations. See the [Asset Value Update object](#asset-value-update-object). If the asset already had value before you started tracking it in Layer, set an **opening balance**: a starting value recorded against Opening Balance Equity as of a specific date, rather than built up from value updates. Set it when you [create the asset](/api-reference/v1/assets/create-asset), and replace or clear it later with [Update an asset](/api-reference/v1/assets/update-asset). Assets can also be tied to a loan: an `ASSET` loan proceed can create or link an asset that the loan financed. See [Create a loan](/api-reference/v1/loans/create-loan). ### Attributes Unique identifier for the asset. ID of the Business that owns the asset. Unique ID of the asset in your system for linking purposes. Name of the asset. The type of fixed asset. Values can be: `RIGHT_OF_USE_ASSET`, `VEHICLE`, `EQUIPMENT`, `GOODWILL` The dedicated ledger account for this asset. The accumulated depreciation account for this asset, if configured. Required before recording `DEPRECIATION_AMORTIZATION` value updates. Original purchase value, in cents. Estimated salvage (residual) value, in cents. Useful life of the asset, in months. The asset's opening balance, if one is set. Contains `balance` (in cents) and `effective_at`. When the asset was archived, if applicable. Internal note about the asset. Arbitrary JSON object you can attach for your own use. Layer stores and returns it unchanged. Reference number for the asset. Tags applied to this asset. ## Asset Value Update object An Asset Value Update is a recorded change to an asset's carrying value. Each update posts a journal entry between the asset (or its accumulated depreciation account) and a counter account. `DEPRECIATION_AMORTIZATION`, `IMPAIRMENT`, and `REVALUATION_DOWN` decrease the asset's value; `IMPROVEMENT` and `REVALUATION_UP` increase it. Depreciation requires the asset to have an `accumulated_depreciation_account` configured. ### Attributes Unique identifier for the value update. ID of the Business that owns the asset. Unique ID of the value update in your system for linking purposes. ID of the asset this value update applies to. Amount of the value change, in cents. The kind of value change. Values can be: `DEPRECIATION_AMORTIZATION`, `IMPROVEMENT`, `IMPAIRMENT`, `REVALUATION_UP`, `REVALUATION_DOWN` Date of the value update. When the value update was archived, if applicable. Internal note about the value update. Arbitrary JSON object you can attach for your own use. Reference number for the value update. Tags applied to this value update. # Bank Transaction object Source: https://docs.layerfi.com/api-reference/bank-transaction/bank-transaction Bank transactions are transactions that have occurred within a bank account owned by a business. ### Attributes Unique identifier for the bank transaction. Unique ID of the bank transaction in your system for linking purposes. **Idempotency key.** Resource type. Value will be "Bank\_Transaction". ID for the Business this transaction belongs to. The source that the bank transaction was imported from. Values can be: `UNIT`, `PLAID`, `API` Unique ID of the bank transaction in its source system. **Idempotency key.** ID of the source account in the source system. Date the transaction occurred. The direction of the transaction relative to the source account. Values can be: `CREDIT`, `DEBIT` The amount of the transaction in cents. The name of the merchant or counterparty associated with the transaction. Description of the transaction. The type of bank account transaction. Example values: `PURCHASE`, `BOOK`, `ATM`, `WIRE`, etc. The status of the transaction's categorization in Layer's systems. Values can be: `PENDING`, `READY_FOR_INPUT`, `CATEGORIZED`, `LAYER_REVIEW` The category assigned to the transaction. Only populated for transactions that have a finalized category. String enum for the category assigned to the transaction. The set of category enums will vary based on chart of account configured for the business. A human-readable string describing the category. This can be presented to the end user in your UI. Tax code applied to the transaction's categorization. Currently only supported for businesses incorporated in Canada (`country` is `CA`). See `tax_options` below for the codes valid for this transaction's date, and [Categorize a Transaction](/api-reference/v1/categorize-bank-transaction#tax-code) for how to set it. Tax codes available for categorizing this transaction, scoped to the business's country and the transaction's date. Currently only populated for businesses incorporated in Canada (`country` is `CA`); `null` otherwise. Available Canada Revenue Agency tax codes for this transaction's date. The value to send in `tax_code` when categorizing. Human-readable, locale-aware name for the tax code. Values can be: `TAXABLE`, `EXEMPT`, `ZERO_RATED`, `OUT_OF_SCOPE`. The Canadian province this tax code applies to, if province-specific (e.g. `BRITISH_COLUMBIA`, `ONTARIO`, `QUEBEC`). Sum of all component rates for this tax code, as a percentage. Date this tax code became effective, if bounded. Last date this tax code is effective, if bounded. Tax components (e.g. GST, PST) that make up this tax code. Identifier for this tax component. Values can be: `GST`, `HST`, `PST`, `QST`. The Canadian province this component applies to, if any. Rate for this component, as a percentage. Whether this tax component is recoverable (e.g. as an input tax credit). Optional rule suggestion returned after categorization when Layer recommends creating a reusable categorization rule. If no suggestion is available, this field is `null`. See [Categorization Rule Suggestions](/guides/transaction-categorization/rules-suggestion) for more details. Suggestion type. Value will be `Create_Categorization_Rule_For_Counterparty`. Unique identifier for this suggestion. Use this ID for tracking suggestion state and rejecting a suggestion. Timestamp when the suggestion was created. Suggestion status. Values can be: `PENDING`, `ACCEPTED`, `REJECTED`. Counterparty associated with the suggestion. UI-ready prompt text to display when asking a user whether to create the suggested rule. Prebuilt payload that can be sent to [Create Categorization Rule](/api-reference/v1/categorization-rules/create-categorization-rule) (this is how suggestions are accepted). Whether to apply the rule to existing uncategorized transactions. Suggestion ID used to create this rule. Counterparty filter for the rule. Rule category identifier. Direction filter. Values can be: `DEBIT`, `CREDIT`. Preview list of transactions affected by the suggested rule. The suggested matches for the transaction. See [Match Bank Transaction](/api-reference/v1/match-bank-transaction) for more details. The unique identifier for the suggested match. Can be used to [match a bank transaction](/api-reference/v1/match-bank-transaction). The type of suggested match. Options include `Transfer_Match`, `Invoice_Match`, `Payout_Match`, and `Journal_Entry_Match`. The details of the suggested match. The type of the details object based off the matchable target. Options include `TRANSFER`, `INVOICE_PAYMENT`, `PAYOUT`, and `MANUAL_JOURNAL_ENTRY`. The unique identifier of the matchable target (e.g., invoice payment ID). The amount involved in the match, in cents. The date of the target of the suggested match in ISO8601 format. A description of the suggested match. ```json Example theme={null} { "id":"67cee0d8-3b8e-4b4b-a857-78ce3bb1d895", "type":"Bank_Transaction", "transaction_type":"Purchase", "business_id":"cfee5365-dcc3-425e-b403-cc9568f7121e", "source":"API", "source_transaction_id":"11111113", "source_account_id":"111113", "imported_at":"2023-06-07T00:42:08.664543Z", "date":"2023-05-15T14:13:07Z", "direction":"Debit", "amount":8026, "counterparty_name":"SUNOCO", "description":null, "categorization_status":"CATEGORIZED", "category":{ "category":"FUEL", "display_name":"Fuel" }, "update_categorization_rules_suggestion": { "type": "Create_Categorization_Rule_For_Counterparty", "id": "b3488b6a-c7b4-4d2a-a8c7-7d15f9942ed4", "created_at": "2025-02-14T17:22:01Z", "status": "PENDING", "counterparty": { "id": "f1664961-43d8-42f1-9a6d-c6c32a9f0adf", "name": "SUNOCO" }, "suggestion_prompt": "Would you like to create a rule for outbound SUNOCO transactions?", "new_rule": { "apply_retroactively": true, "created_by_suggestion_id": "b3488b6a-c7b4-4d2a-a8c7-7d15f9942ed4", "counterparty_filter": "f1664961-43d8-42f1-9a6d-c6c32a9f0adf", "category": { "type": "StableName", "stable_name": "FUEL" }, "bank_direction_filter": "MONEY_OUT" }, "transactions_that_will_be_affected": [] }, "suggested_matches": [ { "id": "cf33f1b6-ac18-480e-ab58-82aab4ab86f4", "matchType": "INVOICE_PAYMENT", "details": { "type": "Invoice_Match", "id": "0cfb7d11-874a-4c15-a9f9-875c21d95c86", "amount": 8026, "date": "2023-05-16T10:12:09Z", "description": "Invoice payment from FakeCustomer" } } ], } ``` # Download Transactions CSV Source: https://docs.layerfi.com/api-reference/bank-transaction/download-csv GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/transactions/exports/csv This endpoint generates a pre-signed AWS S3 URL for a CSV file with transactions. ID of the Business to download the transactions CSV for. The start date for the transactions in ISO-8601 format. Defaults to the business activation date. The end date for the transactions in ISO-8601 format. Defaults to the current date. Filter transactions based on whether they are categorized. Filter transactions based on a specific category. Filter transactions based on their categorization status. Must be one of: `CATEGORIZED`, `UNCATEGORIZED`, `PENDING`. ### Response Returns a pre-signed AWS S3 URL for the list of [Bank Transaction Objects](/api-reference/bank-transaction/bank-transaction) as a CSV. ```bash Request theme={null} curl -X GET 'https://sandbox.layerfi.com/v1/businesses/f9baa8fd-9413-4bcf-810b-6d32604de649/reports/transactions/exports/csv?start_date=2023-01-01T00:00:00-04:00&end_date=2024-01-01T00:00:00-04:00&categorized=true' \ -H 'Authorization: Bearer ' ``` ```json Response theme={null} { "data":{ "type":"S3_Presigned_Url", "presignedUrl": "https://example-bucket.s3.amazonaws.com/example-object?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=FAKEAWSACCESSKEY%2F20240710%2Fus-west-1%2Fs3%2Faws4_request&X-Amz-Date=20240710T000000Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=FAKESIGNATURE1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "fileType": "csv" } } ``` # Fetch bill Source: https://docs.layerfi.com/api-reference/bill/bill get /v1/businesses/{businessId}/bills/{billId} Returns the bill associated with the provided bill id. A bill represents an invoice or purchase order a business has received from a vendor for goods or services, and is used to track purchases and accounts payable in Layer. # Expense object Source: https://docs.layerfi.com/api-reference/bill/expense An expense is a type of bill for a purchase paid at the time of the transaction, such as a card purchase, cash purchase, or check written at the point of sale. Use expenses when you want to record the purchase and the payment together. Expenses are created with `is_expense: true`, `status: PAID`, and a payment for the full amount. ## When to use expenses Use an **expense** for purchases that are paid immediately. The [Create expense](/api-reference/v1/create-expense) endpoint accepts the purchase details, the `paid_at` timestamp, and the payment details in one request. Use a **standard bill** when you need to track accounts payable over time. For example, use a bill for a vendor invoice received today that will be paid later. Standard bills have `is_expense: false` and support payment terms, partial payments, and an outstanding balance. ## API behavior | Task | Expense | Standard bill | | - | - | - | | Create | `POST /v1/businesses/{businessId}/expenses` | `POST /v1/businesses/{businessId}/bills` | | Initial status | `PAID` | `RECEIVED`, `PARTIALLY_PAID`, or `PAID` | | Payment | Included at creation | Optional at creation; can be added later | | List | [List expenses](/api-reference/v1/list-expenses) with `is_expense=true` | [List bills](/api-reference/v1/list-bills) with `is_expense=false` | ## Common workflow 1. [Create expense](/api-reference/v1/create-expense) with purchase, vendor, line item, and payment details. The request is idempotent via `external_id`. 2. [List expenses](/api-reference/v1/list-expenses) with `is_expense=true` when you need a collection of expenses. 3. [Fetch expense](/api-reference/v1/fetch-expense) with the expense `id` when you need one record. 4. Match the expense payment to a bank transaction when Layer suggests a match. ## Payment defaults If both `payment.method` and `payment.payment_clearing_account_identifier` are omitted when creating an expense: * `payment.method` defaults to `ACH`. * `payment.payment_clearing_account_identifier` defaults to the Contributions account until the expense is matched to a bank transaction. If you specify `payment.method` and omit `payment.payment_clearing_account_identifier`, no default clearing account is applied. # Bill payment object Source: https://docs.layerfi.com/api-reference/bill/payments Bill payments represent payments made by a business to vendors. Payments may be made at any time and applied to one or more outstanding (received, but not fully paid) bills. ### Attributes Unique identifier for the payment. Unique ID of the bill payment in your system for linking and idempotency. The [vendor](/api-reference/vendor/vendor) associated with this payment, if one has been set. You can tag a payment with a vendor before it is allocated to any bill (for example, a standalone deposit). Once the payment has bill allocations, the vendor must match the vendor on every allocated bill. Timestamp when the payment was completed. Payment method. Possible values are: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Payment amount, in cents. Processor used to make the payment, if any. Any processor name can be provided and will be tracked. Timestamp when the payment was imported into Layer. Bill allocations allow specifying a payment to be for multiple bills. Most commonly the full payment will be allocated to a single bill, but any number of allocations are allowed. The sum of all allocations must be equal to the payment amount. Unique identifier for the allocation. ID of a bill to which this payment is applied. ID of the payment this allocation applies from. Payment amount allocated to this bill, in cents. Transaction tags refer to tags associated with this bill payment allocation. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Transaction tags refer to tags associated with this bill. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Memo for any text you would like to associate with the bill payment (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the bill payment. Can be used to filter when listing bill payments. ```json Response theme={null} { "data": { "id": "590ed436-c2bd-4e39-8047-f913a852f99c", "external_id": "bill-payment-1", "vendor": { "type": "VendorData", "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "vendor-1", "individual_name": "Jane Smith", "company_name": "Acme Supplies", "email": "ap@acmesupplies.com" }, "at": "2024-06-15T00:00:00Z", "method": "ACH", "amount": 10000, "processor": "BANK_TRANSFER", "imported_at": "2024-06-15T18:11:57.339076Z", "allocations": [ { "id": "8901-abcd-ef23-4567", "bill_id": "b745c116-cd28-41a1-b4ea-84a2768b6e14", "payment_id": "590ed436-c2bd-4e39-8047-f913a852f99c", "amount": 10000, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } ], "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Retrieve Notifications Source: https://docs.layerfi.com/api-reference/business/notifications GET https://sandbox.layerfi.com/v1/businesses/{business_id}/notifications Retrieve counts of outstanding transactions, tasks, or other items that require user attention. ### Path Parameters ID of the Business to retrieve notifications for. ### Response Returns a Business Notifications Object Number of bank transactions from the current month that have not been categorized. Number of bank transactions that require categorization dating back to the business's activation date. Number of tasks that require user attention. Only applicable to businesses enrolled in bookkeeping services. Number of linked account connections that require re-linking or fixing. Amount of refund received by customer. ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/notifications \ -H "Authorization: Bearer " ``` ```json Response theme={null} { "data": { "type": "Business_Notifications", "uncategorized_transactions_this_month": 1, "uncategorized_transactions_all_time": 7, "todo_tasks": 1, "external_accounts_requiring_update": 0 }, "meta": {} } ``` # Custom journal entry object Source: https://docs.layerfi.com/api-reference/custom-journal-entries/custom-journal-entry A Custom Journal Entry represents a [journal entry](/api-reference/ledger/chart#journal-entry-object) that is manually created by your system to reflect an accounting activity. Custom Journal Entries can be used to reflect any kind of accounting activity that isn't reflected in Layer's standard (Accounts Receivable / Accounts Payable / Bank Transactions / etc) workflows. Note that Custom Journal Entries contain metadata about a journal entry and are not journal entries in and of themselves. ### Attributes Unique identifier for the custom journal entry (the domain object, as opposed to the underlying ledger-layer journal entry). Resource type. Value will be "Custom\_Journal\_Entry". Unique ID of the custom journal entry in your system for linking purposes and idempotency. ID of the Business that generated the custom journal entry. Identifier of the user or system that created the journal entry. ID of the underlying ledger entry. The [Customer Object](/api-reference/customer/customer) associated with this journal entry, if any. The [Vendor Object](/api-reference/vendor/vendor) associated with this journal entry, if any. Line items making up the custom journal entry. Array of [Custom Journal Entry Line Items](/api-reference/custom-journal-entries/custom-journal-entry#custom-journal-entry-line-item-object) comprising the Journal Entry. The [Journal Entry Object](/api-reference/ledger/chart#journal-entry-object) associated with this Custom Journal Entry. Tags associated with the custom journal entry. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the bill (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the bill. Can be used to filter when listing bills. #### Custom Journal Entry Line Item object A domain-level object that stores additional metadata about one of the line items of the underlying journal entry Unique identifier for the line item. External ID of the line item in your system. Optional memo for the line item. ID of the line item in the ledger. ```json Response theme={null} { "data": { "type": "Custom_Journal_Entry", "id": "c635d706-bf18-41a1-b4ea-83a4768b6e14", "business_id": "188eb399-f171-4849-861c-5c02d91f800b", "external_id": "journal-entry-1", "created_by": "user-123", "memo": "Q1 Adjustment for Deferred Revenue", "entry_id": "695f6e4f-ddbb-4930-98cc-6496cd719a11", "customer": { "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "customer-1", "individual_name": null, "company_name": "Acme Corp", "email": "billing@acme.com", "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE" }, "vendor": null, "line_items": [ { "id": "733de30f-db72-4d52-98c5-fe070d4433f7", "external_id": "journal-line-item-1", "memo": "Deferred revenue recognition", "account_identifier": { "type": "AccountId", "id": "80b708b5-7b27-456c-9fb1-b8b918241908" }, "amount": 100000, "direction": "DEBIT", "line_item_id": "ledger-line-item-789" }, { "id": "854fe31f-ec73-5e63-09d6-gf171e5544g8", "external_id": "journal-line-item-2", "memo": "Revenue recognition", "account_identifier": { "type": "AccountId", "id": "90c819c6-8c38-567d-0gb2-c9c029352a19" }, "amount": 100000, "direction": "CREDIT", "line_item_id": "ledger-line-item-790" } ], "entry": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "business_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledger_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "agent": "API", "entry_type": "BANK", "date": "2023-11-07T05:31:56Z", "entry_at": "2023-11-07T05:31:56Z", "reversal_of_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "reversal_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "line_items": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "entry_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "account": { "id": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "name": "Current Assets", "stable_name": { "type": "StableName", "stable_name": "CURRENT_ASSETS" }, "normality": "CREDIT", "account_type": { "value": "ASSET", "display_name": "Asset" }, "account_subtype": { "value": "CURRENT", "display_name": "Current Assets" } }, "amount": 123, "direction": "CREDIT", "entry_at": "2023-11-07T05:31:56Z", "createdAt": "2023-11-07T05:31:56Z" } ] }, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Customer credit object Source: https://docs.layerfi.com/api-reference/customer-credits/customer-credit A Customer Credit represents a transaction that reduces accounts payable to a customer, typically due to returned goods. Each customer credit has one or more line items specifying debited revenue accounts, and zero or more allocations applying portions of the credit to invoices. ### Attributes Unique identifier for the customer credit. Unique ID of the customer credit in your system for linking purposes. **Idempotency key**. The [Customer](/api-reference/customer/customer) associated with this credit. Time when the customer credit was sent. Line items included in this customer credit. See [Customer Credit Line Item Object](#customer-credit-line-item-object) for details. Allocations of this customer credit to invoices. See [Customer Credit Allocation Object](#customer-credit-allocation-object) for details. Time when the customer credit was created in Layer. Time when the customer credit was last updated in Layer. Time when the customer credit was deleted, if applicable. Tags associated with the customer credit. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the customer credit (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the customer credit. Can be used to filter when listing customer credits. ### Customer Credit Line Item Object A Customer Credit Line Item represents an individual revenue account being credited by the Customer Credit. Unique identifier for the customer credit line item. [Ledger account](/api-reference/ledger/chart#ledger-account-object) associated with this line item. This is what you're specifying with the 'revenue\_account\_identifier' in the create parameters. Amount for the line item in cents. Description or notes for the line item. Arbitrary metadata you can include with the customer credit line item ### Customer Credit Allocation Object A Customer Credit Allocation represents how a portion of a customer credit is applied to a specific invoice. By allocating customer credits to invoices, the amount owed to customers can be reduced accordingly. Unique identifier for the customer credit allocation. ID of the customer credit this allocation belongs to. ID of the invoice this allocation is for. Amount of the allocation in cents. ```json Response theme={null} { "data": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "vc001", "customer": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "abc123", "individual_name": null, "company_name": "Widgets & Co", "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] }, "sent_at": "2023-11-07T05:31:56Z", "line_items": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledger_account": { "id": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "name": "Sales", "stable_name": { "type": "StableName", "stable_name": "SALES" }, "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "SALES", "display_name": "Sales" } }, "amount": 123, "memo": null } ], "allocations": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customer_credit_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 123 } ], "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": null } } ``` # Payout object Source: https://docs.layerfi.com/api-reference/customer-payouts/payout A Payout represents a transfer of funds from a payment processor or platform to a Business. Payouts typically include the net amount of payments collected on behalf of the business, minus any fees, and are used to reconcile platform balances with bank deposits. If you import Stripe instant payouts, see [Stripe Instant Payouts](/guides/importing-sales-ar-data#stripe-instant-payouts) for the recommended flow. ### Attributes Unique identifier for the payout. Unique ID of the payout in your system for linking purposes and idempotency. ID of the Business that received the payout. The amount of the payout, in cents. The platform fee associated with the payout, in cents. Processor used to make the payment. Any processor name can be provided and will be tracked. If not null, every payment or refund associated with the payout must have the same processor. Timestamp of when the payout was imported into Layer. Timestamp of when the payout was completed. The transaction match associated with the payout, if any. A list of [Invoice Payments](/api-reference/invoice/payments) associated with the payout. List of [Refunds](/api-reference/refunds/refund) associated with this payout. List of [Loan Payments](/api-reference/loan/loan#loan-payment-object) associated with this payout. Tags associated with the payout. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the payout (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the payout. Can be used to filter when listing payouts. ```json Response theme={null} { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "payout-1234", "business_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paid_out_amount": 123, "fee": 123, "processor": "STRIPE", "imported_at": "2023-11-07T05:31:56Z", "completed_at": "2023-11-07T05:31:56Z", "match": { "id": "6b0a3734-f4ef-4fb0-9fc1-3f59b0c1cf99", "match_type": "PAYOUT", "bank_transaction": { "type": "Bank_Transaction_Data", "id": "a703c8d6-cfe8-453d-a275-b92eacc6fc6e", "business_id": "738ec216-e8e5-48f2-b7f2-cdc89c96b3d4", "source": "STRIPE", "source_transaction_id": "trxn_1sdOeLQiFAKE2LQBkcvrJw95f", "source_account_id": "738ec216-e154-48f2-1111-cdc89c96b3d4", "imported_at": "2024-03-19T22:09:53.290591Z", "date": "2024-03-06T06:06:40Z", "direction": "CREDIT", "amount": 87459, "counterparty_name": null, "description": "Payout (po_1OqnTHISISFAKEiTVBkCiyAERwm)", "account_name": "Layer Banking", "categorization_status": "MATCHED" }, "details": { "type": "Payout_Match", "id": "d224508b-b05e-41da-89de-0fbd8a573507", "amount": 87459, "date": "2024-03-06T00:00:00Z", "description": "Payout from STRIPE", "adjustment": null } }, "suggested_matches": [ { "id": "f81ca739-7931-475e-b88f-c2b324523f3a", "matchType": "PAYOUT", "details": { "type": "Payout_Match", "id": "d224508b-b05e-41da-89de-0fbd8a573507", "amount": 87459, "date": "2024-03-06T00:00:00Z", "description": "Payout from STRIPE", "adjustment": null } } ] "payments": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "payment-1", "at": "2023-11-07T05:31:56Z", "method": "CASH", "fee": 123, "additional_fees": [ { "fee_amount": 123, "description": "", "account": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } } ], "amount": 123, "processor": "STRIPE", "imported_at": "2023-11-07T05:31:56Z", "allocations": [ { "invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "payment_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 123, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } ], "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } ], "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": {} } ``` # Archive a customer Source: https://docs.layerfi.com/api-reference/customer/archive-customer POST https://sandbox.layerfi.com/v1/businesses/{business_id}/customers/{customer_id}/archive Archive a customer, hiding them from the business's active customer list. Archiving a customer hides them from the business's active customer list, returned by the [List customers](/api-reference/invoice/list-customers) endpoint. Archived customers can still be accessed by ID, but are not returned in list requests by default. Archived customers will have all A/R and Liability balances retained and all invoices will remain. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ID of the [Customer](/api-reference/invoice/customer) to be archived. ### Response Returns the archived [Customer object](/api-reference/invoice/customer) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/${business_id}/customers/${customer_id}/archive \ -H "Authorization: Bearer " \ ``` ```json Response theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ARCHIVED", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Create a customer Source: https://docs.layerfi.com/api-reference/customer/create-customer POST https://sandbox.layerfi.com/v1/businesses/{business_id}/customers Create a new customer within Layer. This endpoint is idempotent using the `external_id` field. If a customer with the same `external_id` already exists, the existing customer will be updated and returned. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ### Body External ID for the customer within your platform. **Idempotency key.** Name of the individual customer. Name of the company customer. Email address of the customer. Mobile phone number of the customer. Office phone number of the customer. Full address of the customer. Notes about the customer. The new tag's key The new tag's value ### Response Returns the created [Customer object](/api-reference/invoice/customer) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/${business_id}/customers \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note" }' ``` ```json 200 (Updated) theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` ```json 201 (Created) theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Customer object Source: https://docs.layerfi.com/api-reference/customer/customer A Customer of a business can receive invoices and refunds and have payments applied to their invoices. Customers can be referenced when creating invoices and refunds using either the Layer `id`, or the `external id`. ### Attributes Unique identifier for the customer. Unique ID of the customer in your system for linking and idempotency. Full name of the individual customer or contact at a corporate customer. Name of the company customer. Email address of the customer. Mobile phone number of the customer. Office phone number of the customer. Full address of the customer. Status of the customer. Possible values are: `ACTIVE`, `ARCHIVED` Archived customers will not appear when listing customers, but their accounting continues to be tracked and they can still be retrieved directly in the API. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the customer (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the customer. Can be used to filter when listing customers. ```json Response theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Get a customer Source: https://docs.layerfi.com/api-reference/customer/get-customer GET https://sandbox.layerfi.com/v1/businesses/{business_id}/customers/{customer_id} Get an existing customer within Layer. Fetch a single specific customer by ID. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ID of the [Customer](/api-reference/invoice/customer) to be updated. This is the Layer id, not the external id. ### Response Returns the created [Customer object](/api-reference/invoice/customer) ```bash Request theme={null} curl -X GET https://sandbox.layerfi.com/v1/businesses/${business_id}/customers/${customer_id} \ -H "Authorization: Bearer " \ ``` ```json Response theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # List customers Source: https://docs.layerfi.com/api-reference/customer/list-customers GET https://sandbox.layerfi.com/v1/businesses/{business_id}/customers List all customers within Layer. The `GET` endpoint lists all created customers within Layer. Only active customers are returned by default, but archived customers can be included via the `include_archived` flag. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ### Query Parameters Include archived customers in the response. Defaults to false. The external ID of the customer to fetch. A case-insensitive substring used to filter customers whose external ID contains the specified value. The name of the customers to fetch. A case-insensitive substring used to filter customers whose name contains the specified value. ### Response Returns a list of [Customer objects](/api-reference/invoice/customer) ```bash Request theme={null} curl -X GET https://sandbox.layerfi.com/v1/businesses/${business_id}/customers/ \ -H "Authorization: Bearer " \ ``` ```json Response theme={null} { "data": [ { "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note" }, { "external_id": "customer-2", "individual_name": "Jane Doe", "company_name": "MegaCorp", "email": "jane@hotmail.com" } ] } ``` # Unarchive a customer Source: https://docs.layerfi.com/api-reference/customer/unarchive-customer POST https://sandbox.layerfi.com/v1/businesses/{business_id}/customers/{customer_id}/unarchive Unarchive a customer, making them visible in the business's active customer list. Archiving a customer hides them from the business's active customer list, returned by the [List customers](/api-reference/invoice/list-customers) endpoint. Unarchiving reverses that affect. As with archiving, the GL is unaffected by the status of the customer and all A/R and Liability balances are retained. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ID of the [Customer](/api-reference/invoice/customer) to be unarchived. ### Response Returns the unarchived [Customer object](/api-reference/invoice/customer) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/${business_id}/customers/${customer_id}/unarchive \ -H "Authorization: Bearer " \ ``` ```json Response theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` # Update a customer Source: https://docs.layerfi.com/api-reference/customer/update-customer PUT https://sandbox.layerfi.com/v1/businesses/{business_id}/customers/{customer_id} Update an existing customer within Layer. The `PUT` endpoint updates an existing customer. ### Path Parameters ID of the [Business](/api-reference/business/business) the customer is associated with. ID of the [Customer](/api-reference/invoice/customer) to be updated. ### Body External ID for the customer within your platform. **Idempotency key.** Name of the individual customer. Name of the company customer. Email address of the customer. Mobile phone number of the customer. Office phone number of the customer. Full address of the customer. Notes about the customer. The new tag's key The new tag's value ### Response Returns the updated [Customer object](/api-reference/invoice/customer) ```bash Request theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/${business_id}/customers/${customer_id} \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note" }' ``` ```json Response theme={null} { "data": { "type": "CustomerData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "customer-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [] } } ``` # Update transaction date range Source: https://docs.layerfi.com/api-reference/external-account/update-transaction-date-range put /v1/businesses/{businessId}/external-accounts/{externalAccountId}/transaction-date-range Updates the visible transaction date range for an external account. Use this endpoint to limit which transactions are shown from this account based on their date. When the date range is tightened (start date moved forward or end date moved backward), any categorized transactions that now fall outside the new bounds are automatically uncategorized. This ensures that hidden transactions don't contribute to financial reports. Set either field to `null` to remove that bound. For example, setting `show_transactions_on_or_after` to `null` will show all transactions after the business's activation_at date. # Create an Invoice Source: https://docs.layerfi.com/api-reference/invoice/create POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices This endpoint imports an invoice for a business into Layer. ### Path Parameters ID of the [Business](/api-reference/business/business) the invoice is associated with. ### Body External ID for the invoice within your platform. **Idempotency key.** When the invoice was sent by the business to the recipient. Accepts an ISO 8601 date (`YYYY-MM-DD`) or a full ISO 8601 timestamp. A date-only value is stored as midnight Eastern Time on that day. When the invoice is due. Accepts an ISO 8601 date (`YYYY-MM-DD`) or a full ISO 8601 timestamp. A date-only value is stored as midnight Eastern Time on that day. When the invoice was voided. Voiding excludes the invoice entirely from accounting. Number for the invoice for display to end-users. ID of the [Customer](/api-reference/invoice/customer) the invoice is associated with. Either the `customer_id` or the `customer_external_id` must be provided. External ID of the [Customer](/api-reference/invoice/customer) the invoice is associated with. Either the `customer_id` or the `customer_external_id` must be provided. A customer does not need to be created before creating an invoice. When you provide a customer external id, Layer will create a customer object with the provided external id if it does not already exist. Customer details can be updated later using the [Update a customer](/api-reference/invoice/update-customer) endpoint. Any text you would like to associate with the invoice (for example, to display to end users) Line items making up the invoice. The external ID of the invoice line item in your system. Description of the specific line item. The [Account Identifier](/api-reference/ledger/account-identifier) for the line item. If specified, the line item will be attributed to this specific account, typically a product or service revenue account. If not specified, the product name will be mapped to a revenue account based on the business or industry's accounting configuration. Reference to the product being sold. Number of units sold. The amount in cents of each unit. Total discount given to this line item, in cents. List of sales tax obligations on this line item. Total tax amount for this line item, in cents. This object can either be either a `Tax_Name` or an `AccountIdentifier` object. An [Account Identifier](/api-reference/ledger/account-identifier) can be used when a known specific ledger account is appropriate for a tax. A [Tax Name](/api-reference/types/tax-name) can be used to create and use tax categories dynamically. A second [Account Identifier](/api-reference/ledger/account-identifier) specifying that this is a prepayment, and which ledger account to use for accrual reporting. Tag key values associated with this invoice line item. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If not specified, `key` will be displayed. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value definition. If not specified, `value` will be displayed. Additional discount applied to the whole invoice in addition to individual line items. List of sales tax obligations on this line item. Total tax amount for this line item, in cents. This object can either be either a `Tax_Name` or an `AccountIdentifier` object. An [Account Identifier](/api-reference/ledger/account-identifier) can be used when a known specific ledger account is appropriate for a tax. A [Tax Name](/api-reference/types/tax-name) can be used to create and use tax categories dynamaically. Tips included by the buyer, in cents. The [Account Identifier](/api-reference/ledger/account-identifier) for a tips account. If not specified, tips will be attributed to the Chart of Account's default tips account, default a liability account. Alternate accounts can be specified in case tips should be tracked as revenue. Payments that have been made towards the balance of the invoice. External ID for the payment within your platform. **Idempotency key.** Method used to make the payment. Values can be: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Fee associated with processing a payment, e.g. credit card processing fees, in cents. Optional description of the fee. The [Account Identifier](/api-reference/ledger/account-identifier) for the fee to be debited. Amount of the fee in cents. Whether or not the fee is passed to the customer. It is paid by the business otherwise. Processor used to make the payment, if any. Any processor name can be provided and will be tracked. Value of the payment, in cents. If blank, this is assumed to be the entire total of the invoice. Tag key values associated with this invoice. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If not specified, `key` will be displayed. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value definition. If not specified, `value` will be displayed. Arbitrary metadata you can include with the invoice payment The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If not specified, `key` will be displayed. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value definition. If not specified, `value` will be displayed. Arbitrary metadata you can include with the invoice ### Response Returns the created [Invoice Object](/api-reference/invoice/invoice) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "019234", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "invoice_number": "1", "customer_external_id": "customer-john-doe", "line_items": [ { "external_id": "invoice-line-item-1", "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": 2, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ], "tags": [ { "key": "product-category", "dimension_display_name": "Product Category", "value": "test-value", "value_display_name": "test-display-name" } ] }, { "external_id": "invoice-line-item-2", "product": "Full drain cleaning service", "unit_price": 25000, "quantity": 1, "tags": [ { "key": "product-category", "dimension_display_name": "Product Category", "value": "test-value", "value_display_name": "test-display-name" }, { "key": "service-type", "value": "service-value" } ] } ], "additional_discount": 250, "payments": [ { "external_id": "payment-1", "amount": 27466, "method": "CREDIT_CARD", "processor": "STRIPE", "paid_at": "2024-04-02T09:02:00Z", "fee": 825, "tags": [ { "key": "payment-channel", "dimension_display_name": "Payment Channel", "value": "online", "value_display_name": "Online" }, { "key": "department", "value": "sales" } ] } ], "tags": [ { "key": "region", "dimension_display_name": "Region", "value": "west-coast", "value_display_name": "West Coast" }, { "key": "customer-segment", "value": "enterprise" } ] }' ``` ```json Response theme={null} { "data": { "type": "Invoice", "id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "external_id": "019234", "status": "SENT", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "paid_at": null, "voided_at": null, "invoice_number": "1", "customer": { "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "customer-1", "individual_name": null, "company_name": null, "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE" }, "line_items": [ { "id": "e6a491dd-9c22-4403-a54f-32d741a7ec67", "external_id": "invoice-line-item-1", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": "2.00", "subtotal": 2598, "discount_amount": 0, "sales_taxes_total": 218, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ], "total_amount": 2816 }, { "id": "44f06385-3ef5-4517-8095-eeedaf2054ab", "external_id": "invoice-line-item-2", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Full drain cleaning service", "unit_price": 25000, "quantity": "1.00", "subtotal": 25000, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 25000 } ], "subtotal": 27598, "additional_discount": 250, "additional_sales_taxes_total": 0, "tips": 0, "total_amount": 27566, "outstanding_balance": 27566, "payment_allocations": [], "imported_at": "2024-04-19T02:23:59.902537Z", "updated_at": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": {} } } ``` ## Optional: Create a Paid invoice You can specify an invoice as immediately paid by including `InvoicePayment` object(s) in the `payments` field of the invoice. This allows you to create and invoice and specify the full payment information in a single API call. This is equivalent to creating an invoice and then creating a payment fully allocated to that invoice. ### `InvoicePayment` parameters External ID for the invoice within your platform. **Idempotency key.** Method used to make the payment. Values can be: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Fee associated with processing a payment, e.g. credit card processing fees, in cents. Optional description of the fee. The [Account Identifier](/api-reference/ledger/account-identifier) for the fee to be debited. Amount of the fee in cents. Whether or not the fee is passed to the customer. It is paid by the business otherwise. Processor used to make the payment, if any. Any processor name can be provided and will be tracked. Value of the payment, in cents. If blank, this is assumed to be the entire total of the invoice. Tag key values associated with this invoice payment. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If not specified, `key` will be displayed. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value definition. If not specified, `value` will be displayed. ## Optional: Create refunds with the invoice This field can be specified when creating an invoice and any of its invoice line items or invoice payments List of [Dedicated Refunds](/api-reference/refunds/refund#create-dedicated-refund-parameters-object) to create with this payment # Delete an Invoice Source: https://docs.layerfi.com/api-reference/invoice/delete POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices/{invoice_id}/delete Deleting an invoice should only be used when an invoice was improperly created. Invoice deletion is not part of the normal account workflow. This functionality is provided in case an erroneous invoice creation. If you need to void (cancel) an outstanding invoice, use the [Void an Invoice](/api-reference/invoice/void) endpoint instead. Deletion of an invoice is only possible if the invoice has not been paid. Delete all payments made against the invoice before attempting to delete the invoice. ### Path Parameters Id of the [Business](/api-reference/business/business) the invoice is associated with. Id of the [Invoice](/api-reference/invoice/invoice) to be deleted. ### Response Returns the updated [Invoice Object](/api-reference/invoice/invoice) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices/${invoice_id}/delete \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ ``` The API will respond with the previous state of the now deleted invoice. ```json 200 theme={null} { "data": { "type": "Invoice", "id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "external_id": "019234", "status": "SENT", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "paid_at": null, "voided_at": null, "invoice_number": "1", "recipient_name": "John Doe", "line_items": [ { "id": "e6a491dd-9c22-4403-a54f-32d741a7ec67", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": "2.00", "subtotal": 2598, "discount_amount": 0, "sales_taxes_total": 218, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ], "total_amount": 2816, "transaction_tags": [ { "id": "b2c3d4e5-f6a7-8901-bcde-f1234567890a", "key": "product-category", "value": "cleaning-supplies", "dimension_display_name": "Product Category", "value_display_name": "Cleaning Supplies", "dimension_id": "e3f4a5b6-c7d8-9012-cdef-123456789012", "definition_id": "f4a5b6c7-d8e9-0123-def1-234567890123", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] }, { "id": "44f06385-3ef5-4517-8095-eeedaf2054ab", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Full drain cleaning service", "unit_price": 25000, "quantity": "1.00", "subtotal": 25000, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 25000, "transaction_tags": [] } ], "subtotal": 27598, "additional_discount": 250, "additional_sales_taxes_total": 0, "tips": 0, "total_amount": 27566, "outstanding_balance": 27566, "payment_allocations": [], "imported_at": "2024-04-19T02:23:59.902537Z", "updated_at": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` ```json 400 theme={null} { "errors": [ { "type": "Invalid State", "description": "Invoice 6d0c298f-3e4e-4538-9a71-1d5359c22f71 cannot be deleted, there are still valid payments associated with it. Delete these first." } ] } ``` # Delete a Payment Source: https://docs.layerfi.com/api-reference/invoice/delete-payment POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices/payments/{payment_id}/delete Deleting a payment should be used when a payment was improperly created. This functionality is for use in case of erroneous payment creation. Prefer updating existing payments if the payment details have changed. ### Path Parameters Id of the [Business](/api-reference/business/business) the payment is associated with. Id of the [Payment](/api-reference/invoice/payments) to be deleted. ### Response Returns the updated [Payment Object](/api-reference/invoice/payments) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/payments/${payment_id}/delete \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ ``` The API will respond with the previous state of the now deleted payment. ```json Response theme={null} { "data": { "type": "Payment", "id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "external_id": "payment-1", "at": "2024-02-27T02:16:40.369432Z", "method": "CREDIT_CARD", "fee": 20, "amount": 90, "processor": "STRIPE", "imported_at": "2024-02-27T02:16:40.389772Z", "allocations": [ { "invoice_id": "57f0fada-bb56-4f3e-9afa-2a222b68009e", "payment_id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "amount": 90, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } ], "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] }, "meta": {} } ``` # Invoice object Source: https://docs.layerfi.com/api-reference/invoice/invoice An Invoice represents an invoice that a Business has collected for goods and services provided. Invoices are used to pass information about sales and accounts receivable into Layer. ### Attributes Unique identifier for the invoice. Resource type. Value will be "Invoice". Unique ID of the invoice in your system for linking purposes. ID of the Business that generated the invoice. Status of the invoice. Values can be: `SENT`, `PARTIALLY_PAID`, `PAID`, `VOIDED`, `PARTIALLY_WRITTEN_OFF`, `WRITTEN_OFF`, `REFUNDED` When the invoice was sent by the business to the recipient. When the invoice is due. When the invoice was paid. When the invoice was voided. Voiding excludes the invoice from accounting. Number for the invoice for display to end-users. List of [Refund Allocations](/api-reference/refunds/refund#refund-allocation-object) associated with this invoice. [Customer](/api-reference/customer/customer) object associated with the invoice. Line items making up the invoice. ID of the invoice line item. The external ID of the invoice line item in your system. ID of the parent invoice Description of the specific line item. Reference to the product being sold. Number of units sold. The amount in cents of each unit. Total discount given to this line item, in cents. List of [Refund Allocations](/api-reference/refunds/refund#refund-allocation-object) associated with this line item. Ledger account associated with this tax. Type of tax account object. Name of the tax account, if a name was specified when this line item was created. ID of the tax account if either an account ID was used to create the tax line item or if no tax account was specified. Amount, in cents, of tax owed. Total discount given to this line item, in cents. A second [Account Identifier](/api-reference/ledger/account-identifier) specifying that this is a prepayment, and which ledger account to use for accrual reporting. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Subtotal of all invoice line items in cents. Additional discount applied to the whole invoice in addition to individual line items. Sum of all discount amounts across the invoice line items and any additional discounts in cents. Ledger account associated with this tax. Type of tax account object. Name of the tax account, if a name was specified when this line item was created. ID of the tax account if either an account ID was used to create the tax line item or if no tax account was specified. Amount, in cents, of tax owed. Sum of all taxes across the invoice line items and any additional taxes in cents. Tips included by the buyer, in cents. The [Account Identifier](/api-reference/ledger/account-identifier) for a tips account. If not specified, tips will be attributed to the Chart of Account's default tips account, default a liability account. Alternate accounts can be specified in case tips should be tracked as revenue. Total amount of the invoice in cents. The remaining balance on the invoice after factoring in all previous invoice payments and write-offs. Memo for any text you would like to associate with the invoice (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the invoice. Can be used to filter when listing invoices. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Payments made by a customer are allocated toward one or many invoices. This list shows which payments have been been allocated towards this invoice. The most common case is that there is a 1:1 relationship between a payment and an invoice, in which case the allocation's `amount` will match the payment's `amount`. ID of the invoice. ID of the payment. Amount of the payment allocated towards this invoice. If this amount is the full payment amount, this payment was fully allocated towards this invoice. The amount cannot exceed the invoice total. The [Invoice Payment](/api-reference/invoice/payments) that was allocated towards this invoice. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Write-offs applied to the invoice. See the [Write-Off object](/api-reference/v1/fetch-write-off) for more information. Unique identifier for the write-off. Unique identifier for the invoice the write-off is for. Unique ID of the write-off in your system for linking and idempotency. The amount written off. This amount counts towards the invoice total and decreases the outstanding balance of the invoice. User-specified memo indicating the reason for the write-off. Expense account where write off amount is recorded. Timestamp when the write off should be recognized in the general ledger. This may be the same time as the invoice was created if it is an intentional charitable contribution or it could be months after the invoice is issued when that invoice is deemed uncollectible. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Arbitrary metadata you can include with the invoice Time when the invoice was first imported into Layer. **Eligible sort key.** Time when the invoice was last updated in Layer. **Eligible sort key.** ```json Response theme={null} { "data": { "type": "Invoice", "id": "c635d706-bf18-41a1-b4ea-83a4768b6e14", "business_id": "188eb399-f171-4849-861c-5c02d91f800b", "external_id": "1", "status": "PARTIALLY_PAID", "sent_at": "2024-06-04T18:11:57.184157Z", "due_at": "2024-06-05T18:11:57.184158Z", "paid_at": null, "voided_at": null, "invoice_number": "1", "memo": "Memo for the invoice", "customer": { "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "customer-1", "individual_name": null, "company_name": null, "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE" }, "line_items": [ { "id": "733de30f-db72-4d52-98c5-fe070d4433f7", "external_id": "invoice-line-item-1", "invoice_id": "c635d706-bf18-41a1-b4ea-83a4768b6e14", "account_identifier": { "type": "AccountId", "id": "80b708b5-7b27-456c-9fb1-b8b918241908" }, "description": "my test description", "product": "test line item", "unit_price": 50, "quantity": "2.00", "subtotal": 100, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 100, "refund_allocations": [], "transaction_tags": [ { "id": "b2c3d4e5-f6a7-8901-bcde-f1234567890a", "key": "product-category", "value": "cleaning-supplies", "dimension_display_name": "Product Category", "value_display_name": "Cleaning Supplies", "dimension_id": "e3f4a5b6-c7d8-9012-cdef-123456789012", "definition_id": "f4a5b6c7-d8e9-0123-def1-234567890123", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } ], "subtotal": 100, "additional_discount": 0, "additional_sales_taxes": [], "additional_sales_taxes_total": 0, "tips": 0, "tips_account": null, "total_amount": 100, "outstanding_balance": 10, "payment_allocations": [ { "invoice_id": "c635d706-bf18-41a1-b4ea-83a4768b6e14", "payment_id": "590ed436-c2bd-4e39-8047-f913a852f99c", "amount": 90, "payment": { "id": "590ed436-c2bd-4e39-8047-f913a852f99c", "external_id": "payment-1", "at": "2024-01-01T00:00:00Z", "method": "CREDIT_CARD", "fee": 20, "additional_fees": [], "amount": 90, "processor": "STRIPE", "imported_at": "2024-06-04T18:11:57.339076Z", "allocations": [ { "invoice_id": "c635d706-bf18-41a1-b4ea-83a4768b6e14", "payment_id": "590ed436-c2bd-4e39-8047-f913a852f99c", "amount": 90, "transaction_tags": [] } ], "refund_allocations": [], "transaction_tags": [] }, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": {} } ], "write_offs": [], "refund_allocations": [] "imported_at": "2024-06-04T18:11:57.234148Z", "updated_at": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": {} } } ``` # Invoice Payment object Source: https://docs.layerfi.com/api-reference/invoice/payments Invoice payments represent payments made by customers of a business. Payments may be made at any time and applied to any outstanding (sent, but not fully paid) invoice. ### Attributes Unique identifier for the payment. Unique ID of the invoice payment in an external system for linking and idempotency. The [customer](/api-reference/customer/customer) associated with this payment, if one has been set. You can tag a payment with a customer before it is allocated to any invoice (for example, a standalone deposit). Once the payment has invoice allocations, the customer must match the customer on every allocated invoice. Timestamp when the payment was completed. Payment method. Possible values are: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Fee paid by business for processing of payment in positive cents. Optional description of the fee. The [Account Identifier](/api-reference/ledger/account-identifier) for the fee to be debited. Amount of the fee in cents. Whether or not the fee is passed to the customer. It is paid by the business otherwise. When calculating the outstanding balance on the invoice, only the portion of each payment allocation that is applied to the invoice (excluding pass-through fees) is considered. This allows customers to pay the invoice amount plus any pass-through fees without the invoice being considered overpaid. Customer payment amount, in cents. Processor used to make the payment, if any. Any processor name can be provided and will be tracked. Allowed only when `method` is `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, or `OTHER`. Timestamp when the payment was imported into Layer. List of [Dedicated Refunds](/api-reference/refunds/refund#create-dedicated-refund-parameters-object) to create with this payment Tags to apply to the payment. Tags are key-value pairs that can be used to categorize and filter payments. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If not specified, `key` will be displayed. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value definition. If not specified, `value` will be displayed. Allocations specify how a payment is distributed. A payment can include two types of allocations: * **`InvoicePaymentAllocation`**: Allocates a portion of the payment to a specific invoice. * **`InvoicePaymentAllocationToLedgerAccount`**: Allocates a portion of the payment directly to a ledger account, rather than to an invoice. This is useful for recording payments that are not associated with a specific invoice, such as overpayments or deposits. A payment may contain any combination of invoice and ledger account allocations. The sum of all allocation amounts must be less than or equal to the payment amount. ID of an invoice to which this payment is applied. ID of the payment this allocation applies from. Customer payment amount, in cents. Optional memo for the allocation. Arbitrary custom metadata in JSON format. User-visible identifier for the allocation. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived ID of the ledger account to which this payment is allocated. ID of the payment this allocation applies from. Customer payment amount, in cents. Amount allocated after applying any refunds, in cents. Optional memo for the allocation. Arbitrary custom metadata in JSON format. User-visible identifier for the allocation. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived List of [Refund Allocations](/api-reference/refunds/refund#refund-allocation-object) that target this invoice payment, including allocations of dedicated refunds. Each refund allocation includes `refund_id` and `refund_external_id`, the ID and external ID of the refund it belongs to. Memo for any text you would like to associate with the invoice payment (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the invoice payment. Can be used to filter when listing invoice payment. ```json Response theme={null} { "data": { "type": "Payment", "id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "external_id": "payment-1", "customer": { "type": "CustomerData", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "customer-1", "individual_name": "John Doe", "company_name": null, "email": "john.doe@example.com" }, "at": "2024-02-27T02:16:40.369432Z", "method": "CREDIT_CARD", "fee": 20, "amount": 190, "processor": "STRIPE", "imported_at": "2024-02-27T02:16:40.389772Z", "allocations": [ { "type": "InvoicePaymentAllocation", "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "invoice_id": "57f0fada-bb56-4f3e-9afa-2a222b68009e", "payment_id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "amount": 90, "amount_net_of_refunds": 71, "memo": null, "metadata": {}, "reference_number": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] }, { "type": "InvoicePaymentAllocationToLedgerAccount", "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "account_id": "50448df3-6f86-445e-b48f-0e80153e5d42", "payment_id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "amount": 100, "amount_net_of_refunds": 79, "memo": "Customer deposit", "metadata": {}, "reference_number": null, "transaction_tags": [] } ], "refund_allocations": [ { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "refund_id": "e5f6a7b8-c9d0-1234-ef01-345678901234", "refund_external_id": "refund-123", "amount": 40, "line_items": [ { "amount": 40, "ledger_account": { "id": "e5f6a7b8-c9d0-1234-ef01-345678901234", "name": "Customer Refunds", "account_number": "49200", "stable_name": "CUSTOMER_REFUNDS", "normality": "DEBIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "RETURNS_ALLOWANCES", "display_name": "Returns & Allowances" } }, "prepayment_account": null, "transaction_tags": [], "memo": null, "metadata": null, "reference_number": null } ], "invoice_payment_id": "e67c216b-28f4-4a0e-9a21-7f05c19e4c66", "invoice_payment_external_id": "payment-1", "transaction_tags": [], "memo": null, "metadata": null, "reference_number": null } ], "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "metadata": {} } } ``` ## Optional: Create refunds with the invoice payment This field can be specified when creating an invoice and any of its invoice line items or invoice payments List of [Dedicated Refunds](/api-reference/refunds/refund#create-dedicated-refund-parameters-object) to create with this payment # Void an Invoice Source: https://docs.layerfi.com/api-reference/invoice/void POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices/{invoice_id}/void Void an invoice, removing it from accounting and marking it as voided. Voiding an invoice cancels it entirely, removing revenue and receivables from the ledger and marking the invoice as voided. Voiding can only be performed on an invoice before payments have been collected or write-offs have been made. If an invoice was created by mistake and included payments, these should be deleted instead of voiding. ### Path Parameters Id of the [Business](/api-reference/business/business) the invoice is associated with. Id of the [Invoice](/api-reference/invoice/invoice) the write-off is applied to. ### Response Returns the updated [Invoice Object](/api-reference/invoice/invoice) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices/${invoice_id}/void \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ ``` ```json Response theme={null} { "data": { "type": "Invoice", "id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "external_id": "019234", "status": "VOID", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "paid_at": null, "voided_at": null, "invoice_number": "1", "recipient_name": "John Doe", "line_items": [ { "id": "e6a491dd-9c22-4403-a54f-32d741a7ec67", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": "2.00", "subtotal": 2598, "discount_amount": 0, "sales_taxes_total": 218, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ], "total_amount": 2816, "transaction_tags": [ { "id": "b2c3d4e5-f6a7-8901-bcde-f1234567890a", "key": "product-category", "value": "cleaning-supplies", "dimension_display_name": "Product Category", "value_display_name": "Cleaning Supplies", "dimension_id": "e3f4a5b6-c7d8-9012-cdef-123456789012", "definition_id": "f4a5b6c7-d8e9-0123-def1-234567890123", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] }, { "id": "44f06385-3ef5-4517-8095-eeedaf2054ab", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Full drain cleaning service", "unit_price": 25000, "quantity": "1.00", "subtotal": 25000, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 25000, "transaction_tags": [] } ], "subtotal": 27598, "additional_discount": 250, "additional_sales_taxes_total": 0, "tips": 0, "tips_account": null, "total_amount": 27566, "outstanding_balance": 27566, "payment_allocations": [], "imported_at": "2024-04-19T02:23:59.902537Z", "updated_at": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` ```json 400 theme={null} { "errors": [ { "type": "Invalid State", "description": "Cannot void invoice with payments. Delete the payments & invoice if payments were made in error." } ] } ``` ```json 400 theme={null} { "errors": [ { "type": "Invalid State", "description": "Cannot void invoice with write offs. Delete the invoice if write offs were made in error." } ] } ``` # Account Identifier Source: https://docs.layerfi.com/api-reference/ledger/account-identifier Account identifiers are unique identifiers for a specific ledger account within a business. They are used in both API inputs and outputs to specify a given ledger account. They are typically used when [categorizing transactions](/api-reference/v1/categorize-bank-transaction) or [creating categorization rules](/api-reference/v1/categorization-rules/create-categorization-rule). Account identifiers are polymorphic. There are multiple types of identifiers for different use cases which we discuss below. ## `AccountId` The first use case is the intuitive `AccountId` type, which is a unique ID object for a ledger account. This kind of identifier is unique across all businesses and all ledger accounts. ### Request Body `AccountId` indicates we're using an AccountId identifier type. The unique identifier string for the ledger account. ```json Account ID Example theme={null} { "type": "AccountId", "id": "e95c8640-f87b-43bf-a9c6-cabc7ebfdec6" } ``` Account IDs are useful when users create their own ledger accounts, which are not guaranteed to have stable names. To refer to these accounts will need to use the `AccountId` type. ## `StableName` The second use case is the `StableName` type, which is a stable identifier for an account present in your chart of accounts template. This kind of identifier is useful for identifying equivalent accounts across businesses, e.g., referring to the `ACCOUNTS_RECEIVABLE` account across different businesses, since those may have different `AccountId`s but will have the same `StableName`. This is useful for situations where you are building a workflow for a specific account type, e.g. `ACCOUNTS_RECEIVABLE` and don't want to look up the unique account ID for each business. ### Limitations While useful, there are two limitations to note with stable names: 1. End-users with access to the general ledger can create their own ledger accounts, which will not have stable names. To refer to these accounts will need to use the `AccountId` type. 2. Some templated account types are specific to industries. If you have customers with different Charts. If you try to use a stable name for an account which does not exist for a business, you will receive an error. ### Request Body `StableName` indicates we're using a StableName identifier type. The stable identifier string for the ledger account. ```json Stable Name Example theme={null} { "type": "StableName", "stable_name": "CHARITABLE_CONTRIBUTIONS" } ``` ## References * [Required vs. Optional Template Accounts](/api-reference/ledger/required-vs-optional-template-accounts) # Chart of Accounts object Source: https://docs.layerfi.com/api-reference/ledger/chart The chart of accounts for the general ledger of a business on Layer’s platform. A general ledger is automatically created when a [Business](/api-reference/business/business) is created via the [Create a Business](/api-reference/v1/create-business) endpoint. ### Attributes Resource type. Value will be "Chart\_Of\_Accounts". Array of [Ledger Accounts](/api-reference/ledger/chart#ledger-account-object) within the Ledger with their entries and balances omitted. #### Ledger Account object An account within the chart of accounts for the general ledger. Unique identifier of the ledger account. Account name Stable identifier for templated account. Human readable description for this ledger account. An array of [Ledger Account](/api-reference/ledger/chart#ledger-account-object) objects representing child accounts of this ledger account. Balance of the account, in cents. Account balance normality. Values can be: `DEBIT`, `CREDIT` Type of the ledger account. Values can be: `ASSET`, `LIABILITY`, `EQUITY`, `REVENUE`, or `EXPENSE` Subtype of the ledger account. Values can be: `BANK_ACCOUNTS`, `ACCOUNTS_RECEIVABLE`, `INVENTORY`, `PAYMENT_PROCESSOR_CLEARING_ACCOUNT`, `FIXED_ASSET`, `ACCUMULATED_DEPRECIATION`, `CASH`, `UNDEPOSITED_FUNDS`, `CURRENT_ASSET`, `NON_CURRENT_ASSET`, `PREPAID_EXPENSES`, `DEVELOPMENT_COSTS`, `LOANS_RECEIVABLE`, `INTANGIBLE_ASSET`, `ACCOUNTS_PAYABLE`, `CREDIT_CARD`, `INCOME_TAXES_PAYABLE`, `SALES_TAXES_PAYABLE`, `OTHER_TAXES_PAYABLE`, `PAYROLL_TAXES_PAYABLE`, `UNEARNED_REVENUE`, `PAYROLL_LIABILITY`, `PAYROLL_CLEARING`, `LINE_OF_CREDIT`, `TIPS`, `REFUND_LIABILITIES`, `UNDEPOSITED_OUTFLOWS`, `OUTGOING_PAYMENT_CLEARING_ACCOUNT`, `OTHER_CURRENT_LIABILITY`, `LOANS_PAYABLE`, `NOTES_PAYABLE`, `SHAREHOLDER_LOAN`, `NON_CURRENT_LIABILITY`, `CONTRIBUTIONS`, `DISTRIBUTIONS`, `COMMON_STOCK`, `PREFERRED_STOCK`, `ADDITIONAL_PAID_IN_CAPITAL`, `RETAINED_EARNINGS`, `ACCUMULATED_ADJUSTMENTS`, `OPENING_BALANCE_EQUITY`, `OTHER_EQUITY`, `SALES`, `UNCATEGORIZED_REVENUE`, `RETURNS_ALLOWANCES`, `DIVIDEND_INCOME`, `INTEREST_INCOME`, `OTHER_INCOME`, `COGS`, `OPERATING_EXPENSES`, `PAYROLL`, `TAXES_LICENSES`, `UNCATEGORIZED_EXPENSE`, `CHARITABLE_CONTRIBUTIONS`, `LOAN_EXPENSES`, `FINANCE_COSTS`, `INTEREST_EXPENSES`, `DEPRECIATION`, `AMORTIZATION`, `BAD_DEBT`, or `OTHER_EXPENSES` Array of [Ledger Account Line Item](/api-reference/ledger/chart#ledger-account-line-item-object) objects representing ledger entries recorded in this account. #### Journal Entry object A journal entry within the general ledger. Unique identifier of the journal entry. ID of the business associated with this journal entry. ID of the general ledger containing this journal entry. Entity that created the journal entry. Type of entry. Example values: `INVOICE_PAYMENT`, `EXPENSE` Array of [Ledger Account Line Items](/api-reference/ledger/chart#ledger-account-line-item-object) comprising the Journal Entry. #### Ledger Account Line Item object A ledger entry within a ledger account. Unique identifier of the ledger account line item. ID of the Journal entry the ledger account line item was part of. Simplified [Ledger Account](/api-reference/ledger/chart#ledger-account-object) object containing this line item. Direction of line item. Values can be: `DEBIT`, `CREDIT` Timestamp of the financial transaction associated with the line item. Timestamp when ledger entry was added to the ledger account. ```json Example theme={null} { "data": { "type": "Chart_Of_Accounts", "accounts": [ { "id": "6ac7e685-4859-43a0-9f26-61e57c31f4ea", "name": "Expenses", "stable_name": "EXPENSES", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": null, "sub_accounts": [ { "id": "ab16f453-6b0f-416d-bcc9-92edba3b6e0a", "name": "Cost of Goods Sold", "stable_name": "COGS", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "COGS", "display_name": "COGS" }, "sub_accounts": [ // Sub-accounts omitted for brevity ] }, { "id": "ab5f3795-734e-4b12-b9a1-c32ec4b43c2e", "name": "Operating Expenses", "stable_name": "OPERATING_EXPENSES", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" }, "sub_accounts": [ // Sub-accounts omitted for brevity ] }, ] }, { "id": "700a1b71-0b38-4d36-b46c-c0610f7849b5", "name": "Revenue", "stable_name": "REVENUE", "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": null, "sub_accounts": [ { "id": "59d427f8-4681-4a8c-926e-3c3963b24e8f", "name": "Service Revenue", "stable_name": "SERVICES_REVENUE", "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "SALES", "display_name": "Sales" }, "sub_accounts": [] }, { "id": "d9ac1801-3433-4666-9e49-597c3d8c9816", "name": "Sale of Goods Revenue", "stable_name": "GOODS_REVENUE", "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "SALES", "display_name": "Sales" }, "sub_accounts": [] } ] }, // Additional accounts omitted for brevity ] } } ``` # Reverse Journal Entry Source: https://docs.layerfi.com/api-reference/ledger/entries/create-reversal-entry POST https://sandbox.layerfi.com/v1/businesses/{business_id}/ledger/entries/{entry_id}/reverse This endpoint creates a reversal entry for an existing journal entry. ### Path Parameters ID of the Business to create the reversal entry for. ID of the Journal Entry to create a reversal entry for. ### Response Returns a Journal Entry with one of the following status codes: * 201 Created - A new reversal entry was successfully created. * 200 OK - The journal entry was already reversed. The response contains the existing or newly created reversal [Journal Entry](/api-reference/ledger/chart#journal-entry-object) ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/d2f6d97f-3345-4299-9ec2-468738c5d536/ledger/entries/3b062adc-6877-4f28-accf-2acd220ef13b/reverse \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" ``` ```json Response theme={null} { "data": { "type": "Ledger_Entry", "id": "1fe5ccfc-9dbb-444a-8cb8-e2874e98433e", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "ledger_id": "0f4bb90e-1c43-4994-81e8-aac4dcd6e380", "agent": "API", "entry_type": "REVERSAL", "date": "2024-05-30T21:43:14.079497Z", "entry_at": "2024-05-01T19:00:00Z", "reversal_of_id": "8a01e025-c111-4360-b3e0-eecaf70a560e", "reversal_id": null, "line_items": [ { "id": "e40d6f90-a820-4f0c-9d46-c6ff50975fb8", "entry_id": "1fe5ccfc-9dbb-444a-8cb8-e2874e98433e", "account": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2", "name": "Rent", "stable_name": "RENT_EXPENSE", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" } }, "amount": 250000, "direction": "CREDIT", "entry_at": "2024-05-01T19:00:00Z", "createdAt": "2024-05-30T21:43:14.079497Z" }, { "id": "5e9f885f-eda5-41e0-be05-c5e3d04ddce8", "entry_id": "1fe5ccfc-9dbb-444a-8cb8-e2874e98433e", "account": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa", "name": "Layer Demo Banking", "stable_name": null, "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "account_subtype": { "value": "BANK_ACCOUNTS", "display_name": "Bank Accounts" } }, "amount": 250000, "direction": "DEBIT", "entry_at": "2024-05-01T19:00:00Z", "createdAt": "2024-05-30T21:43:14.079497Z" } ], "invoice": null, "manual_entry": null, "source": { "type": "Transaction_Ledger_Entry_Source", "transaction_id": "073afbfd-e25d-4c62-b591-060740f00cf8", "external_id": "12345-1234-expense-243", "account_name": "Layer Demo Banking", "date": "2024-05-01T19:00:00Z", "amount": 250000, "direction": "DEBIT", "counterparty": "WeWork", "entity_name": "Bank Transaction", "display_description": "Layer Demo Banking transaction May 1" } } } ``` # Fetch Journal Entry Source: https://docs.layerfi.com/api-reference/ledger/entries/get-journal-entry GET https://sandbox.layerfi.com/v1/businesses/{business_id}/ledger/entries/{entry_id} This endpoint retrieves a journal entry within a business' general ledger. ### Path Parameters ID of the Business to retrieve the Journal Entry for. ID of the Journal Entry to retrieve. ### Response The retrieved [Journal Entry](/api-reference/ledger/chart#journal-entry-object) ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/businesses/d2f6d97f-3345-4299-9ec2-468738c5d536/ledger/entries/0e81ec02-483a-4ade-8878-b8e731e14c0f \ -H "Authorization: Bearer " ``` ```json Response theme={null} { "data": { "type": "Ledger_Entry", "id": "8a01e025-c111-4360-b3e0-eecaf70a560e", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "ledger_id": "0f4bb90e-1c43-4994-81e8-aac4dcd6e380", "agent": "API", "entry_type": "EXPENSE", "date": "2024-05-23T03:56:30.536048Z", "entry_at": "2024-05-01T19:00:00Z", "reversal_of_id": null, "reversal_id": null, "line_items": [ { "id": "2fbae241-b7d2-4e9d-ae92-14d123e8beb3", "entry_id": "8a01e025-c111-4360-b3e0-eecaf70a560e", "account": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2", "name": "Rent", "stable_name": "RENT_EXPENSE", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" } }, "amount": 250000, "direction": "DEBIT", "entry_at": "2024-05-01T19:00:00Z", "createdAt": "2024-05-23T03:56:30.536048Z" }, { "id": "5d97051f-958b-4d26-a5f2-a90030c39e1e", "entry_id": "8a01e025-c111-4360-b3e0-eecaf70a560e", "account": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa", "name": "Layer Demo Banking", "stable_name": null, "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "account_subtype": { "value": "BANK_ACCOUNTS", "display_name": "Bank Accounts" } }, "amount": 250000, "direction": "CREDIT", "entry_at": "2024-05-01T19:00:00Z", "createdAt": "2024-05-23T03:56:30.536048Z" } ], "invoice": null, "manual_entry": null, "source": { "type": "Transaction_Ledger_Entry_Source", "transaction_id": "073afbfd-e25d-4c62-b591-060740f00cf8", "external_id": "12345-Corp-1234-expense-243", "account_name": "Layer Demo Banking", "date": "2024-05-01T19:00:00Z", "amount": 250000, "direction": "DEBIT", "counterparty": "WeWork", "entity_name": "Bank Transaction", "display_description": "Layer Demo Banking transaction May 1" } } } ``` # Required vs. Optional Template Accounts Source: https://docs.layerfi.com/api-reference/ledger/required-vs-optional-template-accounts After going through [the quickstart](/guides/quickstart) and onboarding of your platform onto Layer, your platform will be configured with a specific chart of account template used to initialize the general ledger for all of your business users. Template chart of accounts are composed of both required and optional accounts. Required accounts are accounts that are created automatically for a business. Optional accounts are created lazily- that is, an optional account in a business's chart of accounts template may be referenced via its stable name (e.g., while categorizing a bank transaction) even if the account has not yet been instantiated. Examples of required accounts used across all businesses are `ASSETS`, `LIABILITIES`, `ACCOUNTS_RECEIVABLE`, `OPERATING_EXPENSES`, etc. ### Required Template Accounts When a new business is created, its chart of accounts will be created with all of the required template accounts. You may use either `AccountId` or `StableName` to identify a required template account. ### Optional Template Accounts Unlike required template accounts, optional template accounts do not get immediately instantiated for the new businesses. Instead, they are accounts users can interact with (e.g. categorize a transaction) via a `StableName` identifier. Once used, the account gets instantiated for the business and a unique `AccountId` is created for that account. You may only use a `StableName` to reference an optional template account before creation. Once created, you may use either `AccountId` or `StableName` to identify an optional template account. ## Use cases * [Transaction categorization](/api-reference/v1/categorize-bank-transaction) * [Designing your own transaction categorization user interface](/api-reference/v1/fetch-transaction-categories) ## References * [Account Identifiers](/api-reference/ledger/account-identifier) # Loan object Source: https://docs.layerfi.com/api-reference/loan/loan A Loan represents financing a Business has taken on: a term loan, line of credit, lease, equipment financing, or merchant cash advance. Creating a loan opens a dedicated liability account in the Business's ledger (under `NOTES_PAYABLE` by default), and records the proceeds and repayments against it. A loan is made up of three related concepts: * **Proceeds**: the funds (or assets) received when the loan is drawn. A proceed is either a cash **disbursement** or an **asset** that the loan financed (for example, financed equipment). See the [Loan Proceed object](#loan-proceed-object). * **Payments**: repayments made against the loan, each split into **principal**, **interest**, and **fee** portions. See the [Loan Payment object](#loan-payment-object). * **Ledger account**: the dedicated liability account Layer maintains for the loan, exposed as `loan_account`. ### Attributes Unique identifier for the loan. ID of the Business that holds the loan. Unique ID of the loan in your system for linking purposes. Human-friendly name for the loan. The type of loan. Values can be: `TERM_LOAN`, `MCA`, `FLEX_LOAN`, `LINE_OF_CREDIT`, `LEASE`, `EQUIPMENT_FINANCING` The dedicated ledger (liability) account for this loan. Current outstanding balance of the loan, in cents. The loan's active opening balance, if one has been derived: pre-existing debt recorded against Opening Balance Equity rather than explained by recorded proceeds and payments. Layer derives it from the loan's recorded history and any `reported_balance` you have sent; it is not set directly. Contains `ledger_account_id`, `ledger_account_name`, `balance` (in cents), `effective_at`, `created_at`, `updated_at`, `transaction_tags`, `memo`, `metadata`, and `reference_number`. See [Backfilling existing loans](/guides/loans/backfilling-existing-loans). Date the loan was originated. Original principal, in cents. Present for `TERM_LOAN`, `MCA`, `FLEX_LOAN`, `LEASE`, and `EQUIPMENT_FINANCING`. Credit limit, in cents. Present for `LINE_OF_CREDIT`. Fixed fee, expressed as a percentage in a decimal string (for example, `"15"` for a 15% fee). Present for `MCA` and `FLEX_LOAN`. Loan term in months. Present for `TERM_LOAN`, `LEASE`, and `EQUIPMENT_FINANCING`. When the loan was fully repaid, if applicable. When the loan was cancelled, if applicable. When the loan was archived, if applicable. Internal note about the loan. Arbitrary JSON object you can attach for your own use. Layer stores and returns it unchanged. Reference number for the loan. Tags applied to this loan. ## Loan Proceed object A Loan Proceed represents funds (or an asset) received when a loan is drawn. A proceed is one of two types: * **`DISBURSEMENT`**: a cash disbursement, received via a `method` such as ACH or check. * **`ASSET`**: an asset the loan financed (for example, financed equipment). The funded asset is referenced by `asset_id`. Proceeds can be supplied inline when you [create](/api-reference/v1/loans/create-loan) or [update](/api-reference/v1/loans/update-loan) a loan, or managed individually with the loan proceed endpoints: [list](/api-reference/v1/loans/list-loan-proceeds), [create](/api-reference/v1/loans/create-loan-proceed), [fetch](/api-reference/v1/loans/fetch-loan-proceed), [update](/api-reference/v1/loans/update-loan-proceed), and [archive](/api-reference/v1/loans/archive-loan-proceed). ### Attributes Unique identifier for the loan proceed. ID of the Business that holds the loan. Unique ID of the proceed in your system for linking purposes. ID of the loan this proceed belongs to. How the proceeds were received. Values can be: `ASSET`, `DISBURSEMENT` Payment method used for the proceed. Values can be: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Proceed amount, in cents. ID of the asset funded by this proceed. Present for `ASSET` proceeds. Date the proceed was received. When the proceed was archived, if applicable. Internal note about the proceed. Arbitrary JSON object you can attach for your own use. Reference number for the proceed. Tags applied to this proceed. ## Loan Payment object A Loan Payment is a repayment made against a loan. Each payment is broken into one or more **splits** by type (`PRINCIPAL`, `INTEREST`, `FEE`), and the splits must sum to the payment `amount` and share its sign. A payment with a negative `amount` is a **reversal**, which gives back an earlier repayment. Record a reversal as its own payment rather than editing the payment it offsets, so the reversal books on its own date. Payments can optionally be **deferred**: recorded but not posted to the ledger until they are paid out or their due date is reached. ### Attributes Unique identifier for the loan payment. ID of the Business that made the payment. Unique ID of the payment in your system for linking purposes. ID of the loan this payment applies to. The principal, interest, and fee splits that make up this payment. The split amounts sum to `amount` and share its sign. Unique identifier for the split. Unique ID of the split in your system for linking purposes. The portion of the payment this split applies to. Values can be: `PRINCIPAL`, `INTEREST`, `FEE` Split amount, in cents. The ledger account this split posted to. Total payment amount, in cents. Negative on a reversal. Date of the payment. Whether posting to the ledger is deferred. Payment method. Values can be: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Payment processor, if any. The clearing account used for the payment, if any. When the payment was archived, if applicable. Internal note about the payment. Arbitrary JSON object you can attach for your own use. Reference number for the payment. Tags applied to this payment. # Record custom account transaction Source: https://docs.layerfi.com/api-reference/openapi-generated-schemas/record-custom-account-transaction post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/transactions/record Record a one-off expense from a personal account or another transaction not recorded in an existing bank feed. Receipts can be included. # Update custom account transaction Source: https://docs.layerfi.com/api-reference/openapi-generated-schemas/update-custom-account-transaction patch /v1/businesses/{businessId}/custom-accounts/{customAccountId}/transactions/{transactionId} Update a transaction on a custom account. To manage receipts, use the recorded-transaction PATCH endpoint. # Update recorded transaction Source: https://docs.layerfi.com/api-reference/openapi-generated-schemas/update-recorded-transaction patch /v1/businesses/{businessId}/custom-accounts/{customAccountId}/transactions/{transactionId}/record Update a one-off expense or another transaction not recorded in an existing bank feed. Receipts can be included. # List Plaid Accounts Source: https://docs.layerfi.com/api-reference/plaid-account/list-plaid-accounts GET https://sandbox.layerfi.com/v1/businesses/{business_id}/plaid/accounts This endpoint lists the Plaid accounts associated with a business. ### Path Parameters ID of the [Business](/api-reference/business/business) to list the Plaid accounts for. ### Response List of [Plaid Account](/api-reference/plaid-account/plaid-account) objects. ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/plaid/accounts \ -H "Authorization: Bearer " ``` ```json Response theme={null} { "data": [ { "type": "Plaid_Account_With_Processor_Token", "id": "d0068f9a-e5ad-4bed-b338-a022d6d75bd4", "plaid_account_id": "Aaoy8G7VXZHVeqNoL1GvcmkPdqpLRWi9NArdG", "plaid_processor_token": "processor-sandbox-0496279d-6c4c-4363-8783-f87d0d08e442", "status": "ACTIVE", "mask": "0000", "name": "Plaid Checking", "account_type": "DEPOSITORY", "subtype": "checking", "created_at": "2024-05-28T22:24:33.467485Z", "updated_at": "2024-05-28T22:24:33.467485Z", "connection_needs_repair_as_of": null, "ledger_account_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ], "meta": {} } ``` # Plaid Account object Source: https://docs.layerfi.com/api-reference/plaid-account/plaid-account A bank account linked via Plaid associated with a [Business](/api-reference/business/business). ### Attributes Unique (Layer-generated) identifier of the plaid account. Plaid-generated identifier of the plaid account. Account status within Layer. Values can be: `ACTIVE`, `ARCHIVED`. The last 2-4 alphanumeric characters of an account's official account number. Content and format varies based by financial institution. The name of the account, either assigned by the user or by the financial institution itself. The type of the account. See [Plaid account type schema](https://plaid.com/docs/api/accounts/#account-type-schema) for a full listing of account types and corresponding subtypes. Possible values: `INVESTMENT`, `CREDIT`, `DEPOSITORY`, `LOAN`, `BROKERAGE`, `OTHER`. The subtype of the account. See [Plaid account type schema](https://plaid.com/docs/api/accounts/#account-type-schema) for a full listing of account types and corresponding subtypes. Possible values: `401a`, `401k`, `403B`, `457b`, `529`, `brokerage`, `cash isa`, `crypto exchange`, `education savings account`, `ebt`, `fixed annuity`, `gic`, `health reimbursement arrangement`, `hsa`, `isa`, `ira`, `lif`, `life insurance`, `lira`, `lrif`, `lrsp`, `non-custodial wallet`, `non-taxable brokerage account`, `other`, `other insurance`, `other annuity`, `prif`, `rdsp`, `resp`, `rlif`, `rrif`, `pension`, `profit sharing plan`, `retirement`, `roth`, `roth 401k`, `rrsp`, `sep ira`, `simple ira`, `sipp`, `stock plan`, `thrift savings plan`, `tfsa`, `trust`, `ugma`, `utma`, `variable annuity`, `credit card`, `paypal`, `cd`, `checking`, `savings`, `money market`, `prepaid`, `auto`, `business`, `commercial`, `construction`, `consumer`, `home equity`, `loan`, `mortgage`, `overdraft`, `line of credit`, `student`, `cash management`, `keogh`, `mutual fund`, `recurring`, `rewards`, `safe deposit`, `sarsep`, `payroll`, `null`. The timestamp of when the account was created. The timestamp of when the account was last updated. The timestamp of when the connection to the account from its processor token was determined to be broken, indicating the need to repair the connection. This can be done by re-linking the account and issuing a new processor token. Only appears if the account is associated with a processor token rather than an item. The ID of the plaid item this account is associated with. Null if this account is instead associated with a plaid processor token. If non-null, the type will be Plaid\_Account\_With\_Item. The ID of the plaid processor token this account is associated with. Null if this account is instead associated with a plaid item. If non-null, the type will be Plaid\_Account\_With\_Processor\_Token. The ID of the [ledger account](https://docs.layerfi.com/api-reference/ledger/chart#ledger-account-object) associated with the plaid account. ```json Example theme={null} { "type": "Plaid_Account_With_Processor_Token", "id": "d0068f9a-e5ad-4bed-b338-a022d6d75bd4", "plaid_account_id": "Aaoy8G7VXZHVeqNoL1GvcmkPdqpLRWi9NArdG", "plaid_processor_token": "processor-sandbox-0496279d-6c4c-4363-8783-f87d0d08e442", "status": "ACTIVE", "mask": "0000", "name": "Plaid Checking", "account_type": "DEPOSITORY", "subtype": "checking", "created_at": "2024-05-28T22:24:33.467485Z", "updated_at": "2024-05-28T22:24:33.467485Z", "ledger_account_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` # Retrieve Plaid Configuration Source: https://docs.layerfi.com/api-reference/plaid/get GET https://sandbox.layerfi.com/v1/configure/plaid Retrieves a Plaid configuration for your Layer account. ### Response Returns the selected [Plaid Configuration Object](/api-reference/plaid/plaid) ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/configure/plaid \ -H "Authorization: Bearer " ``` ```json Example theme={null} { "data":{ "type":"Plaid_Configuration", "client_id":"6488fafd7a73ae00122004d6", "secret_last_4":"acae", "plaid_env_url_override": "SANDBOX" } } ``` # Plaid Configuration object Source: https://docs.layerfi.com/api-reference/plaid/plaid Layer uses Plaid to connect to pull information from your customers' external bank accounts and credit cards. The Plaid Configuration object allows you to manage the Plaid configuration associated with your Layer account. ### Attributes Resource type. Value will be: "Plaid\_Configuration" Account-wide client id. Account-wide plaid secret. Only the last 4 characters will be displayed. Plaid environment to use- either SANDBOX (which corresponds to [https://sandbox.plaid.com](https://sandbox.plaid.com)) or PRODUCTION (which corresponds to [https://production.plaid.com](https://production.plaid.com)). ```json Example theme={null} { "data":{ "type":"Plaid_Configuration", "client_id":"6488fafd7a73ae00122004d6", "secret_last_4":"acae", "plaid_env_url_override": "SANDBOX" } } ``` # Set Plaid Credentials Source: https://docs.layerfi.com/api-reference/plaid/set PUT https://sandbox.layerfi.com/v1/configure/plaid Sets Plaid credentials to be used with your Layer account. ### Body Plaid ID, visible on [https://dashboard.plaid.com/developers/keys](https://dashboard.plaid.com/developers/keys) Plaid secret. Plaid environment to use- either SANDBOX (which corresponds to [https://sandbox.plaid.com](https://sandbox.plaid.com)) or PRODUCTION (which corresponds to [https://production.plaid.com](https://production.plaid.com)). If not specified, defaults to PRODUCTION. ### Response Returns the created [Plaid Configuration Object](/api-reference/plaid/plaid) ```bash Request theme={null} curl -X PUT https://sandbox.layerfi.com/v1/configure/plaid \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "client_id":"CLIENT_ID", "secret":"CLIENT_SECRET", "plaid_env_url_override": "SANDBOX" }' ``` ```json Response theme={null} { "data":{ "type":"Plaid_Configuration", "client_id":"6488fafd7a73ae00122004d6", "secret_last_4":"acae", "plaid_env_url_override": "SANDBOX" } } ``` # Refund object Source: https://docs.layerfi.com/api-reference/refunds/refund A Refund represents a transaction that returns value from a business to a customer. Each refund has one or more Refund Allocations (targets) and zero or more Refund Payments. ## Creating Refunds There are two ways to create refunds: ### Simple Refunds Use simple refunds when you want to fully refund a single target (invoice, invoice line item, or invoice payment) and the refund is fully paid. Layer automatically: * Calculates the refund amount based on what can be refunded from the target * Creates one allocation that perfectly cancels out the target * Creates one refund payment that pays the refund in full ### Itemized Refunds Use itemized refunds for more complex scenarios including: * Refunding multiple targets in a single refund * Partial refunds that don't fully cancel out the target * Unpaid refunds (refunds owed but not yet disbursed) * Custom allocation amounts or payment structures With itemized refunds, you specify all allocations and payments explicitly. ## Refund Object ### Attributes Unique identifier for the refund. Unique ID of the refund in your system for linking purposes. **Idempotency key**. Amount refunded to the customer in cents. Status of the refund. Time when the refund was completed. Whether this refund is dedicated or not. Dedicated refunds can only have one allocation and one payment, and their allocation target cannot be changed. Allocations associated with this refund. See [Refund Allocation Object](#refund-allocation-object) for details. Payments associated with this refund. See [Refund Payment Object](#refund-payment-object) for details. Payouts associated with this refund. Tags associated with the refund. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the refund. Arbitrary metadata you can include with the refund. Any (typically user-visible) identifier you would like to associate with the refund. Can be used to filter when listing refunds. ## Refund Allocation Object A Refund Allocation represents one of the targets of a refund. It can reference a specific invoice, invoice line item, invoice payment, or customer. For example, a refund can apply to two separate invoices if the invoices have the same customer. The total of the amounts of the refund allocations must add up to the refund amount. Unique identifier for the refund allocation. ID of the refund this allocation belongs to. External ID of the refund this allocation belongs to. ID of the invoice this allocation is associated with. Amount of the allocation in cents. Line items that make up this allocation. See [Refund Allocation Line Item Object](#refund-allocation-line-item-object) for details. External ID of the invoice this allocation is associated with. ID of the invoice line item this allocation is associated with. If specified, must not refer to a different invoice than `invoice_id` or `invoice_external_id`. The external ID of the invoice line item to refund. If specified alongside `invoice_line_item_id`, they must refer to the same invoice line item. ID of the invoice payment this allocation is associated with. External ID of the invoice payment this allocation is associated with. The [Customer](/api-reference/customer/customer) associated with this refund allocation. Tags associated with the refund allocation. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the refund allocation. Arbitrary metadata you can include with the refund allocation. Any (typically user-visible) identifier you would like to associate with the refund allocation. ## Refund Allocation Line Item Object A Refund Allocation Line Item represents a specific line within a refund allocation, allowing for detailed breakdowns of how the allocation amount is distributed across different ledger accounts. External identifier for the line item. Amount of the line item in cents. The ledger account associated with this line item. The prepayment ledger account associated with this line item, if applicable. Tags associated with the line item. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the line item. Arbitrary metadata you can include with the line item. Any (typically user-visible) identifier you would like to associate with the refund pyment. Can be used to filter when listing refund payments. ## Refund Payment Object A Refund Payment represents a money movement by which the refund was disbursed to the customer. A refund with zero payments represents a refund that is owed to a customer but has not yet been sent. A refund can have many payments so long as the total of their `refunded_amount`s does not exceed the total amount of the refund. Refund payments are matchable to bank transactions and are therefore the means by which refunds are reconciled with bank accounts. Unique identifier for the payment. Unique ID of the payment in your system for linking purposes. **Idempotency key**. Amount refunded to the customer in cents. Fee paid by the business to make the refund payment (typically a payment processing fee). Time when the payment was completed. Method of the payment (e.g., `CREDIT_CARD`, `ACH`, etc.). Processor used for the payment (e.g., `STRIPE`, `SHOPIFY`, etc.). Refunded payment fees associated with the refund payment. See [Refunded Payment Fee Object](#refunded-payment-fee-object) for details. Tags associated with the refund payment. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the refund payment. Arbitrary metadata you can include with the refund payment. ## Refunded Payment Fee Object A Refunded Payment Fee represents a fee that was refunded as part of a refund payment. This differs from the 'refund\_processing\_fee' field on the refund payment, since that is paid by the business (typically to a payment processor), whereas this is refunded from the payment processor back to the business. Identifier of the ledger account for the refunded payment fee. Description of the fee that the refunded payment fee refunds. Amount of the fee refund in cents. ## Simple Refund Creation Parameters Use these parameters to create a simple refund that fully refunds a single target (invoice, invoice line item, or invoice payment) and is fully paid. Unique ID of the refund in your system for linking purposes. **Idempotency key**. When the refund was completed and paid. The ID of the invoice to refund. Cannot be used with other target identifiers. The external ID of the invoice to refund. Cannot be used with other target identifiers. The ID of the invoice line item to refund. Cannot be used with other target identifiers. The external ID of the invoice line item to refund. Cannot be used with other target identifiers. The ID of the invoice payment to refund. Cannot be used with other target identifiers. The external ID of the invoice payment to refund. Cannot be used with other target identifiers. Fee charged to the business for processing the refund in cents. Defaults to 0. Method of the payment (e.g., `CREDIT_CARD`, `ACH`, etc.). Processor used for the payment (e.g., `STRIPE`, `SHOPIFY`, etc.). Tags to apply to the refund. Tags are key-value pairs that can be used to categorize and filter refunds. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If the dimension doesn't exist, this will be used as its display name. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value. If the value doesn't exist, this will be used as its display name. Memo for any text you would like to associate with the refund. Arbitrary metadata you can include with the refund. ## Itemized Refund Creation Parameters Use these parameters to create an itemized refund with full control over allocations and payments. Unique ID of the refund in your system for linking purposes. **Idempotency key**. The total amount of the refund in cents. Must equal the sum of all allocation amounts. When the refund was completed. The targets of the refund. Each allocation specifies how much of the refund should be applied to a specific invoice, line item, payment, or customer. External identifier for the allocation. Total amount of this allocation in cents. Must equal the sum of all line item amounts. Line items that make up this allocation. ID of the invoice this allocation targets. External ID of the invoice this allocation targets. ID of the invoice line item this allocation targets. External ID of the invoice line item this allocation targets. ID of the invoice payment this allocation targets. External ID of the invoice payment this allocation targets. ID of the customer this allocation targets. External ID of the customer this allocation targets. Tags for this allocation. Memo for this allocation. Metadata for this allocation. The payment methods and amounts used to process the refund. External identifier for the payment. Amount refunded to the customer in cents. Fee charged to the business for processing this payment. When this payment was completed. Payment method used. Processor used for this payment. Fees refunded as part of this payment. Tags for this payment. Memo for this payment. Metadata for this payment. Any (typically user-visible) identifier for this payment. Tags to apply to the refund. Tags are key-value pairs that can be used to categorize and filter refunds. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If the dimension doesn't exist, this will be used as its display name. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value. If the value doesn't exist, this will be used as its display name. Memo for any text you would like to associate with the refund. Arbitrary metadata you can include with the refund. ```json Response theme={null} { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "refund-123", "refunded_amount": 123, "status": "PAID", "completed_at": "2023-11-07T05:31:56Z", "is_dedicated": false, "allocations": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "refund_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "refund_external_id": "refund-123", "invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 123, "line_items": [ { "external_id": "line-item-1", "amount": 123, "ledger_account": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "Revenue", "account_number": "4000" }, "prepayment_account": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "memo": null, "metadata": null } ], "invoice_external_id": "invoice-123", "invoice_line_item_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoice_line_item_external_id": "line-item-123", "invoice_payment_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoice_payment_external_id": "payment-123", "customer": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "31415926535", "individual_name": "John Doe", "company_name": "Acme Corp", "email": "john@example.com", "mobile_phone": "555-123-4567", "office_phone": "555-987-6543", "address_string": "123 Main St, Anytown, CA 90210", "notes": "VIP customer", "status": "ACTIVE", "transaction_tags": [ { "key": "CustomerType", "value": "Premium", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ] }, "transaction_tags": [ { "key": "RefundReason", "value": "CustomerRequest", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": null, "metadata": null } ], "payments": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "31415926535", "refunded_amount": 123, "refund_processing_fee": 15, "completed_at": "2023-11-07T05:31:56Z", "method": "CREDIT_CARD", "processor": "STRIPE", "refunded_payment_fees": [ { "account": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "description": "Processing fee refund", "fee_amount": 10 } ], "transaction_tags": [ { "key": "ProcessorReference", "value": "ref_12345", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": null, "metadata": null } ], "payouts": [], "transaction_tags": [ { "key": "Department", "value": "CustomerService", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": null, "metadata": null } ``` ## Dedicated Refunds Dedicated refunds are a refunds that are created alongside invoices, invoice line items, and invoice payments. They provide a streamlined way to create refunds during the invoice creation or payment recording process. They are intended for when you know at the time of importing an invoice, invoice line item, or payment that it will be refunded, and want to create everything in one API call. Each dedicated refund has exactly one allocation and one payment. Once created, the allocation target cannot be changed Dedicated refunds can be included when creating: **Invoices**: Add `dedicated_refunds` array to the invoice body **Invoice Line Items**: Add `dedicated_refunds` array to any line item **Invoice Payments**: Add `dedicated_refunds` array to any payment within an invoice ### Simple vs Itemized Dedicated Refunds When creating dedicated refunds, Layer will automatically determine whether to create them as simple or itemized refunds based on the parameters you provide: **Simple Dedicated Refunds** (see [Simple Refunds](#simple-refund-creation-parameters)): * Created when you don't specify the `line_items` parameter * Layer automatically calculates the refund amount and creates a single allocation * Ideal for straightforward refunds where you want to refund the full amount of a target **Itemized Dedicated Refunds** (see [Itemized Refunds](#itemized-refund-creation-parameters)): * Created when you provide the `line_items` parameter with detailed allocation breakdowns * You have full control over how the refund amount is distributed across different ledger accounts * Required for complex refunds involving multiple accounts or partial amounts ### Create Dedicated Refund Parameters Object External ID for the refund within your platform. **Idempotency key.** The [Account Identifier](/api-reference/ledger/account-identifier) for the refund allocation. If not specified, will use the appropriate account based on the target. Detailed line items for the refund allocation. Use this for itemized refunds where you need to specify the exact amounts and accounts. Amount for this line item in cents. The [Account Identifier](/api-reference/ledger/account-identifier) for this line item. Tags for this line item. Memo for this line item. Metadata for this line item. Reference number for this line item. When the refund was completed. Processing fee for the refund, in cents. Defaults to 0. Method used to make the refund. Values can be: `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, `OTHER` Processor used to make the refund, if any. List of payment fees that were refunded as part of this refund. The [Account Identifier](/api-reference/ledger/account-identifier) for the refunded fee. Description of the fee being refunded. Amount of the fee refund in cents. Tags to apply to the refund. Tags are key-value pairs that can be used to categorize and filter refunds. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If the dimension doesn't exist, this will be used as its display name. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value. If the value doesn't exist, this will be used as its display name. Any text you would like to associate with the refund. Arbitrary metadata you can include with the refund. Any (typically user-visible) identifier you would like to associate with the refund. ### Example: Invoice with Dedicated Refunds ```json theme={null} { "external_id": "invoice-123", "sent_at": "2024-04-02T09:02:00Z", "customer_external_id": "customer-456", "line_items": [ { "product": "Widget Pro", "unit_price": 2500, "quantity": 4, "dedicated_refunds": [ { "external_id": "refund-widget-1", "line_items": [ { "amount": 1000, "account_identifier": { "type": "StableName", "stable_name": "CUSTOMER_REFUNDS" } } ], "completed_at": "2024-04-03T10:00:00Z", "method": "CREDIT_CARD", "processor": "RAINFOREST", "memo": "Partial (itemized) refund for damaged item" } ] } ], "payments": [ { "external_id": "payment-123", "method": "CREDIT_CARD", "amount": 5000, "dedicated_refunds": [ { "external_id": "refund-processing-fee", "completed_at": "2024-04-03T10:00:00Z", "method": "CREDIT_CARD", "processor": "RAINFOREST", "memo": "Full (simple) payment refund" } ] }, { "external_id": "payment-xyz", "method": "CREDIT_CARD", "amount": 7000 } ], "dedicated_refunds": [ { "external_id": "refund-invoice-discount", "line_items": [ { "amount": 250, "account_identifier": { "type": "StableName", "stable_name": "CUSTOMER_REFUNDS" } } ], "completed_at": "2024-04-03T10:00:00Z", "method": "CREDIT_CARD", "processor": "RAINFOREST", "memo": "Partial (itemized) refund for whole invoice" } ] } ``` # Balance Sheet object Source: https://docs.layerfi.com/api-reference/reports/balance-sheet/balance-sheet A Balance Sheet object represents a balance sheet that has been generated for a [Business](/api-reference/business/business). Balance Sheets are generated for a specific effective date and only contain information for categorized transactions that have been journaled to the general ledger. ### Attributes ID of the Business the balance sheet was generated for. Resource type. Value will be "Balance\_Sheet" Effective date for the balance sheet. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the assets on the balance sheet. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the liabilities and equity on the balance sheet. A boolean representing whether all imported transactions within the effective date have been categorized. If FALSE, there are uncategorized transactions. ```json theme={null} { "data": { "type": "Balance_Sheet", "business_id": "47bdad2a-d670-4295-ae52-6f263e91caf2", "effective_date": "2024-06-07T00:15:29.477022Z", "assets": { "name": "Assets", "display_name": "Assets", "value": 50425, "line_items": [ { "name": "Bank Accounts", "display_name": "Bank Accounts", "value": 57425, "line_items": [ { "name": "Default Test Client Banking", "display_name": "Default Test Client Banking", "value": 57425, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Accounts Receivable (A/R)", "display_name": "Accounts Receivable (A/R)", "value": 0, "line_items": [], "is_contra": false }, { "name": "Inventory", "display_name": "Inventory", "value": 0, "line_items": [], "is_contra": false }, { "name": "Fixed Assets", "display_name": "Fixed Assets", "value": -7000, "line_items": [ { "name": "Machinery & Equipment", "display_name": "Machinery & Equipment", "value": 0, "line_items": [], "is_contra": false }, { "name": "Laser", "display_name": "Laser", "value": 0, "line_items": [], "is_contra": false }, { "name": "Computer Equipment", "display_name": "Computer Equipment", "value": 0, "line_items": [], "is_contra": false }, { "name": "Furniture & Fixtures", "display_name": "Furniture & Fixtures", "value": 0, "line_items": [], "is_contra": false }, { "name": "Accumulated Depreciation", "display_name": "Accumulated Depreciation", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Cash", "display_name": "Cash", "value": 0, "line_items": [], "is_contra": false }, { "name": "Undeposited funds", "display_name": "Undeposited funds", "value": 0, "line_items": [], "is_contra": false }, { "name": "Payment Processor Clearing Accounts", "display_name": "Payment Processor Clearing Accounts", "value": 0, "line_items": [ { "name": "Stripe Clearing", "display_name": "Stripe Clearing", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false } ], "is_contra": false }, "liabilities_and_equity": { "name": "Liabilities and Equity", "display_name": "Liabilities and Equity", "value": 50425, "line_items": [ { "name": "Liabilities", "display_name": "Liabilities", "value": 50000, "line_items": [ { "name": "Accounts Payable (A/P)", "display_name": "Accounts Payable (A/P)", "value": 50000, "line_items": [], "is_contra": false }, { "name": "Credit Cards", "display_name": "Credit Cards", "value": 0, "line_items": [], "is_contra": false }, { "name": "Shareholder Loans", "display_name": "Shareholder Loans", "value": 0, "line_items": [], "is_contra": false }, { "name": "Payroll Liabilities", "display_name": "Payroll Liabilities", "value": 0, "line_items": [], "is_contra": false }, { "name": "Sales Tax Payable", "display_name": "Sales Tax Payable", "value": 0, "line_items": [], "is_contra": false }, { "name": "Line of Credit", "display_name": "Line of Credit", "value": 0, "line_items": [], "is_contra": false }, { "name": "Notes Payable", "display_name": "Notes Payable", "value": 0, "line_items": [], "is_contra": false }, { "name": "Collected Tips", "display_name": "Collected Tips", "value": 0, "line_items": [], "is_contra": false }, { "name": "Unearned Revenue", "display_name": "Unearned Revenue", "value": 0, "line_items": [], "is_contra": false }, { "name": "Undeposited Payments", "display_name": "Undeposited Payments", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Equities", "display_name": "Equities", "value": 425, "line_items": [ { "name": "Revenue", "display_name": "Revenue", "value": 400, "line_items": [], "is_contra": false }, { "name": "Expenses", "display_name": "Expenses", "value": -20, "line_items": [], "is_contra": true }, { "name": "Contributions", "display_name": "Contributions", "value": 5, "line_items": [], "is_contra": false }, { "name": "Distributions", "display_name": "Distributions", "value": 0, "line_items": [], "is_contra": false }, { "name": "Common Stock", "display_name": "Common Stock", "value": 0, "line_items": [], "is_contra": false }, { "name": "Additional Paid-In Capital", "display_name": "Additional Paid-In Capital", "value": 0, "line_items": [], "is_contra": false }, { "name": "Retained Earnings", "display_name": "Retained Earnings", "value": 0, "line_items": [], "is_contra": false }, { "name": "Accumulated Adjustments", "display_name": "Accumulated Adjustments", "value": 0, "line_items": [], "is_contra": false }, { "name": "Opening Balance Equity", "display_name": "Opening Balance Equity", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false } ], "is_contra": false }, "fully_categorized": true } } ``` # Retrieve a Balance Sheet Source: https://docs.layerfi.com/api-reference/reports/balance-sheet/get-balance-sheet GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/balance-sheet This endpoint retrieves a balance sheet. ID of the Business to generate a Balance Sheet for. ### Response Returns the generated [Balance Sheet](/api-reference/reports/balance-sheet/balance-sheet). ```bash Request theme={null} curl -X GET 'https://sandbox.layerfi.com/v1/businesses/47bdad2a-d670-4295-ae52-6f263e91caf2/reports/balance-sheet?effective_date=2023-01-01T00:00:00-06:00' \ -H 'Authorization: Bearer ' ``` ```json Response theme={null} { "data": { "type": "Balance_Sheet", "business_id": "47bdad2a-d670-4295-ae52-6f263e91caf2", "effective_date": "2024-06-07T00:15:29.477022Z", "assets": { "name": "Assets", "display_name": "Assets", "value": 50425, "line_items": [ { "name": "Bank Accounts", "display_name": "Bank Accounts", "value": 57425, "line_items": [ { "name": "Default Test Client Banking", "display_name": "Default Test Client Banking", "value": 57425, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Accounts Receivable (A/R)", "display_name": "Accounts Receivable (A/R)", "value": 0, "line_items": [], "is_contra": false }, { "name": "Inventory", "display_name": "Inventory", "value": 0, "line_items": [], "is_contra": false }, { "name": "Fixed Assets", "display_name": "Fixed Assets", "value": -7000, "line_items": [ { "name": "Machinery & Equipment", "display_name": "Machinery & Equipment", "value": 0, "line_items": [], "is_contra": false }, { "name": "Laser", "display_name": "Laser", "value": 0, "line_items": [], "is_contra": false }, { "name": "Computer Equipment", "display_name": "Computer Equipment", "value": 0, "line_items": [], "is_contra": false }, { "name": "Furniture & Fixtures", "display_name": "Furniture & Fixtures", "value": 0, "line_items": [], "is_contra": false }, { "name": "Accumulated Depreciation", "display_name": "Accumulated Depreciation", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Cash", "display_name": "Cash", "value": 0, "line_items": [], "is_contra": false }, { "name": "Undeposited funds", "display_name": "Undeposited funds", "value": 0, "line_items": [], "is_contra": false }, { "name": "Payment Processor Clearing Accounts", "display_name": "Payment Processor Clearing Accounts", "value": 0, "line_items": [ { "name": "Stripe Clearing", "display_name": "Stripe Clearing", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false } ], "is_contra": false }, "liabilities_and_equity": { "name": "Liabilities and Equity", "display_name": "Liabilities and Equity", "value": 50425, "line_items": [ { "name": "Liabilities", "display_name": "Liabilities", "value": 50000, "line_items": [ { "name": "Accounts Payable (A/P)", "display_name": "Accounts Payable (A/P)", "value": 50000, "line_items": [], "is_contra": false }, { "name": "Credit Cards", "display_name": "Credit Cards", "value": 0, "line_items": [], "is_contra": false }, { "name": "Shareholder Loans", "display_name": "Shareholder Loans", "value": 0, "line_items": [], "is_contra": false }, { "name": "Payroll Liabilities", "display_name": "Payroll Liabilities", "value": 0, "line_items": [], "is_contra": false }, { "name": "Sales Tax Payable", "display_name": "Sales Tax Payable", "value": 0, "line_items": [], "is_contra": false }, { "name": "Line of Credit", "display_name": "Line of Credit", "value": 0, "line_items": [], "is_contra": false }, { "name": "Notes Payable", "display_name": "Notes Payable", "value": 0, "line_items": [], "is_contra": false }, { "name": "Collected Tips", "display_name": "Collected Tips", "value": 0, "line_items": [], "is_contra": false }, { "name": "Unearned Revenue", "display_name": "Unearned Revenue", "value": 0, "line_items": [], "is_contra": false }, { "name": "Undeposited Payments", "display_name": "Undeposited Payments", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false }, { "name": "Equities", "display_name": "Equities", "value": 425, "line_items": [ { "name": "Revenue", "display_name": "Revenue", "value": 400, "line_items": [], "is_contra": false }, { "name": "Expenses", "display_name": "Expenses", "value": -20, "line_items": [], "is_contra": true }, { "name": "Contributions", "display_name": "Contributions", "value": 5, "line_items": [], "is_contra": false }, { "name": "Distributions", "display_name": "Distributions", "value": 0, "line_items": [], "is_contra": false }, { "name": "Common Stock", "display_name": "Common Stock", "value": 0, "line_items": [], "is_contra": false }, { "name": "Additional Paid-In Capital", "display_name": "Additional Paid-In Capital", "value": 0, "line_items": [], "is_contra": false }, { "name": "Retained Earnings", "display_name": "Retained Earnings", "value": 0, "line_items": [], "is_contra": false }, { "name": "Accumulated Adjustments", "display_name": "Accumulated Adjustments", "value": 0, "line_items": [], "is_contra": false }, { "name": "Opening Balance Equity", "display_name": "Opening Balance Equity", "value": 0, "line_items": [], "is_contra": false } ], "is_contra": false } ], "is_contra": false }, "fully_categorized": true } } ``` # Cash Flow Statement object Source: https://docs.layerfi.com/api-reference/reports/cash-flow-statement/cash-flow-statement A Cash Flow Statement object represents a cash flow statement that has been generated for a [Business](/api-reference/business/business). ### Attributes The start date of the period for which the cash flow statement is generated. The end date of the period for which the cash flow statement is generated. List of [Line Item](/api-reference/ledger/chart#ledger-account-line-item-object) objects detailing the cash flows from operational activities, with their entries omitted. List of [Line Item](/api-reference/ledger/chart#ledger-account-line-item-object) objects detailing the cash flows from investing activities, with their entries omitted. List of [Line Item](/api-reference/ledger/chart#ledger-account-line-item-object) objects detailing the cash flows from financing activities, with their entries omitted. Net increase or decrease in cash during the period, in cents. Cash balance at the beginning of the period, in cents. Cash balance at the end of the period, in cents. ```json theme={null} { "data": { "type": "Cash_Flow_Statement", "period_start_date": "2023-01-01T00:00:00-06:00", "period_end_date": "2023-12-31T00:00:00-06:00", "cash_from_operations": [ { "id": "ab16f453-6b0f-416d-bcc9-92edba3b6e0a", "name": "Cost of Goods Sold", "stable_name": "COGS", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "balance": 5156220 }, { "id": "ab5f3795-734e-4b12-b9a1-c32ec4b43c2e", "name": "Operating Expenses", "stable_name": "OPERATING_EXPENSES", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "balance": 6395004 } ], "cash_from_investing": [ { "id": "43f6887f-d24a-401f-bd0d-47a352185039", "name": "Property and Equipment", "stable_name": "PROPERTY_AND_EQUIPMENT", "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "balance": 0 } ], "cash_from_financing": [ { "id": "aa96d895-96b7-40d9-aa1f-52bbd1d1651e", "name": "Equity", "stable_name": "EQUITY", "normality": "CREDIT", "account_type": { "value": "EQUITY", "display_name": "Equities" }, "balance": -367655 }, { "id": "02369cdf-3356-4747-bce4-438cac3e35d3", "name": "Liabilities", "stable_name": "LIABILITIES", "normality": "CREDIT", "account_type": { "value": "LIABILITY", "display_name": "Liabilities" }, "balance": 0 } ], "net_increase_in_cash": 1750000, "cash_at_period_start": 1000000, "cash_at_period_end": 2750000 } } ``` # Retrieve a Cash Flow Statement Source: https://docs.layerfi.com/api-reference/reports/cash-flow-statement/get-cash-flow-statement GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/cash-flow-statement This endpoint retrieves a cash flow statement. ID of the Business to generate a Cash Flow Statement for. ### Response Returns the generated [Cash Flow Statement](/api-reference/reports/cash-flow-statement/cash-flow-statement). ```bash Request theme={null} curl -X GET 'https://sandbox.layerfi.com/v1/businesses/47bdad2a-d670-4295-ae52-6f263e91caf2/reports/cash-flow-statement?effective_date=2023-01-01T00:00:00-06:00' \ -H 'Authorization: Bearer ' ``` ```json Response theme={null} { "data": { "type": "Cash_Flow_Statement", "period_start_date": "2023-01-01T00:00:00-06:00", "period_end_date": "2023-12-31T00:00:00-06:00", "cash_from_operations": [ { "id": "ab16f453-6b0f-416d-bcc9-92edba3b6e0a", "name": "Cost of Goods Sold", "stable_name": "COGS", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "balance": 5156220 }, { "id": "ab5f3795-734e-4b12-b9a1-c32ec4b43c2e", "name": "Operating Expenses", "stable_name": "OPERATING_EXPENSES", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "balance": 6395004 } ], "cash_from_investing": [ { "id": "43f6887f-d24a-401f-bd0d-47a352185039", "name": "Property and Equipment", "stable_name": "PROPERTY_AND_EQUIPMENT", "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "balance": 0 } ], "cash_from_financing": [ { "id": "aa96d895-96b7-40d9-aa1f-52bbd1d1651e", "name": "Equity", "stable_name": "EQUITY", "normality": "CREDIT", "account_type": { "value": "EQUITY", "display_name": "Equities" }, "balance": -367655 }, { "id": "02369cdf-3356-4747-bce4-438cac3e35d3", "name": "Liabilities", "stable_name": "LIABILITIES", "normality": "CREDIT", "account_type": { "value": "LIABILITY", "display_name": "Liabilities" }, "balance": 0 } ], "net_increase_in_cash": 1750000, "cash_at_period_start": 1000000, "cash_at_period_end": 2750000 } } ``` # Retrieve a Profit and Loss Source: https://docs.layerfi.com/api-reference/reports/pnl/get GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/profit-and-loss This endpoint retrieves a profit and loss. ID of the Business to generate a Profit and Loss report for. The start date for the Profit and Loss report in ISO-8601 format. Either `start_date` and `end_date` or `year` and `month` must be provided. The end date for the Profit and Loss report in ISO-8601 format. Either `start_date` and `end_date` or `year` and `month` must be provided. The year for the Profit and Loss report. Either `start_date` and `end_date` or `year` and `month` must be provided. The month for the Profit and Loss report. Either `start_date` and `end_date` or `year` and `month` must be provided. The reporting basis for the report (e.g., "CASH" or "ACCRUAL"). Filter the report by specific tags. If `tag_key` is provided, `tag_values` must also be provided. Filter the report by specific tags. Multiple values can be specified, separated by commas. If `tag_values` is provided, `tag_key` must also be provided. When set to `true` (default), uncategorized transactions that have a suggested transfer match are excluded from the uncategorized inflows and outflows totals. Set to `false` to include those transactions in the uncategorized totals. This is excluded by default so that we don't unnecessarily bloat your revenue and expenses. ### Response Returns the generated [Profit and Loss](/api-reference/reports/pnl/pnl) report. ```bash Request theme={null} curl -X GET 'https://sandbox.layerfi.com/v1/businesses/d2f6d97f-3345-4299-9ec2-468738c5d536/reports/profit-and-loss?start_date=2023-01-01T00:00:00-06:00&end_date=2023-12-01T00:00:00-06:00' \ -H 'Authorization: Bearer ' ``` ```json Response theme={null} { "data": { "type": "Profit_And_Loss", "business_id": "d2f6d97f-3345-4299-9ec2-468738c5d536", "start_date": "2023-01-01T06:00:00Z", "end_date": "2023-12-01T06:00:00Z", "income": { "name": "REVENUE", "display_name": "Revenue", "value": 49397, "line_items": [ { "name": "SERVICES_REVENUE", "display_name": "Service Revenue", "value": 46897, "line_items": null }, { "name": "GOODS_REVENUE", "display_name": "Sale of Goods Revenue", "value": 0, "line_items": null }, { "name": "DISCOUNTS", "display_name": "Discounts & Refunds", "value": 2500, "line_items": null } ] }, "cost_of_goods_sold": { "name": "COGS", "display_name": "Cost of Goods Sold", "value": 8026, "line_items": [ { "name": "JOB_SUPPLIES", "display_name": "Job supplies", "value": 8026, "line_items": null } ] }, "gross_profit": 41371, "expenses": { "name": "OPERATING_EXPENSES", "display_name": "Operating Expenses", "value": 0, "line_items": [ { "name": "INSURANCE", "display_name": "Insurance", "value": 0, "line_items": null }, { "name": "RENT_EXPENSE", "display_name": "Rent", "value": 0, "line_items": null }, { "name": "UTILITIES", "display_name": "Utilities", "value": 0, "line_items": null }, { "name": "EQUIPMENT", "display_name": "Equipment & Tools", "value": 0, "line_items": null }, { "name": "ADVERTISING", "display_name": "Advertising", "value": 0, "line_items": null }, { "name": "VEHICLE_EXPENSES", "display_name": "Vehicle Expenses", "value": 0, "line_items": null } ] }, "profit_before_taxes": 41371, "taxes": { "name": "TAXES", "display_name": "Taxes", "value": 0, "line_items": null }, "net_profit": 41371, "other_outflows": null, "personal_expenses": null, "fully_categorized": true } } ``` # Retrieve Profit and Loss Details Source: https://docs.layerfi.com/api-reference/reports/pnl/get-pnl-details GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/profit-and-loss-details This endpoint retrieves the Profit and Loss Details for a business. ID of the Business to generate a Profit and Loss Details report for. ### Response Returns the generated [Profit and Loss Details](/api-reference/reports/pnl/pnl-details) report. ```bash Request theme={null} curl -X GET 'https://sandbox.layerfi.com/v1/businesses/f9baa8fd-9413-4bcf-810b-6d32604de649/reports/profit-and-loss-details?month=3&year=2024&reporting_basis=CASH' \ -H 'Authorization: Bearer ' ``` ```json Response theme={null} { "data": { "type": "Profit_And_Loss_Details", "cash_transactions": [ { "transaction": { "id": "0e603dc0-e140-4d7a-8f16-99d1aa5a8ad2", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "source": "UNIT", "source_transaction_id": "12345-FakeCorp-1234-expense-199", "source_account_id": "1234", "imported_at": "2024-05-23T03:51:15.836137Z", "date": "2024-03-01T20:00:00Z", "direction": "DEBIT", "amount": 250000, "counterparty_name": "WeWork", "description": null, "account_name": "Layer Demo Banking", "categorization_status": "CATEGORIZED" }, "ledger_entries": [ { "id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "ledger_id": "0f4bb90e-1c43-4994-81e8-aac4dcd6e380", "agent": "LAYER_AUTO", "entry_type": "EXPENSE", "date": "2024-05-23T03:52:54.880652Z", "entry_at": "2024-03-01T20:00:00Z", "reversal_of_id": null, "reversal_id": null, "line_items": [ { "id": "079444d8-cf57-49ac-955e-6edc97d746d5", "entry_id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "account": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2", "name": "Rent", "stable_name": "RENT_EXPENSE", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" } }, "amount": 250000, "direction": "DEBIT", "entry_at": "2024-03-01T20:00:00Z", "createdAt": "2024-05-23T03:52:54.880652Z" }, { "id": "8ac6683e-db36-4dd3-a35c-a7adb3e62066", "entry_id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "account": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa", "name": "Layer Demo Banking", "stable_name": null, "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "account_subtype": { "value": "BANK_ACCOUNTS", "display_name": "Bank Accounts" } }, "amount": 250000, "direction": "CREDIT", "entry_at": "2024-03-01T20:00:00Z", "createdAt": "2024-05-23T03:52:54.880652Z" } ] } ], "combined_result": [ { "account": { "account_id": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2" }, "name": "Rent", "stable_name": { "stable_name": "RENT_EXPENSE" }, "account_normality": "DEBIT", "account_type": "EXPENSE", "account_subtype": "OPERATING_EXPENSES" }, "amount": 250000, "direction": "DEBIT" }, { "account": { "account_id": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa" }, "name": "Layer Demo Banking", "stable_name": null, "account_normality": "DEBIT", "account_type": "ASSET", "account_subtype": "BANK_ACCOUNTS" }, "amount": 250000, "direction": "CREDIT" } ] }, // more transactions omitted for brevity ], "profit_and_loss_details": { "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "start_date": "2024-03-01T05:00:00Z", "end_date": "2024-04-01T04:00:00Z", "income": { "name": "Revenue", "display_name": "Revenue", "value": 2730000, "line_items": [ { "name": "SERVICES_REVENUE", "display_name": "Service Revenue", "value": 2730000, "line_items": [], "is_contra": false, "entries": [ { "id": "allocation-f61a2686-2085-4fe1-96a3-2103c93f9074-f61a2686-2085-4fe1-96a3-2103c93f9074-0", "entry_id": "allocation-f61a2686-2085-4fe1-96a3-2103c93f9074-f61a2686-2085-4fe1-96a3-2103c93f9074", "account": { "id": "59d427f8-4681-4a8c-926e-3c3963b24e8f", "name": "Service Revenue", "stable_name": "SERVICES_REVENUE", "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "SALES", "display_name": "Sales" } }, "amount": 420000, "direction": "CREDIT", "date": "2024-03-01T20:00:00Z", "source": { "type": "Invoice_Ledger_Entry_Source", "invoice_id": "679b689f-0a29-47f1-84cf-c4cef492ef5b", "external_id": null, "invoice_number": null, "recipient_name": "FakeCorp 94720", "date": "2024-03-01T20:00:00Z", "amount": 420000, "entity_name": "Invoice", "display_description": "Invoice (March 1)" } }, ] } ], "is_contra": false, "entries": [] }, "cost_of_goods_sold": { "name": "Cost of Goods Sold", "display_name": "Cost of Goods Sold", "value": 428940, "line_items": [], "is_contra": false, "entries": [] }, "gross_profit": 2301060, "expenses": { "name": "Expenses", "display_name": "Expenses", "value": 560695, "line_items": [], "is_contra": false, "entries": [] }, "profit_before_taxes": 1740365, "taxes": { "name": "Taxes", "display_name": "Taxes", "value": 0, "line_items": [], "is_contra": false, "entries": [] }, "net_profit": 1740365, "fully_categorized": true }, "balances": [ { "account": { "account_id": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2" }, "name": "Rent", "stable_name": { "stable_name": "RENT_EXPENSE" }, "account_normality": "DEBIT", "account_type": "EXPENSE", "account_subtype": "OPERATING_EXPENSES" }, "amount": 250000, "direction": "DEBIT" }, { "account": { "account_id": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa" }, "name": "Layer Demo Banking", "stable_name": null, "account_normality": "DEBIT", "account_type": "ASSET", "account_subtype": "BANK_ACCOUNTS" }, "amount": 1712350, "direction": "DEBIT" }, ] } } ``` # Profit and Loss object Source: https://docs.layerfi.com/api-reference/reports/pnl/pnl A Profit and Loss object represents a profit and loss report that has been generated for a [Business](/api-reference/business/business). Profit and Loss reports are generated for a specific time range and only contain information for categorized transactions that have been journaled to the general ledger. ### Attributes ID of the Business the profit and loss report was generated for. Resource type. Value will be "Profit\_And\_Loss" Start date for data included in the report. End date for data included in the report. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the income line items in the report. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the cost of goods sold line items in the report. Gross profit in cents. Calculated by subtracting total cost\_of\_sales line items from total income line items. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the expense line items in the report. Net profit before taxes in cents. Calculated by subtracting total expenses line items from gross\_profit. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing the tax line items in the report. Net profit in cents. Calculated by subtracting total taxes line items from profit\_before\_taxes An optional array of [Line Item](/api-reference/reports/pnl/pnl#line-item-object) objects representing additional line items below the net profit line in the report. This will be used when alternative P\&L structures and groupings have been configured. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing business outflow transactions that are not part of the profit and loss statement. A [Line Item](/api-reference/reports/pnl/pnl#line-item-object) object representing personal expense transactions that are not part of the profit and loss statement. A boolean representing whether all imported transactions within the report date range have been categorized. If FALSE, there are uncategorized transactions within the selected date range, indicating the provided report data may be incomplete. #### Line Item object Enum name for the line item. Ex. "REVENUE" Display name for the line item. Ex. "Revenue" The value of the line item in cents. An array of [Line Item](/api-reference/reports/pnl/pnl#line-item-object) objects representing child line items within the report section. #### Ledger Entry Source Object The `LedgerEntrySource` represents the source of a ledger entry. This is a polymorphic type that can be any of the following: * **Transaction Ledger Entry Source**: Represents entries originating from bank transactions. * **Invoice Ledger Entry Source**: Represents entries related to specific invoices. * **Invoice Write-Off Ledger Entry Source**: Details entries for write-offs associated with invoices. * **Manual Ledger Entry Source**: Represents manually created ledger entries. * **Invoice Payment Ledger Entry Source**: Represents payments made against invoices. * **Refund Ledger Entry Source**: Represents refund transactions. * **Opening Balance Ledger Entry Source**: Used to represent the initial balances when setting up accounts. * **Payout Ledger Entry Source**: Represents payouts processed through external payment processors. ```json Profit and Loss theme={null} { "data":{ "type":"Profit_And_Loss", "business_id":"d2f6d97f-3345-4299-9ec2-468738c5d536", "start_date":"2023-01-01T06:00:00Z", "end_date":"2023-12-01T06:00:00Z", "income":{ "name":"REVENUE", "display_name":"Revenue", "value":49397, "line_items":[ { "name":"SERVICES_REVENUE", "display_name":"Service Revenue", "value":46897, "line_items":null }, { "name":"GOODS_REVENUE", "display_name":"Sale of Goods Revenue", "value":0, "line_items":null }, { "name":"DISCOUNTS", "display_name":"Discounts & Refunds", "value":2500, "line_items":null } ] }, "cost_of_goods_sold":{ "name":"COGS", "display_name":"Cost of Goods Sold", "value":8026, "line_items":[ { "name":"JOB_SUPPLIES", "display_name":"Job supplies", "value":8026, "line_items":null } ] }, "gross_profit":41371, "expenses":{ "name":"OPERATING_EXPENSES", "display_name":"Operating Expenses", "value":0, "line_items":[ { "name":"INSURANCE", "display_name":"Insurance", "value":0, "line_items":null }, { "name":"RENT_EXPENSE", "display_name":"Rent", "value":0, "line_items":null }, { "name":"UTILITIES", "display_name":"Utilities", "value":0, "line_items":null }, { "name":"EQUIPMENT", "display_name":"Equipment & Tools", "value":0, "line_items":null }, { "name":"ADVERTISING", "display_name":"Advertising", "value":0, "line_items":null }, { "name":"VEHICLE_EXPENSES", "display_name":"Vehicle Expenses", "value":0, "line_items":null } ] }, "profit_before_taxes":41371, "taxes":{ "name":"TAXES", "display_name":"Taxes", "value":0, "line_items":null }, "net_profit":41371, "other_outflows":null, "personal_expenses":null, "fully_categorized":true } } ``` # Profit and Loss Details object Source: https://docs.layerfi.com/api-reference/reports/pnl/pnl-details The Profit and Loss Details object provides a detailed view of the transactions and ledger entries that contribute to a business's profit and loss statement for a specific reporting period. ### Attributes An array of [Cash Transaction Effect](/api-reference/reports/pnl/pnl-details#cash-transaction-effect-object) objects, detailing individual transactions and their corresponding ledger entries affecting the profit and loss statement. A [Profit and Loss Details Body](/api-reference/reports/pnl/pnl-details#profit-and-loss-details-body-object) object, containing a detailed breakdown of income, expenses, and net results for the report period. A list of Line Item Input objects representing the aggregated balance of accounts impacted within the reporting period. #### Cash Transaction Effect object The basic data of the [Bank Transaction Object](/api-reference/bank-transaction/bank-transaction). An array of ledger entries related to the [Bank Transaction Object](/api-reference/bank-transaction/bank-transaction). An array of [Line Item](/api-reference/reports/pnl/pnl#line-item-object) objects representing the combined results of the transaction's effects on different accounts. #### Profit and Loss Details Body object ID of the Business the report was generated for. Start date for data included in the report. End date for data included in the report. Income [Line Item With Details](/api-reference/reports/pnl/pnl-details#line-item-with-details-object) objects. Cost of goods sold [Line Item With Details](/api-reference/reports/pnl/pnl-details#line-item-with-details-object) objects. Gross profit. Expense [Line Item With Details](/api-reference/reports/pnl/pnl-details#line-item-with-details-object) objects. Profit before taxes. Tax [Line Item With Details](/api-reference/reports/pnl/pnl-details#line-item-with-details-object) objects. Net profit after taxes. Whether all transactions within the period are fully categorized. #### Line Item With Details object Name identifier for the line item. Display name for the line item. The value of the line item in cents. Child [Line Item With Details](/api-reference/reports/pnl/pnl-details#line-item-with-details-object) objects, if any. Indicates if the line item is a contra account. Ledger entries associated with the line item. #### Ledger Line Item With Source Unique identifier for the line item. Identifier of the ledger entry to which this line item belongs. The account affected by this line item. The monetary amount of the line item in cents. Direction of the transaction, either 'IN' for inflows or 'OUT' for outflows. Date when the line item was recorded. The [Ledger Entry Source](/api-reference/reports/pnl/pnl#ledger-entry-source-object), detailed by the specific subtype which includes context-specific fields. ```json Response theme={null} { "data": { "type": "Profit_And_Loss_Details", "cash_transactions": [ { "transaction": { "id": "0e603dc0-e140-4d7a-8f16-99d1aa5a8ad2", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "source": "UNIT", "source_transaction_id": "12345-FakeCorp-1234-expense-199", "source_account_id": "1234", "imported_at": "2024-05-23T03:51:15.836137Z", "date": "2024-03-01T20:00:00Z", "direction": "DEBIT", "amount": 250000, "counterparty_name": "WeWork", "description": null, "account_name": "Layer Demo Banking", "categorization_status": "CATEGORIZED" }, "ledger_entries": [ { "id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "ledger_id": "0f4bb90e-1c43-4994-81e8-aac4dcd6e380", "agent": "LAYER_AUTO", "entry_type": "EXPENSE", "date": "2024-05-23T03:52:54.880652Z", "entry_at": "2024-03-01T20:00:00Z", "reversal_of_id": null, "reversal_id": null, "line_items": [ { "id": "079444d8-cf57-49ac-955e-6edc97d746d5", "entry_id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "account": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2", "name": "Rent", "stable_name": "RENT_EXPENSE", "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expenses" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" } }, "amount": 250000, "direction": "DEBIT", "entry_at": "2024-03-01T20:00:00Z", "createdAt": "2024-05-23T03:52:54.880652Z" }, { "id": "8ac6683e-db36-4dd3-a35c-a7adb3e62066", "entry_id": "08bd0b04-89fe-406e-b5f7-6b0fb65cc799", "account": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa", "name": "Layer Demo Banking", "stable_name": null, "normality": "DEBIT", "account_type": { "value": "ASSET", "display_name": "Assets" }, "account_subtype": { "value": "BANK_ACCOUNTS", "display_name": "Bank Accounts" } }, "amount": 250000, "direction": "CREDIT", "entry_at": "2024-03-01T20:00:00Z", "createdAt": "2024-05-23T03:52:54.880652Z" } ] } ], "combined_result": [ { "account": { "account_id": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2" }, "name": "Rent", "stable_name": { "stable_name": "RENT_EXPENSE" }, "account_normality": "DEBIT", "account_type": "EXPENSE", "account_subtype": "OPERATING_EXPENSES" }, "amount": 250000, "direction": "DEBIT" }, { "account": { "account_id": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa" }, "name": "Layer Demo Banking", "stable_name": null, "account_normality": "DEBIT", "account_type": "ASSET", "account_subtype": "BANK_ACCOUNTS" }, "amount": 250000, "direction": "CREDIT" } ] }, // more transactions omitted for brevity ], "profit_and_loss_details": { "business_id": "f9baa8fd-9413-4bcf-810b-6d32604de649", "start_date": "2024-03-01T05:00:00Z", "end_date": "2024-04-01T04:00:00Z", "income": { "name": "Revenue", "display_name": "Revenue", "value": 2730000, "line_items": [ { "name": "SERVICES_REVENUE", "display_name": "Service Revenue", "value": 2730000, "line_items": [], "is_contra": false, "entries": [ { "id": "allocation-f61a2686-2085-4fe1-96a3-2103c93f9074-f61a2686-2085-4fe1-96a3-2103c93f9074-0", "entry_id": "allocation-f61a2686-2085-4fe1-96a3-2103c93f9074-f61a2686-2085-4fe1-96a3-2103c93f9074", "account": { "id": "59d427f8-4681-4a8c-926e-3c3963b24e8f", "name": "Service Revenue", "stable_name": "SERVICES_REVENUE", "normality": "CREDIT", "account_type": { "value": "REVENUE", "display_name": "Revenue" }, "account_subtype": { "value": "SALES", "display_name": "Sales" } }, "amount": 420000, "direction": "CREDIT", "date": "2024-03-01T20:00:00Z", "source": { "type": "Invoice_Ledger_Entry_Source", "invoice_id": "679b689f-0a29-47f1-84cf-c4cef492ef5b", "external_id": null, "invoice_number": null, "recipient_name": "FakeCorp 94720", "date": "2024-03-01T20:00:00Z", "amount": 420000, "entity_name": "Invoice", "display_description": "Invoice (March 1)" } }, ] } ], "is_contra": false, "entries": [] }, "cost_of_goods_sold": { "name": "Cost of Goods Sold", "display_name": "Cost of Goods Sold", "value": 428940, "line_items": [], "is_contra": false, "entries": [] }, "gross_profit": 2301060, "expenses": { "name": "Expenses", "display_name": "Expenses", "value": 560695, "line_items": [], "is_contra": false, "entries": [] }, "profit_before_taxes": 1740365, "taxes": { "name": "Taxes", "display_name": "Taxes", "value": 0, "line_items": [], "is_contra": false, "entries": [] }, "net_profit": 1740365, "fully_categorized": true }, "balances": [ { "account": { "account_id": { "id": "50edc310-66ab-4380-b1de-0d52c24821b2" }, "name": "Rent", "stable_name": { "stable_name": "RENT_EXPENSE" }, "account_normality": "DEBIT", "account_type": "EXPENSE", "account_subtype": "OPERATING_EXPENSES" }, "amount": 250000, "direction": "DEBIT" }, { "account": { "account_id": { "id": "5c114ae2-0e6f-4798-8e9a-f7e1c892e2fa" }, "name": "Layer Demo Banking", "stable_name": null, "account_normality": "DEBIT", "account_type": "ASSET", "account_subtype": "BANK_ACCOUNTS" }, "amount": 1712350, "direction": "DEBIT" }, ] } } ``` # Retrieve SMS Configuration Source: https://docs.layerfi.com/api-reference/sms/get GET https://sandbox.layerfi.com/v1/configure/sms Retrieves an SMS configuration for your Layer account. ### Response Returns the selected [SMS Configuration Object](/api-reference/sms/sms) ```bash Request theme={null} curl https://sandbox.layerfi.com/v1/configure/sms \ -H "Authorization: Bearer " ``` ```json Example theme={null} { "data":{ "type":"SMS_Configuration", "sms_enabled": true } } ``` # Set SMS Configuration Source: https://docs.layerfi.com/api-reference/sms/set PUT https://sandbox.layerfi.com/v1/configure/sms Updates the SMS configuration on your Layer account. ### Body Whether SMS is enabled for all businesses. If "true" only businesses with phone numbers will receive SMS. ### Response Returns the created [SMS Configuration Object](/api-reference/sms/sms) ```bash Request theme={null} curl -X PUT https://sandbox.layerfi.com/v1/configure/sms \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "sms_enabled": true }' ``` ```json Example theme={null} { "data":{ "type":"Sms_Configuration", "sms_enabled": true } } ``` # Fetch SMS configuration Source: https://docs.layerfi.com/api-reference/sms/sms get /v1/businesses/{businessId}/sms Returns the SMS settings for the business associated with the provided business id. Currently this setting is an `enabled` flag. Note that SMS must be enabled on both a platform level (see /v1/configure/sms) and an individual business level in order to receive SMS messages. # Abort document upload Source: https://docs.layerfi.com/api-reference/v1/abort-document-upload post /v1/businesses/{businessId}/documents/{documentId}/abort Aborts a multipart upload and archives the document record. Use this endpoint if you need to cancel an upload that is in progress or if an error occurs during upload. Any uploaded parts will be cleaned up from S3. # Activate bookkeeping Source: https://docs.layerfi.com/api-reference/v1/activate-bookkeeping post /v1/businesses/{businessId}/bookkeeping/activate Activates bookkeeping for the specified business. # Archive bank account Source: https://docs.layerfi.com/api-reference/v1/archive-bank-account post /v1/businesses/{businessId}/bank-accounts/{bankAccountId}/archive Archives the specified bank account. Archived accounts are hidden from default list responses unless `include_archived=true` is passed. # Archive business Source: https://docs.layerfi.com/api-reference/v1/archive-business put /v1/businesses/{businessId}/archive Archiving a business makes the business inactive. No additional data will by synchronized and business data is not accessible via normal API endpoints. However, data is retained and can be unarchived in the future. # Archive custom account Source: https://docs.layerfi.com/api-reference/v1/archive-custom-account post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/archive Archives a custom account for a business. This action will prevent the account from syncing new transactions and will remove the account from the Layer dashboard. Previously imported transactions will remain. Archiving can be reversed with the `reactivate` endpoint. # Archive document Source: https://docs.layerfi.com/api-reference/v1/archive-document post /v1/businesses/{businessId}/bank-transactions/{transactionId}/documents/{documentId}/archive Archiving a document makes the document inactive. The document will no longer be accessible via normal API endpoints, but the document is retained and can be unarchived in the future. # Archive external account Source: https://docs.layerfi.com/api-reference/v1/archive-external-account post /v1/businesses/{businessId}/external-accounts/{externalAccountId}/archive Archives an external account for a business. This action will prevent the account from syncing new transactions and will remove the account from the Layer dashboard. Past synced transactions will remain. # Archive bank statement upload Source: https://docs.layerfi.com/api-reference/v1/archive-transaction-upload post /v1/businesses/{businessId}/transaction-uploads/{uploadId}/archive Archives a transaction upload and its imported transactions, reversing their categorization. This endpoint also supports other custom-account transaction uploads. # Archive trial balances import Source: https://docs.layerfi.com/api-reference/v1/archive-trial-balances-import delete /v1/businesses/{businessId}/documents/trial-balances-import Archives the existing trial balances import for a business, including the opening balances and manual journal entries that were created from it. Use this before re-importing when the source data has changed. # Archive vehicle Source: https://docs.layerfi.com/api-reference/v1/archive-vehicle post /v1/businesses/{businessId}/mileage/vehicles/{vehicleId}/archive Archives a vehicle. Archived vehicles are hidden from the default list but can still be retrieved with the allow_archived parameter. # Archive vendor Source: https://docs.layerfi.com/api-reference/v1/archive-vendor post /v1/businesses/{businessId}/vendors/{vendorId}/archive Archives an existing vendor. # Archive an asset Source: https://docs.layerfi.com/api-reference/v1/assets/archive-asset delete /v1/businesses/{businessId}/assets/{assetId} Archives an asset. This also archives the asset's value updates and reverses their ledger entries. # Archive an asset value update Source: https://docs.layerfi.com/api-reference/v1/assets/archive-asset-value-update delete /v1/businesses/{businessId}/assets/value-updates/{valueUpdateId} Archives an asset value update and reverses its ledger entry. # Create an asset Source: https://docs.layerfi.com/api-reference/v1/assets/create-asset post /v1/businesses/{businessId}/assets Creates a fixed asset for the specified business, or upserts an existing one: if an asset with the same `external_id` already exists it is updated in place. A dedicated ledger account is created for new assets. # Create an asset value update Source: https://docs.layerfi.com/api-reference/v1/assets/create-asset-value-update post /v1/businesses/{businessId}/assets/value-updates Records a change to an asset's value (depreciation, improvement, impairment, or revaluation) and posts the corresponding journal entry. Identify the asset with either `asset_id` or `asset_external_id`. # Fetch an asset Source: https://docs.layerfi.com/api-reference/v1/assets/fetch-asset get /v1/businesses/{businessId}/assets/{assetId} Returns a single asset by ID. # Fetch an asset value update Source: https://docs.layerfi.com/api-reference/v1/assets/fetch-asset-value-update get /v1/businesses/{businessId}/assets/value-updates/{valueUpdateId} Returns a single asset value update by ID. # List asset value updates Source: https://docs.layerfi.com/api-reference/v1/assets/list-asset-value-updates get /v1/businesses/{businessId}/assets/value-updates Returns a list of value updates across all assets for the specified business. Results are paginated; see [Pagination](/api-details/pagination) for details. # List assets Source: https://docs.layerfi.com/api-reference/v1/assets/list-assets get /v1/businesses/{businessId}/assets Returns a list of active fixed assets for the specified business. Results are paginated; see [Pagination](/api-details/pagination) for details. # List value updates for an asset Source: https://docs.layerfi.com/api-reference/v1/assets/list-value-updates-for-asset get /v1/businesses/{businessId}/assets/{assetId}/value-updates Returns all value updates recorded for a specific asset. # Update an asset Source: https://docs.layerfi.com/api-reference/v1/assets/update-asset patch /v1/businesses/{businessId}/assets/{assetId} Updates an asset. Only the fields you include are changed. # Update an asset value update Source: https://docs.layerfi.com/api-reference/v1/assets/update-asset-value-update patch /v1/businesses/{businessId}/assets/value-updates/{valueUpdateId} Updates an asset value update. Changing the amount, type, account, or date re-posts the underlying journal entry. # Authorize Quickbooks OAuth flow Source: https://docs.layerfi.com/api-reference/v1/authorize-quickbooks-oauth-flow post /v1/businesses/{businessId}/quickbooks/authorize This API call begins an OAuth flow to connect a Quickbooks account to a business. It will manage the CSRF token state internally and this API call will return the redirect URL for the OAuth flow. # Batch create invoices Source: https://docs.layerfi.com/api-reference/v1/batch-create-invoices post /v1/businesses/{businessId}/invoices/batch Create multiple invoices in a single request. Supports an optional `allow_partial_success` mode that commits each invoice independently, returning `207 Multi-Status` when results are mixed. ## Modes This endpoint supports two modes of operation controlled by the `allow_partial_success` query parameter. ### All-or-nothing (default) When `allow_partial_success` is omitted or `false`, the request behaves as a single atomic operation. If any invoice fails validation or creation, the entire batch is rolled back and a `4xx` error is returned. No invoices are persisted. This is equivalent to the [`/bulk` endpoint](/api-reference/v1/bulk-create-invoices), but always returns the `BatchCreateInvoicesResponse` envelope (with an empty `failed_invoices` map on success). ### Partial success When `allow_partial_success=true`, each invoice is created in its own independent transaction. A failure on one invoice does not roll back invoices that have already succeeded. * `successful_invoices`: invoices that were committed. * `failed_invoices`: a map from a failure key to a failure object with a `message` and optional machine-readable `code` for invoices that did not persist. HTTP `207 Multi-Status` is returned when at least one invoice fails and at least one succeeds. `200 OK` is returned when all invoices succeed (even in partial-success mode). ## Failure keys Each entry in `failed_invoices` is keyed by a human-readable identifier derived in this order: 1. The invoice's `external_id` 2. The invoice's `reference_number` 3. `unknown-N` (zero-based counter) if neither is set If two failed invoices share the same base key, subsequent entries are suffixed with `#1`, `#2`, etc. (e.g. `ref-2`, `ref-2#1`). ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # List bookkeeping periods for a business Source: https://docs.layerfi.com/api-reference/v1/bookkeeping/list-bookkeeping-periods-for-a-business get /v1/businesses/{businessId}/bookkeeping/periods # Bulk categorize transactions Source: https://docs.layerfi.com/api-reference/v1/bulk-categorize-bank-transactions post /v1/businesses/{businessId}/bank-transactions/bulk-categorize Categorize multiple bank transactions in a single request. Each transaction in the request must include a transaction_id and a categorization object specifying how to categorize it. # Bulk create customers Source: https://docs.layerfi.com/api-reference/v1/bulk-create-customers post /v1/businesses/{businessId}/customers/bulk Creates multiple customers for a business in a single request. # Bulk create invoice payments Source: https://docs.layerfi.com/api-reference/v1/bulk-create-invoice-payments post /v1/businesses/{businessId}/invoices/payments/bulk Creates multiple invoice payments in a single request. Each payment in the array uses the same parameters as the single payment endpoint. If a payment includes an `external_id` that matches an existing payment, the existing payment will be updated instead of creating a new one (upsert behavior). # Bulk create invoices Source: https://docs.layerfi.com/api-reference/v1/bulk-create-invoices post /v1/businesses/{businessId}/invoices/bulk Create multiple invoices in a batch operation. This endpoint is useful for backfill use cases when creating a business with an extended invoice history. This endpoint is deprecated. Use the [Batch create invoices](/api-reference/v1/batch-create-invoices) endpoint instead, which supports both all-or-nothing and partial success modes. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: the maximum number of requests that the client is permitted to make per the second * **X-RateLimit-Remaining**: the number of requests remaining in the current rate limit window * **X-RateLimit-Reset**: the UNIX timestamp at which the current rate limit window resets For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Bulk create payouts Source: https://docs.layerfi.com/api-reference/v1/bulk-create-payouts post /v1/businesses/{businessId}/payouts/bulk Creates or updates multiple payouts for a business in a single request. This endpoint uses upsert semantics: if a payout with the same `external_id` already exists, it will be updated; otherwise, a new payout is created. The request will be rejected with a 400 error if any duplicate `external_id` values are present within the same request. # Bulk create refunds Source: https://docs.layerfi.com/api-reference/v1/bulk-create-refunds post /v1/businesses/{businessId}/invoices/refunds/bulk Creates multiple refunds for a business in a single request. This endpoint is idempotent using the `external_id` field as the idempotency key for each refund. # Bulk create trips Source: https://docs.layerfi.com/api-reference/v1/bulk-create-trips post /v1/businesses/{businessId}/mileage/trips/bulk Creates multiple trips for the specified business in a single request. Maximum of 100 trips per request. This endpoint is idempotent using the `external_id` field as the idempotency key for each trip. # Bulk create vehicles Source: https://docs.layerfi.com/api-reference/v1/bulk-create-vehicles post /v1/businesses/{businessId}/mileage/vehicles/bulk Creates multiple vehicles for the specified business in a single request. Maximum of 100 vehicles per request. This endpoint is idempotent using the `external_id` field as the idempotency key for each vehicle. # Bulk delete invoice payments Source: https://docs.layerfi.com/api-reference/v1/bulk-delete-invoice-payments post /v1/businesses/{businessId}/invoices/payments/bulk-delete Deletes multiple invoice payments at once. Maximum 100 payments per request. # Bulk delete invoices Source: https://docs.layerfi.com/api-reference/v1/bulk-delete-invoices post /v1/businesses/{businessId}/invoices/bulk-delete Deletes multiple invoices at once. Maximum 100 invoices per request. All specified invoices must exist and have no payment allocations. # Bulk match Source: https://docs.layerfi.com/api-reference/v1/bulk-match post /v1/businesses/{businessId}/bank-transactions/bulk-match Confirm matches for multiple bank transactions. This should be used when platforms have pre-existing knowledge of what bank transactions are associated with a financial event such as an invoice payment or a payout. This allows you to match multiple transactions in a single request. Use this endpoint when you already know which `suggested_match_id` should be confirmed for each transaction. ## Request Body Provide a `match_pairs` array of transaction-to-suggested-match pairs. Each item in the array confirms one existing suggested match for one transaction. ## Response Returns updated [Bank Transactions](/api-reference/bank-transaction/bank-transaction) objects for matched transactions. # Bulk match or categorize Source: https://docs.layerfi.com/api-reference/v1/bulk-match-or-categorize post /v1/businesses/{businessId}/bank-transactions/bulk-match-or-categorize Match and/or categorize multiple bank transactions in a single request. A single request can apply match actions, categorize actions, or both. You specify the action type per transaction in the `transactions` object. ## Request Body Each key in `transactions` is a transaction id, and each value is either a Match or a Categorize action. ### Match Use `suggested_match_id` to confirm a suggested match for that transaction. ```json theme={null} { "transactions": { "transaction_uuid": { "type": "match", "suggested_match_id": "suggested_match_uuid" }, "next_transaction_uuid": { "type": "match", "suggested_match_id": "suggested_match_uuid" }, // ... } } ``` ### Categorize Use `categorization` to categorize that transaction (single category or split). ```json theme={null} { "transactions": { "transaction_uuid": { "type": "categorize", "categorization": { "type": "Category", "category": { "type": "StableName", "stable_name": "MEALS" } } }, "next_transaction_uuid": { // ... }, // ... } } ``` For more variations for categorization payloads, see [Category payload](/api-reference/v1/categorize-bank-transaction#category). ## Response Returns the updated [Bank Transactions](/api-reference/bank-transaction/bank-transaction) for all processed transactions with the additional fields for [rules suggestions](/api-reference/v1/bulk-match-or-categorize#response-items-update-categorization-rules-suggestion). ### Rule Suggestions Transactions that have been categorized (i.e. taken a category payload) may include `update_categorization_rules_suggestion`. Transactions processed with a match action do not return rule suggestions. For full behavior and integration guidance, see [Categorization Rule Suggestions](/guides/transaction-categorization/rules-suggestion). # Bulk uncategorize transactions Source: https://docs.layerfi.com/api-reference/v1/bulk-uncategorize-bank-transactions post /v1/businesses/{businessId}/bank-transactions/bulk-uncategorize Remove categorization from multiple bank transactions in a single request. # Create service Source: https://docs.layerfi.com/api-reference/v1/catalog/create-service post /v1/businesses/{businessId}/catalog/services Creates a new service in the catalog. If a service with the same external_id already exists, it will be updated instead. # Delete service Source: https://docs.layerfi.com/api-reference/v1/catalog/delete-service delete /v1/businesses/{businessId}/catalog/services/{serviceId} Soft deletes a service. Deleted services are excluded from listings by default but can still be retrieved with allow_deleted=true. # Get service Source: https://docs.layerfi.com/api-reference/v1/catalog/get-service get /v1/businesses/{businessId}/catalog/services/{serviceId} Retrieves a single service by ID. # List services Source: https://docs.layerfi.com/api-reference/v1/catalog/list-services get /v1/businesses/{businessId}/catalog/services Returns a list of services in the service catalog for the specified business. # Update service Source: https://docs.layerfi.com/api-reference/v1/catalog/update-service patch /v1/businesses/{businessId}/catalog/services/{serviceId} Partially updates a service. Only the fields provided in the request body will be updated. # Archive categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/archive-categorization-rule post /v1/businesses/{businessId}/categorization-rules/{categorizationRuleId}/archive Archives (soft-deletes) a categorization rule. The rule will no longer be applied to new transactions. Archived rules can be included in list results using the `include_archived` query parameter. # Create categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/create-categorization-rule post /v1/businesses/{businessId}/categorization-rules Creates a new categorization rule for the business. Rules are applied to matching transactions based on the specified filters. At least one filter must be specified (`merchant_type_filter`, `transaction_description_filter`, `counterparty_filter`, `bank_transaction_type_filter`). ### Applying categorization rules retroactively The rule can optionally be applied retroactively to existing uncategorized transactions via the `apply_retroactively` flag. If `apply_retroactively` is `true`, the rule will be applied to existing uncategorized transactions when the rule is created. If `false`, the rule will only apply to future matching transactions and the preview is informational only. # Get categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/get-categorization-rule get /v1/businesses/{businessId}/categorization-rules/{categorizationRuleId} Returns a single categorization rule by ID. # Get suggested categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/get-suggested-categorization-rule get /v1/businesses/{businessId}/categorization-rules/suggestions/{suggestionId} Returns a single suggested categorization rule update by its id. # List categorization rules Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/list-categorization-rules get /v1/businesses/{businessId}/categorization-rules Returns a list of categorization rules for the specified business. Rules can be filtered by archived status and external IDs. Results are paginated. # List suggested categorization rules Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/list-suggested-categorization-rules get /v1/businesses/{businessId}/categorization-rules/suggestions Returns a paginated list of suggested categorization rule updates for the business. You can set `show_affected_transactions=true` to preview transactions each suggestion would recategorize. For more details about previewing suggestions, see [Rule Suggestions](/guides/transaction-categorization/rules-suggestion#previewing-suggestions). # Reject suggested categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/reject-suggested-categorization-rule delete /v1/businesses/{businessId}/categorization-rules/suggestions/{suggestionId} Rejects a suggested categorization rule update. This marks the suggestion as dismissed and prevents it from being shown again. # Update categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/update-categorization-rule put /v1/businesses/{businessId}/categorization-rules/{categorizationRuleId} Updates an existing categorization rule. This replaces the entire rule content. The rule can optionally be applied retroactively to existing uncategorized transactions. # Update suggested categorization rule Source: https://docs.layerfi.com/api-reference/v1/categorization-rules/update-suggested-categorization-rule patch /v1/businesses/{businessId}/categorization-rules/suggestions/{suggestionId} Updates a suggested categorization rule. Use this endpoint to mark a categorization rules suggestion as not dismissed. This allows the transaction categorization flow to show the suggestion again to the user. ### Undoing a dismissed suggestion Set `dismissed_at` to `null` to mark the suggestion as not dismissed and return it to normal suggestion flow. ### Rejecting a suggestion To reject a suggestion, see [reject suggested categorization rule](/api-reference/v1/categorization-rules/reject-suggested-categorization-rule). Do not use this endpoint to set the dismissed\_at field to some timestamp. # Categorize bank transaction Source: https://docs.layerfi.com/api-reference/v1/categorize-bank-transaction put /v1/businesses/{businessId}/bank-transactions/{transactionId}/categorize Categorize a bank transaction to an account defined in the chart of accounts. A single transaction can be categorized to a single account or split across multiple accounts. You specify the type of categorization based on the request body. ## Request Body: Single Category or Split All categorizations are either a single `Category` or a `Split`. * **Category** is used to categorize the transaction as a single (non-split) category. This will be the case the vast majority of the time. * **Split** is used when the transaction's value should be allocated across multiple categories. This is most commonly the case when multiple items are purchased and those items should be categorized separately. ```mermaid theme={null} graph TD A[Transaction to be categorized] --> B[Single Category] A --> S[Split] B --> C[Category] B --> E[Exclusion] ``` In the diagram above, `Category` and `Exclusion` are both single-category request bodies: they assign the entire transaction to one account identifier. `Split` is a separate request body type that allocates the transaction's value across multiple categories. ### Category Category payloads should have a type field and a category field. This category field can be any [Account Identifier](/api-reference/ledger/account-identifier). The available categories can be fetched using the [Get Chart of Accounts](/api-reference/v1/get-chart-of-accounts) endpoint. #### Option 1: Payload using a StableName Set to `Category` when categorizing the transaction as a single (non-split) category. Set to `StableName` when using a stable name for the category. The stable name from any option, as a string. #### Option 2: Payload using an AccountId Set to `Category` when categorizing the transaction as a single (non-split) category. Set to `AccountId` when using an account ID for the category. The account id, set as a string. #### Option 3: Payload using an Exclusion Set to `Category` when categorizing the transaction as a single (non-split) category, and the category is an exclusion. Set to `Exclusion` when marking the transaction as excluded from categorization. The type of exclusion to apply. Available options are `PERSONAL_EXPENSES`, `PERSONAL_INFLOWS`, `DUPLICATE_TRANSACTION`, or `OTHER_EXCLUSION`. Optional tax code to apply alongside the category (Options 1 and 2 only). See [Tax Code](/api-reference/v1/categorize-bank-transaction#tax-code) below. ### Split Categorizations Splits are specified with an array of categorizations, as above, with an amount tied to each category. The total amount must exactly equal the amount of the transaction. Amounts are always specified in positive cents. #### Split Payload Set to `Split` when categorizing the transaction as a single (non-split) category. Array of entries consisting of a category and an amount. The category payload is the same as for non-split categorizations: an `AccountId`, `StableName`, or `Exclusion` payload (see Options 1–3 above). `AccountId` The account id. `StableName` The stable name string. `Exclusion` Available options are `PERSONAL_EXPENSES`, `PERSONAL_INFLOWS`, `DUPLICATE_TRANSACTION`, or `OTHER_EXCLUSION`. Amount, in cents, to categorize to this portion of the split. Tax code for this split entry. See [Tax Code](/api-reference/v1/categorize-bank-transaction#tax-code) below. ## Tax Code `tax_code` is an optional field, available on both the `Category` and `Split` entry payloads, that assigns a Canada Revenue Agency tax code (e.g. GST, PST, HST, QST) to a categorization. `tax_code` is currently only supported for businesses incorporated in Canada (`country` is `CA` on the [Business](/api-reference/business/business) object). Providing a `tax_code` for any other business country will return a 400 error. A tax code value. Must be one of the `code` values returned in `tax_options` on the [Bank Transaction](/api-reference/bank-transaction/bank-transaction#param-tax-options) object for the codes valid on that transaction's date. Cannot be used together with an `Exclusion` category. ```bash Category with Tax Code theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/bank-transactions/67cee0d8-3b8e-4b4b-a857-78ce3bb1d895/categorize \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "Category", "category": { "type": "StableName", "stable_name": "MEALS" }, "tax_code": "GST_PST_BC" }' ``` ## Rules Suggestion Responses may include `update_categorization_rules_suggestion` when Layer recommends creating a reusable categorization rule. For more details, see [Categorization Rule Suggestions](/guides/transaction-categorization/rules-suggestion). ```bash Category (Stable Name) theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/bank-transactions/67cee0d8-3b8e-4b4b-a857-78ce3bb1d895/categorize \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "Category", "category": { "type": "StableName", "stable_name": "MEALS" } }' ``` ```bash Category (Account Id) theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/bank-transactions/67cee0d8-3b8e-4b4b-a857-78ce3bb1d895/categorize \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "Category", "category": { "type": "AccountId", "id": "5b83ccb3-bdb3-42ab-8e88-c2222bfa97df" } }' ``` ```bash Split theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/bank-transactions/67cee0d8-3b8e-4b4b-a857-78ce3bb1d895/categorize \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "Split", "entries": [ { "category": { "type": "StableName", "stable_name": "MEALS" }, "amount": 4250 }, { "category": { "type": "StableName", "stable_name": "BUSINESS_TRAVEL" }, "amount": 6000 } ] }' ``` ```json Category theme={null} { "data":{ "id":"c63a7a21-d6d7-4d3a-b8f3-e419161a9516", "type":"Bank_Transaction", "transaction_type":"Book", "business_id":"cfee5365-dcc3-425e-b403-cc9568f7121e", "source":"API", "source_transaction_id":"11111114", "source_account_id":"111113", "imported_at":"2023-06-07T00:48:25.784724Z", "date":"2023-05-10T14:13:07Z", "direction":"DEBIT", "amount":5670, "counterparty_name":"Home Depot", "description":"HOMEDEPOT MI59", "categorization_status":"CATEGORIZED", "category":{ "category":"SUPPLIES", "display_name":"Supplies" }, "categorization_method":"LAYER_AUTO", "categorization_flow":{ "type":"ASK_FROM_SUGGESTIONS", "categories":[ { "category":"SUPPLIES", "display_name":"Supplies" }, { "category":"EQUIPMENT", "display_name":"Business equipment" }, { "category":"MARKETING", "display_name":"Marketing expenses" } ] } }, "meta":{ } } ``` ```json Split theme={null} { "data": { "type": "Bank_Transaction", "id": "56759ace-1b5a-47ca-9271-94bf4b2c1005", "business_id": "96d483a3-fa80-46a1-a6cb-41d8120f7874", "source": "PLAID", "source_transaction_id": "test-id-1", "source_account_id": "account-1", "imported_at": "2024-07-15T20:02:03.167163Z", "date": "2024-07-15T20:02:02.965531Z", "direction": "DEBIT", "amount": 10250, "counterparty_name": "Test counterparty", "description": null, "account_name": "Default Test Client Banking", "categorization_status": "SPLIT", "category": { "type": "Split_Categorization", "entries": [ { "amount": 4250, "category": { "id": "fa30634d-9ebe-42bf-a99f-0fff97f8b8e9", "stable_name": "MEALS", "category": "fa30634d-9ebe-42bf-a99f-0fff97f8b8e9", "display_name": "Meals" } }, { "amount": 6000, "category": { "id": "4bcf9027-532e-4c9e-b030-b5cc3264fdf8", "stable_name": "BUSINESS_TRAVEL", "category": "4bcf9027-532e-4c9e-b030-b5cc3264fdf8", "display_name": "Business travel" } } ] }, "categorization_method": "API", "categorization_flow": null, "projected_income_category": "EXPENSE", "suggested_matches": [], "match": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ] } } ``` ```json Categorization Rule Suggestion theme={null} { "data": { "type": "Bank_Transaction", "id": "67cee0d8-3b8e-4b4b-a857-78ce3bb1d895", "business_id": "cfee5365-dcc3-425e-b403-cc9568f7121e", "source": "API", "source_transaction_id": "11111113", "source_account_id": "111113", "imported_at": "2023-06-07T00:42:08.664543Z", "date": "2023-05-15T14:13:07Z", "direction": "DEBIT", "amount": 8026, "counterparty_name": "SUNOCO", "description": null, "categorization_status": "CATEGORIZED", "category": { "category": "FUEL", "display_name": "Fuel" }, "update_categorization_rules_suggestion": { "type": "Create_Categorization_Rule_For_Counterparty", "id": "b3488b6a-c7b4-4d2a-a8c7-7d15f9942ed4", "created_at": "2025-02-14T17:22:01Z", "status": "PENDING", "counterparty": { "id": "f1664961-43d8-42f1-9a6d-c6c32a9f0adf", "name": "SUNOCO" }, "suggestion_prompt": "Would you like to create a rule for outbound SUNOCO transactions?", "new_rule": { "apply_retroactively": true, "created_by_suggestion_id": "b3488b6a-c7b4-4d2a-a8c7-7d15f9942ed4", "counterparty_filter": "f1664961-43d8-42f1-9a6d-c6c32a9f0adf", "category": { "type": "StableName", "stable_name": "FUEL" }, "bank_direction_filter": "DEBIT" }, "transactions_that_will_be_affected": [] } } } ``` # Complete document upload Source: https://docs.layerfi.com/api-reference/v1/complete-document-upload post /v1/businesses/{businessId}/documents/{documentId}/complete Completes a multipart upload after all parts have been uploaded to S3. You must provide the upload_id from the create response and the ETag returned by S3 for each uploaded part. The ETag is returned in the response headers when you PUT to each presigned URL. # Create bank account Source: https://docs.layerfi.com/api-reference/v1/create-bank-account post /v1/businesses/{businessId}/bank-accounts Creates a new bank account for the specified business. # Create bill Source: https://docs.layerfi.com/api-reference/v1/create-bill post /v1/businesses/{businessId}/bills Creates a new bill for a business. # Create bill payment Source: https://docs.layerfi.com/api-reference/v1/create-bill-payment post /v1/businesses/{businessId}/bills/bill-payments Creates a new payment for one or more bills. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 5 requests | 1 second | 10 requests | | Production | 25 requests | 1 second | 50 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create billing report export Source: https://docs.layerfi.com/api-reference/v1/create-billing-report-export post /v1/billing/reports Submits an async request to generate a rolling 3-month bookkeeping billing report (XLSX) for the authenticated client. Returns immediately with an export resource; poll GET /v1/exports/{exportId} or subscribe to export.completed / export.failed webhooks for completion. Starts an async export that generates a rolling 3-month bookkeeping billing report (XLSX) for your client. The response is `202 Accepted` with an [Export](/api-reference/v1/fetch-export) resource. Poll [Fetch export](/api-reference/v1/fetch-export) or subscribe to `export.completed` / `export.failed` webhooks. See [Generating async reports](/guides/async-reports). # Create bookkeeping status report export Source: https://docs.layerfi.com/api-reference/v1/create-bookkeeping-status-report-export post /v1/reports/bookkeeping/exports Starts an async XLSX export of bookkeeping status for the authenticated client's enrolled businesses. The workbook contains Businesses and Periods sheets. Returns an export resource; poll GET /v1/exports/{exportId} or subscribe to export.completed / export.failed webhooks for completion. Starts a client-wide async XLSX export of bookkeeping status for businesses enrolled in bookkeeping. The workbook has a `Businesses` sheet with enrollment, onboarding, pending task, and latest closed period information, and a `Periods` sheet with period statuses, billing statuses, task metrics, and closing milestones. Poll [Fetch export](/api-reference/v1/fetch-export) or subscribe to `export.completed` / `export.failed` webhooks to retrieve the completed file. See [Generating async reports](/guides/async-reports). # Create business Source: https://docs.layerfi.com/api-reference/v1/create-business post /v1/businesses Creates a new business in Layer. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will update or no-op. ## Response Status Codes * **201 Created** - A new business was successfully created * **200 OK** - An existing business was found and returned: * Archived business with matching phone number was unarchived * Non-archived business with matching external ID was found * **400 Bad Request** - Phone number matches an existing non-archived business with a different external ID The response includes `previously_imported: true` when an existing business is returned. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 10 requests | 1 second | 10 requests | | Production | 10 requests | 1 second | 10 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create business auth token Source: https://docs.layerfi.com/api-reference/v1/create-business-auth-token post /v1/businesses/{businessId}/auth-token Creates a new auth token scoped to the specified business. The business auth token is used to authenticate Layer API requests from client-side applications. Note the return type is an AuthToken object rather than a standard Layer API response object. # Create Check payroll config Source: https://docs.layerfi.com/api-reference/v1/create-check-payroll-config put /v1/businesses/{businessId}/payroll/check/configs Creates a new Check payroll configuration for the given business. If a config with the same `check_company_id` already exists, this is a no-op and returns 200. # Create child ledger account Source: https://docs.layerfi.com/api-reference/v1/create-child-ledger-account post /v1/businesses/{businessId}/ledger/accounts/{accountId}/create-child-account Creates a child account under the specified parent account. The child inherits account_type, account_subtype, and normality from the parent. # Create custom account Source: https://docs.layerfi.com/api-reference/v1/create-custom-account post /v1/businesses/{businessId}/custom-accounts/ Creates a custom account for a business. Custom accounts offer platforms direct control over bank account data and should be used for accounts operated directly by the platform. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 5 requests | 1 second | 10 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create customer credit Source: https://docs.layerfi.com/api-reference/v1/create-customer-credit post /v1/businesses/{businessId}/invoices/customer-credits Creates a new customer credit for a business. # Create dedicated invoice payment Source: https://docs.layerfi.com/api-reference/v1/create-dedicated-invoice-payment post /v1/businesses/{businessId}/invoices/{invoiceId}/payment Creates a payment that is dedicated to a specific invoice. The full payment amount will be allocated to this invoice. # Create dedicated refund on invoice Source: https://docs.layerfi.com/api-reference/v1/create-dedicated-invoice-refund post /v1/businesses/{businessId}/invoices/{invoiceId}/refund Creates a refund that is dedicated to a specific invoice. # Create demo business Source: https://docs.layerfi.com/api-reference/v1/create-demo-business post /v1/businesses/demo Creates a new demo business in Layer. Demo businesses are used for testing and demonstration purposes. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will return the existing demo business if it's not archived. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 10 requests | 1 second | 10 requests | | Production | 10 requests | 1 second | 10 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create document upload Source: https://docs.layerfi.com/api-reference/v1/create-document-upload post /v1/businesses/{businessId}/documents Creates a new document record and initiates a multipart upload to S3. Returns presigned URLs for uploading file parts directly to S3. This endpoint is designed for uploading large files that may exceed standard upload limits. After uploading all parts to the presigned URLs, call the complete endpoint to finalize the upload. # Create expense Source: https://docs.layerfi.com/api-reference/v1/create-expense post /v1/businesses/{businessId}/expenses Creates an expense for a business. An expense is a type of bill for a purchase paid at the time of the transaction. Use this endpoint to provide purchase, vendor, line item, and payment details in one request. The response is a bill with `is_expense: true` and `status: PAID`. Create an expense when a purchase and payment happen at the same time. An expense is a type of bill with `is_expense: true` and `status: PAID`. Use this endpoint to submit the vendor, line items, purchase date, and payment details in one request. The request is idempotent via `external_id`; if an expense with the same `external_id` already exists, Layer returns the existing expense with a `200` response. Required fields to plan for: * `paid_at`: when the purchase was paid * `line_items`: what was purchased * `payment`: how it was paid * `vendor_id` or `vendor_external_id`: who was paid Line items use the same shape as [Create bill](/api-reference/v1/create-bill). See the [Expense object](/api-reference/bill/expense) for when to use expenses instead of standard bills. # Create ledger account Source: https://docs.layerfi.com/api-reference/v1/create-ledger-account post /v1/businesses/{businessId}/ledger/accounts Creates a new ledger account. The stable_name field can be used for idempotency - if an account with the same stable_name already exists, it will be returned instead of creating a duplicate. # Create P&L comparisons Source: https://docs.layerfi.com/api-reference/v1/create-p&l-comparisons post /v1/businesses/{businessId}/reports/profit-and-loss-comparison Compare Profit & Loss views across time periods and/or tags. This endpoint allows specifying multiple time periods (specified in months, years, or custom date ranges) and tags and will generate a comparison for every combination. Note that this endpoint is retrieval only, but uses a `POST` HTTP verb rather than `GET` because of the complexity of the parameters. # Create payout Source: https://docs.layerfi.com/api-reference/v1/create-payout post /v1/businesses/{businessId}/payouts Creates a new payout for a business or updates existing payout. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will update or no-op. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 3 requests | 1 second | 6 requests | | Production | 25 requests | 1 second | 50 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create refund Source: https://docs.layerfi.com/api-reference/v1/create-refund post /v1/businesses/{businessId}/invoices/refunds Creates a new refund for a business or updates existing refund. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will update or no-op. # Create refund payment Source: https://docs.layerfi.com/api-reference/v1/create-refund-payment post /v1/businesses/{businessId}/invoices/refunds/{refundId}/payments Creates a new payment for a customer refund. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will no-op. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Retained earnings Source: https://docs.layerfi.com/api-reference/v1/create-retained-earnings-closing-action post /v1/businesses/{businessId}/closing/retained-earnings Create a retained earnings adjustment. Use `year` for an annual retained earnings close. Alternatively, use `effective_date` to choose a specific date. [Preview retained earnings](/api-reference/v1/preview-retained-earnings-closing-action) to see the adjustment without creating it. ## Cash and accrual reporting Cash and accrual reports use different retained earnings adjustments. # Create sales demo business Source: https://docs.layerfi.com/api-reference/v1/create-sales-demo-business post /v1/sales-demos Creates a sales demo business in Layer and asynchronously seeds it with realistic demo data (customers, invoices, payouts, bank accounts, and transactions) so it is presentation-ready within seconds. A `200` or `201` means the business exists, not that seeding has finished. Re-POSTing the same `external_id` returns an existing sales demo and re-triggers seeding; an empty plain demo is promoted in place. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 10 requests | 1 second | 10 requests | | Production | 10 requests | 1 second | 10 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create tag dimension Source: https://docs.layerfi.com/api-reference/v1/create-tag-dimension post /v1/businesses/{businessId}/tags/dimensions Creates a new tag dimension for the business. Tag dimensions define the structure and constraints for tags. # Create tag value Source: https://docs.layerfi.com/api-reference/v1/create-tag-value post /v1/businesses/{businessId}/tags/dimensions/{dimensionId}/values Creates a new tag value definition for a specific tag dimension. # Create tax packet Source: https://docs.layerfi.com/api-reference/v1/create-tax-packet post /v1/businesses/{businessId}/reports/tax-packets Creates a new tax packet request for generating comprehensive tax reporting documents including P&L reports, general ledger details, and account transactions. # Create trip Source: https://docs.layerfi.com/api-reference/v1/create-trip post /v1/businesses/{businessId}/mileage/trips Creates a new trip for the specified business. This endpoint is idempotent using the `external_id` field as the idempotency key. `distance` is optional when both `google_start_place_id` and `google_end_place_id` are provided (from the [address suggestions](/api-reference/v1/get-address-suggestions) endpoints); the driving distance between them is then computed automatically and the trip's `distance_source` is `COMPUTED`. Providing an explicit `distance` always takes precedence and sets `distance_source` to `MANUAL`. A request with neither a `distance` nor both place IDs returns a 400. When updating an existing trip via `external_id`, the distance is recomputed only if the place IDs change; if they are unchanged, the existing distance is kept. # Create vehicle Source: https://docs.layerfi.com/api-reference/v1/create-vehicle post /v1/businesses/{businessId}/mileage/vehicles Creates a new vehicle for the specified business. This endpoint is idempotent using the `external_id` field as the idempotency key. # Create vendor Source: https://docs.layerfi.com/api-reference/v1/create-vendor post /v1/businesses/{businessId}/vendors Creates a new vendor for a business. # Create vendor credit Source: https://docs.layerfi.com/api-reference/v1/create-vendor-credit post /v1/businesses/{businessId}/bills/vendor-credits Creates a new vendor credit for a business. # Create vendor payout Source: https://docs.layerfi.com/api-reference/v1/create-vendor-payout post /v1/businesses/{businessId}/vendor-payouts Creates a new vendor payout for a business or updates existing vendor payout. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will update or no-op. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Create custom journal entry Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/create-custom-journal-entry post /v1/businesses/{businessId}/custom-journal-entries/ Creates a new custom journal entry for the specified business. The credits and debits must balance. # Create multiple custom journal entries Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/create-multiple-custom-journal-entries post /v1/businesses/{businessId}/custom-journal-entries/bulk Creates multiple custom journal entries in a single request. # Fetch custom journal entry Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/fetch-custom-journal-entry get /v1/businesses/{businessId}/custom-journal-entries/{customJournalEntryId} Returns the custom journal entry associated with the provided ID. # List custom journal entries Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/list-custom-journal-entries get /v1/businesses/{businessId}/custom-journal-entries/ Returns a list of custom journal entries for the specified business. Entries can be filtered by date ranges and other parameters. # Reverse custom journal entry Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/reverse-custom-journal-entry delete /v1/businesses/{businessId}/custom-journal-entries/{customJournalEntryId} Creates a reversal entry for a custom journal entry, cancelling it out and setting its `reversed_at` date. # Update custom journal entry Source: https://docs.layerfi.com/api-reference/v1/custom-journal-entries/update-custom-journal-entry put /v1/businesses/{businessId}/custom-journal-entries/{customJournalEntryId} Updates an existing custom journal entry. The credits and debits must balance. # Deactivate bookkeeping Source: https://docs.layerfi.com/api-reference/v1/deactivate-bookkeeping post /v1/businesses/{businessId}/bookkeeping/deactivate Deactivates bookkeeping for the specified business. # Delete bill Source: https://docs.layerfi.com/api-reference/v1/delete-bill post /v1/businesses/{businessId}/bills/{billId}/delete Deletes an existing bill. # Delete bill payment Source: https://docs.layerfi.com/api-reference/v1/delete-bill-payment post /v1/businesses/{businessId}/bills/bill-payments/{paymentId}/delete Deletes an existing bill payment. # Delete Check payroll config Source: https://docs.layerfi.com/api-reference/v1/delete-check-payroll-config delete /v1/businesses/{businessId}/payroll/check/configs/{checkPayrollConfigId} Archives the specified Check payroll configuration, removing it from active use. # Delete customer credit Source: https://docs.layerfi.com/api-reference/v1/delete-customer-credit delete /v1/businesses/{businessId}/invoices/customer-credits/{customerCreditId} Marks a customer credit as deleted (soft delete). # Delete dedicated invoice payment Source: https://docs.layerfi.com/api-reference/v1/delete-dedicated-invoice-payment delete /v1/businesses/{businessId}/invoices/{invoiceId}/payment/{paymentId} Deletes a payment that is dedicated to a specific invoice. # Delete invoice Source: https://docs.layerfi.com/api-reference/v1/delete-invoice post /v1/businesses/{businessId}/invoices/{invoiceId}/delete Marks an invoice as deleted. The invoice must not have any valid payments or refunds associated with it. # Delete invoice payment Source: https://docs.layerfi.com/api-reference/v1/delete-invoice-payment post /v1/businesses/{businessId}/invoices/payments/{paymentId}/delete Marks an invoice payment as deleted. # Delete ledger account Source: https://docs.layerfi.com/api-reference/v1/delete-ledger-account delete /v1/businesses/{businessId}/ledger/accounts/{accountId} Deletes a ledger account. The account must not have any transactions or child accounts. # Delete opening balance Source: https://docs.layerfi.com/api-reference/v1/delete-opening-balance delete /v1/businesses/{businessId}/external-accounts/{externalAccountId}/opening-balance Deletes the opening balance for an external account. # Delete payout Source: https://docs.layerfi.com/api-reference/v1/delete-payout delete /v1/businesses/{businessId}/payouts/{payoutId} Deletes a payout for a business. Ledger entries will be reversed but referenced payments and refunds will not be removed. To keep ledger entries most understandable, we recommend updating payouts rather than deleting and recreating when the intent is to fix or update information from the same payout. # Delete refund Source: https://docs.layerfi.com/api-reference/v1/delete-refund delete /v1/businesses/{businessId}/invoices/refunds/{refundId} Deletes a refund for a business. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Delete refund payment Source: https://docs.layerfi.com/api-reference/v1/delete-refund-payment delete /v1/businesses/{businessId}/invoices/refunds/payments/{paymentId} Deletes a refund payment by ID. # Delete tags from entity Source: https://docs.layerfi.com/api-reference/v1/delete-tags-from-entity post /v1/businesses/{businessId}/tags/delete Remove tags from entities of a specified type. This generic endpoint allows removing tags from any supported entity type. # Delete trip Source: https://docs.layerfi.com/api-reference/v1/delete-trip delete /v1/businesses/{businessId}/mileage/trips/{tripId} Deletes a trip by marking it as deleted. # Delete vehicle Source: https://docs.layerfi.com/api-reference/v1/delete-vehicle delete /v1/businesses/{businessId}/mileage/vehicles/{vehicleId} Deletes a vehicle. The vehicle must not have any trips associated with it and must not be archived. # Delete vendor credit Source: https://docs.layerfi.com/api-reference/v1/delete-vendor-credit delete /v1/businesses/{businessId}/bills/vendor-credits/{vendorCreditId} Marks a vendor credit as deleted (soft delete). # Delete vendor payout Source: https://docs.layerfi.com/api-reference/v1/delete-vendor-payout delete /v1/businesses/{businessId}/vendor-payouts/{payoutId} Deletes a vendor payout for a business. # Delete write-off Source: https://docs.layerfi.com/api-reference/v1/delete-write-off delete /v1/businesses/{businessId}/invoices/{invoiceId}/write-offs/{writeOffId} Deletes a write-off for a business. # Export account transactions as Excel Source: https://docs.layerfi.com/api-reference/v1/export-account-transactions-as-excel get /v1/businesses/{businessId}/ledger/accounts/{accountId}/exports/excel Exports the transaction history for a specific ledger account as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. The export includes transaction date, entry number, description, debit/credit amounts, running balance, and related accounts. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Export AP aging report as Excel Source: https://docs.layerfi.com/api-reference/v1/export-ap-aging-report-as-excel get /v1/businesses/{businessId}/reports/unified/ap-aging/exports/excel Exports an accounts payable aging report as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Export balance sheet as CSV Source: https://docs.layerfi.com/api-reference/v1/export-balance-sheet-as-csv get /v1/businesses/{businessId}/reports/balance-sheet/exports/csv Exports a balance sheet report as a CSV file. Returns a pre-signed URL for downloading the generated CSV file. # Export balance sheet as Excel Source: https://docs.layerfi.com/api-reference/v1/export-balance-sheet-as-excel get /v1/businesses/{businessId}/reports/balance-sheet/exports/excel Exports a balance sheet report as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Export cashflow statement as CSV Source: https://docs.layerfi.com/api-reference/v1/export-cashflow-statement-as-csv get /v1/businesses/{businessId}/reports/cashflow-statement/exports/csv Exports a cashflow statement as a CSV file. Returns a pre-signed URL for downloading the generated CSV file. # Export ledger balances to CSV Source: https://docs.layerfi.com/api-reference/v1/export-ledger-balances-csv get /v1/businesses/{businessId}/ledger/balances/exports/csv Exports ledger account balances to a CSV file. Returns a presigned URL to download the file. # Export ledger entries to CSV Source: https://docs.layerfi.com/api-reference/v1/export-ledger-entries-csv get /v1/businesses/{businessId}/ledger/entries/exports/csv Exports ledger entries to a CSV file. Returns a presigned URL to download the file. # Export month-over-month P&L Source: https://docs.layerfi.com/api-reference/v1/export-month-over-month-p&l get /v1/businesses/{businessId}/reports/profit-and-loss/exports/month-over-month Exports a month-over-month profit and loss comparison as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Export P&L as CSV Source: https://docs.layerfi.com/api-reference/v1/export-p&l-as-csv get /v1/businesses/{businessId}/reports/profit-and-loss/exports/csv Exports a profit and loss report as a CSV file. Returns a pre-signed URL for downloading the generated CSV file. # Export P&L as Excel Source: https://docs.layerfi.com/api-reference/v1/export-p&l-as-excel get /v1/businesses/{businessId}/reports/profit-and-loss/exports/excel Exports a profit and loss report as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Export P&L comparison as CSV Source: https://docs.layerfi.com/api-reference/v1/export-p&l-comparison-as-csv post /v1/businesses/{businessId}/reports/profit-and-loss/exports/comparison-csv Exports a profit and loss comparison report as a CSV file. Returns a pre-signed URL for downloading the generated CSV file. # Export P&L line items as Excel Source: https://docs.layerfi.com/api-reference/v1/export-p&l-line-items-as-excel get /v1/businesses/{businessId}/reports/profit-and-loss/lines/exports/excel Exports detailed P&L line item information as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Export transactions as CSV Source: https://docs.layerfi.com/api-reference/v1/export-transactions-as-csv get /v1/businesses/{businessId}/reports/transactions/exports/csv Exports transaction data as a CSV file. Returns a pre-signed URL for downloading the generated CSV file. # Export transactions as Excel Source: https://docs.layerfi.com/api-reference/v1/export-transactions-as-excel get /v1/businesses/{businessId}/reports/transactions/exports/excel Exports transaction data as an Excel file. Returns a pre-signed URL for downloading the generated Excel file. # Fetch accounting configuration Source: https://docs.layerfi.com/api-reference/v1/fetch-accounting-configuration get /v1/businesses/{businessId}/accounting-config Returns the accounting configuration associated for the provided business. This is the means by which you can see things such as the default reporting basis for a business or when the books are closed as of. # Fetch AP aging report Source: https://docs.layerfi.com/api-reference/v1/fetch-ap-aging-report get /v1/businesses/{businessId}/reports/unified/ap-aging Returns an accounts payable aging report showing outstanding bills grouped by vendor and aging buckets. # Fetch AR aging detail for a customer Source: https://docs.layerfi.com/api-reference/v1/fetch-ar-aging-detail-for-a-customer get /v1/businesses/{businessId}/invoices/ar-aging/customer/{customerId} Returns detailed accounts receivable aging information for a specific customer, including outstanding balances broken down by aging buckets (current, 1-30 days, 31-60 days, 61-90 days, 91+ days). # Fetch AR aging report Source: https://docs.layerfi.com/api-reference/v1/fetch-ar-aging-report get /v1/businesses/{businessId}/invoices/ar-aging Returns an accounts receivable aging report showing outstanding invoices grouped by customer and aging buckets. This report helps track overdue payments and manage cash flow. # Fetch balance sheet Source: https://docs.layerfi.com/api-reference/v1/fetch-balance-sheet get /v1/businesses/{businessId}/reports/balance-sheet Returns a balance sheet report showing assets, liabilities, and equity at a specific point in time. # Fetch bank transaction Source: https://docs.layerfi.com/api-reference/v1/fetch-bank-transaction get /v1/businesses/{businessId}/bank-transactions/{bankTransactionId} Returns the bank transaction associated with the provided bank transaction id. # Fetch bookkeeping reporting periods Source: https://docs.layerfi.com/api-reference/v1/fetch-bookkeeping-reporting-periods get /v1/businesses/{businessId}/reports/bookkeeping/periods Returns the current bookkeeping status summary together with historical bookkeeping periods for a business. Periods include simplified external status, billing status, closing timeline milestones, and per-period task metrics. Newest periods are returned first; inactive and ongoing periods are excluded. Returns the current bookkeeping status summary together with historical bookkeeping periods (newest first). Each period includes simplified external status, billing status, closing timeline milestones, and task metrics. Inactive and ongoing periods are excluded. # Fetch bookkeeping reporting status Source: https://docs.layerfi.com/api-reference/v1/fetch-bookkeeping-reporting-status get /v1/businesses/{businessId}/reports/bookkeeping/status Returns a rich bookkeeping status summary for a single business, including enrollment dates, periods waiting on the business, latest fully closed period, pending tasks, disconnected bank accounts, and last inbound SMS. Returns a point-in-time bookkeeping status summary for analytics and support workflows, including enrollment, periods waiting on the business, latest closed period, pending tasks, bank connection health, last inbound SMS, and the upcoming onboarding call. # Fetch bookkeeping status Source: https://docs.layerfi.com/api-reference/v1/fetch-bookkeeping-status get /v1/businesses/{businessId}/bookkeeping/status Returns the effective bookkeeping enrollment status for the specified business, including onboarding completion metadata. Returns the effective bookkeeping enrollment status for a business, including onboarding completion metadata. Auth is the same as other v1 business routes: a platform bearer token or a [business-scoped access token](/api-details/authentication#business-scoped-access-tokens). # Fetch business Source: https://docs.layerfi.com/api-reference/v1/fetch-business get /v1/businesses/{businessId} Returns the business associated with the provided business id. # Fetch business activities Source: https://docs.layerfi.com/api-reference/v1/fetch-business-activities get /v2/activity/businesses/{businessId}/activities Generates a list of activities for a specific business. Activities include categorization, SMS, and other business-specific events. This endpoint is paginated, see [Pagination](/api-details/pagination) for details. This v2 endpoint uses the same response format as v1. # Fetch business activity metrics Source: https://docs.layerfi.com/api-reference/v1/fetch-business-activity-summary get /v2/activity/businesses/{businessId} Generates a monthly activity summary for a specific business, including SMS, categorization, and external account connection metrics. This v2 endpoint supports an optional date range and returns a monthly breakdown format. # Fetch business email Source: https://docs.layerfi.com/api-reference/v1/fetch-business-email get /v1/businesses/{businessId}/support-emails/{messageId} Fetches one message from a thread linked to this business. Returns its stored HTML or plain-text body and temporary presigned S3 URLs for attachments. Treat HTML as untrusted before rendering it. Fetch the email again to refresh expired attachment URLs. # Fetch cashflow statement Source: https://docs.layerfi.com/api-reference/v1/fetch-cashflow-statement get /v1/businesses/{businessId}/reports/cashflow-statement Returns a cashflow statement showing cash inflows and outflows over a specified time period. # Fetch client accounting configuration Source: https://docs.layerfi.com/api-reference/v1/fetch-client-accounting-configuration get /v1/configure/{clientId}/accounting Returns the accounting configuration for the specified client. This includes settings such as the default reporting basis and books closure information at the client level. # Fetch custom account Source: https://docs.layerfi.com/api-reference/v1/fetch-custom-account get /v1/businesses/{businessId}/custom-accounts/{customAccountId} Fetches a custom account for a business. Custom accounts offer platforms direct control over bank account data and should be used for accounts operated directly by the platform. # Fetch customer credit Source: https://docs.layerfi.com/api-reference/v1/fetch-customer-credit get /v1/businesses/{businessId}/invoices/customer-credits/{customerCreditId} Returns the customer credit associated with the provided customer credit ID. # Fetch data sync validation totals Source: https://docs.layerfi.com/api-reference/v1/fetch-data-sync-validation-totals get /v1/businesses/{businessId}/reports/data-sync-validation Returns accounting totals that you can compare with the source system after syncing or backfilling sales data. Invoice-derived totals use the accrual basis, while payment processor fees use the cash basis. All monetary values are in cents. See the [sales data backfill validation guide](/guides/validating-sales-data-backfills) for the comparison workflow. Use this report after a sales data sync or backfill to compare Layer's accounting totals with totals calculated from your source system. Invoice-derived fields use accrual accounting, while `PAYMENT_PROCESSOR_FEES` uses the cash basis. See [Validate a sales data backfill](/guides/validating-sales-data-backfills) for the complete comparison and troubleshooting workflow. # Fetch document Source: https://docs.layerfi.com/api-reference/v1/fetch-document get /v1/businesses/{businessId}/s3_doc/{documentId} Returns a presigned URL (`S3_Presigned_Url`) for the document associated with the provided document id. This endpoint can fetch any document associated with the business, including transaction-specific receipts. The response includes `document_type` along with `fileName`, `createdAt`, and `documentId`. # Fetch expense Source: https://docs.layerfi.com/api-reference/v1/fetch-expense get /v1/businesses/{businessId}/bills/{billId} Returns the bill associated with the provided bill id. A bill represents an invoice or purchase order a business has received from a vendor for goods or services, and is used to track purchases and accounts payable in Layer. An expense is a type of bill. To fetch one expense, use [Fetch bill](/api-reference/bill/bill) with the expense `id` returned by [Create expense](/api-reference/v1/create-expense): ```http theme={null} GET /v1/businesses/{business_id}/bills/{bill_id} ``` The response is a bill with `is_expense: true`. See the [Expense object](/api-reference/bill/expense) for more on expenses vs. standard bills. # Fetch export Source: https://docs.layerfi.com/api-reference/v1/fetch-export get /v1/exports/{exportId} Returns a single async export request for the authenticated client. When status is completed, download_url contains a presigned link to the generated file. When `status` is `completed`, use `download_url` to download the generated file. The URL is a short-lived presigned link. For the full workflow, including webhook subscriptions, see [Generating async reports](/guides/async-reports). # Fetch external account Source: https://docs.layerfi.com/api-reference/v1/fetch-external-account get /v1/businesses/{businessId}/external-accounts/{externalAccountId} Fetches an external account for a business. External accounts represent all connected financial accounts, including bank accounts, credit cards, loans, etc. # Fetch invoice Source: https://docs.layerfi.com/api-reference/v1/fetch-invoice get /v1/businesses/{businessId}/invoices/{invoiceId} Returns the invoice associated with the provided invoice id. # Fetch opening balance Source: https://docs.layerfi.com/api-reference/v1/fetch-opening-balance get /v1/businesses/{businessId}/external-accounts/{externalAccountId}/opening-balance Fetches the opening balance for an external account. This is useful when verifying or reconciling the historical balance sheet. # Fetch P&L line items Source: https://docs.layerfi.com/api-reference/v1/fetch-p&l-line-items get /v1/businesses/{businessId}/reports/profit-and-loss/lines Returns detailed line item information for a specific P&L account or category over a specified time period. # Fetch P&L report Source: https://docs.layerfi.com/api-reference/v1/fetch-p&l-report get /v1/businesses/{businessId}/reports/profit-and-loss Returns a detailed profit and loss report for a specified time period. This endpoint provides comprehensive financial data including revenue, expenses, and net income calculations. # Fetch P&L summaries Source: https://docs.layerfi.com/api-reference/v1/fetch-p&l-summaries get /v1/businesses/{businessId}/reports/profit-and-loss-summaries Returns profit and loss summaries over a specified time range. This endpoint is useful for displaying charts and comparisons, as the summaries are less detailed than the full P&L report but a range of months can be queried at the same time. # Fetch P&L summary Source: https://docs.layerfi.com/api-reference/v1/fetch-p&l-summary get /v1/businesses/{businessId}/reports/profit-and-loss-summary Returns a profit and loss summary for a single arbitrary date range. Unlike the monthly summaries endpoint which returns per-month breakdowns, this endpoint aggregates the entire specified period into one summary. Both date bounds are optional: omitting start_date uses the business activation date, and omitting end_date uses the current time. Omitting both returns an all-time summary. This endpoint is useful for dashboard cards showing aggregate financial metrics like total revenue, expenses, net profit, and uncategorized transaction counts. # Fetch payout Source: https://docs.layerfi.com/api-reference/v1/fetch-payout get /v1/businesses/{businessId}/payouts/{payoutId} Fetches a payout for a business. # Fetch platform activity summary Source: https://docs.layerfi.com/api-reference/v1/fetch-platform-activity-summary get /v2/activity Generates a platform activity summary with monthly breakdowns across all businesses. This is the v2 version that provides more detailed monthly analytics. # Fetch Quickbooks account Source: https://docs.layerfi.com/api-reference/v1/fetch-quickbooks-account get /v1/businesses/{businessId}/quickbooks/ledger/accounts/{accountId} This API call fetches a specific Quickbooks account for a business. # Fetch Quickbooks configuration Source: https://docs.layerfi.com/api-reference/v1/fetch-quickbooks-configuration get /v1/configure/quickbooks Fetch the current platform Quickbooks configuration. # Fetch refund Source: https://docs.layerfi.com/api-reference/v1/fetch-refund get /v1/businesses/{businessId}/invoices/refunds/{refundId} Fetches a refund for a business. # Fetch refund payment Source: https://docs.layerfi.com/api-reference/v1/fetch-refund-payment get /v1/businesses/{businessId}/invoices/refunds/payments/{paymentId} Fetches a specific refund payment by ID. # Fetch Schedule C report Source: https://docs.layerfi.com/api-reference/v1/fetch-schedule-c-report get /v1/businesses/{businessId}/reports/tax/schedule-c Returns a Schedule C (Form 1040) report for sole proprietors, showing income and expenses mapped to IRS Schedule C line items. This endpoint requires the business's chart of accounts to have Schedule C mappings configured. # Fetch SMS configuration Source: https://docs.layerfi.com/api-reference/v1/fetch-sms-configuration get /v1/businesses/{businessId}/sms Returns the SMS settings for the business associated with the provided business id. Currently this setting is an `enabled` flag. Note that SMS must be enabled on both a platform level (see /v1/configure/sms) and an individual business level in order to receive SMS messages. # Fetch SMS message history Source: https://docs.layerfi.com/api-reference/v1/fetch-sms-message-history get /v1/businesses/{businessId}/sms/messages Returns the SMS message log for the specified business. This endpoint returns the most recent messages first. # Fetch Stripe configuration Source: https://docs.layerfi.com/api-reference/v1/fetch-stripe-configuration get /v1/configure/stripe Fetch the current platform Stripe configuration. Platform configuration includes the stripe secret used for API access, while business-level configuration includes specific Stripe entity IDs such as a Stripe connect account. # Fetch task Source: https://docs.layerfi.com/api-reference/v1/fetch-task get /v1/businesses/{businessId}/tasks/{taskId} Fetches a task for a business. Tasks only exist for businesses enrolled in bookkeeping services, and task lifecycle management is handled by Layer's bookkeeping team. # Fetch transaction categories Source: https://docs.layerfi.com/api-reference/v1/fetch-transaction-categories get /v1/businesses/{businessId}/categories Retrieves the list of usable transaction categories based on the business' chart of accounts. This endpoint is used by Layer's `` embedded component, and can be used to build your own transaction categorization user interface. If you are primarily using Layer's embedded components, you likely won't need to use this API endpoint directly. ## Filtering by mode Use the [mode](/api-reference/v1/fetch-transaction-categories#parameter-mode) query parameter to control which subset of categories is returned: | Mode | Categories returned | | - | - | | `DEFAULT` | The business's configured category list (see `category_list_type` on the [accounting configuration](/api-reference/v1/fetch-accounting-configuration)). This is the default when `mode` is omitted. | | `ALL` | All accounts and optional categories from the chart of accounts. | | `EXPENSES` | Expense categories only. | | `REVENUE` | Revenue categories only. | ## Types There are three types of categories you'll find in the category list: `AccountNested`, `OptionalAccountNested`, and `ExclusionNested`. ### AccountNested `AccountNested` represents a [required template account](/api-reference/ledger/required-vs-optional-template-accounts#required-template-accounts) in the business's chart of accounts. ### OptionalAccountNested `OptionalAccountNested` represents an [optional template account](/api-reference/ledger/required-vs-optional-template-accounts#optional-template-accounts) in the business's chart of accounts. ### ExclusionNested `ExclusionNested` represents an [exclusion](/api-reference/v1/categorize-bank-transaction#param-type-4) type that can be used to exclude a transaction from the business's accounting. ## Interpreting the category list In all cases, use `display_name` to present the category to the user. Use the columns below to choose a stable identifier. | Category type | `AccountId` | `StableName` | Identify with | Notes | | - | - | - | - | - | | Optional template account | After instantiation | Yes | `StableName` (always); `AccountId` once instantiated | Optional accounts only have an `AccountId` after first use. Use `StableName` to reference them before instantiation. | | User-defined custom account | Yes | No | `AccountId` only | A new `AccountId` is created when the account is added; no stable name is assigned. | | Required template account | Yes | Yes | `AccountId` or `StableName` | The stable name is the same as the account name. | | Exclusion | No | Yes | `StableName` | The exclusion type acts as the stable name; exclusions have no `AccountId`. | # Fetch transaction document Source: https://docs.layerfi.com/api-reference/v1/fetch-transaction-document get /v1/businesses/{businessId}/bank-transactions/{transactionId}/documents/{documentId} Returns the document associated with the provided document id. This endpoint can fetch any document associated with the business, including transaction-specific receipts. # Fetch uncategorized transaction counts Source: https://docs.layerfi.com/api-reference/v1/fetch-uncategorized-transaction-counts get /v1/businesses/{businessId}/notifications/uncategorized-monthly Retrieve the count of categorized and uncategorized transactions for a range of months. `start_year`, `start_month`, `end_year`, and `end_month` determine the range of months to fetch. If not specified, range will start at January of the current year and end at the current month. # Fetch vendor Source: https://docs.layerfi.com/api-reference/v1/fetch-vendor get /v1/businesses/{businessId}/vendors/{vendorId} Returns the vendor associated with the provided vendor id. # Fetch vendor credit Source: https://docs.layerfi.com/api-reference/v1/fetch-vendor-credit get /v1/businesses/{businessId}/bills/vendor-credits/{vendorCreditId} Returns the vendor credit associated with the provided vendor credit ID. # Fetch vendor payout Source: https://docs.layerfi.com/api-reference/v1/fetch-vendor-payout get /v1/businesses/{businessId}/vendor-payouts/{payoutId} Fetches a vendor payout for a business. # Fetch write-off Source: https://docs.layerfi.com/api-reference/v1/fetch-write-off get /v1/businesses/{businessId}/invoices/{invoiceId}/write-offs/{writeOffId} Fetches a write-off for a business. # Generate invoice PDF Source: https://docs.layerfi.com/api-reference/v1/generate-invoice-pdf get /v1/businesses/{businessId}/invoices/{invoiceId}/pdf Generates a PDF document for the specified invoice and returns a presigned URL to download the PDF. # Get account line items Source: https://docs.layerfi.com/api-reference/v1/get-account-line-items get /v1/businesses/{businessId}/ledger/accounts/{accountId}/lines Returns all line items for a specific ledger account with running balances. # Get address details Source: https://docs.layerfi.com/api-reference/v1/get-address-details get /v1/businesses/{businessId}/mileage/address-details Resolves a `place_id` from the address suggestions endpoint to a formatted address and coordinates. Resolves a `place_id` returned by [address suggestions](/api-reference/v1/get-address-suggestions) to a full formatted address and coordinates. Use the same `session_token` as the suggestion requests that produced the `place_id`; this call ends the autocomplete session. # Get address suggestions Source: https://docs.layerfi.com/api-reference/v1/get-address-suggestions get /v1/businesses/{businessId}/mileage/address-suggestions Returns address autocomplete suggestions for a partial address query, for use when entering trip start and end addresses. Pass the selected suggestion's `place_id` to the address details endpoint and to trip create/update. Use this endpoint to power address autocomplete when entering a trip's start and end addresses. Generate an opaque `session_token` (for example a UUID) when the user begins typing in an address field, reuse it for every suggestion request in that session and the final [address details](/api-reference/v1/get-address-details) request, then discard it. Requests sharing a token are grouped into a single billed session. Pass the selected suggestion's `place_id` to the address details endpoint to fetch the formatted address and coordinates, and to [create trip](/api-reference/v1/create-trip) or [update trip](/api-reference/v1/update-trip) as `google_start_place_id` / `google_end_place_id` to have the trip's distance computed automatically. # Get bank account Source: https://docs.layerfi.com/api-reference/v1/get-bank-account get /v1/businesses/{businessId}/bank-accounts/{bankAccountId} Returns a single bank account by ID. # Get chart of accounts Source: https://docs.layerfi.com/api-reference/v1/get-chart-of-accounts get /v1/businesses/{businessId}/ledger/chart Returns the complete chart of accounts for the business as a nested tree structure. # Get connection status Source: https://docs.layerfi.com/api-reference/v1/get-connection-status get /v1/businesses/{businessId}/quickbooks/connection-status Returns the connection status of Quickbooks for a business. To create new connections, use Quickbooks connection component. Businesses who have not connected a Quickbooks account will have a response with `is_connected` set to false. # Get dedicated invoice payment Source: https://docs.layerfi.com/api-reference/v1/get-dedicated-invoice-payment get /v1/businesses/{businessId}/invoices/{invoiceId}/payment/{paymentId} Returns a payment that is dedicated to a specific invoice. # Get ledger account Source: https://docs.layerfi.com/api-reference/v1/get-ledger-account get /v1/businesses/{businessId}/ledger/accounts/{accountId} Returns a single ledger account by ID or stable_name. # Get ledger balances Source: https://docs.layerfi.com/api-reference/v1/get-ledger-balances get /v1/businesses/{businessId}/ledger/balances Returns the ledger account balances for the business. Supports filtering by date range, reporting basis, customer, vendor, and tags. # Get mileage summary Source: https://docs.layerfi.com/api-reference/v1/get-mileage-summary get /v1/businesses/{businessId}/mileage/summary Returns a summary of mileage statistics grouped by year and month, including total miles, business miles, personal miles, uncategorized miles, trip counts, and estimated deductions. # Get tag dimension Source: https://docs.layerfi.com/api-reference/v1/get-tag-dimension get /v1/businesses/{businessId}/tags/dimensions/{dimensionId} Returns a tag dimension by ID. # Get tag dimension by key Source: https://docs.layerfi.com/api-reference/v1/get-tag-dimension-by-key get /v1/businesses/{businessId}/tags/dimensions/key/{dimensionKey} Returns a tag dimension by its key string. This is an alternative to fetching by UUID. # Get trip Source: https://docs.layerfi.com/api-reference/v1/get-trip get /v1/businesses/{businessId}/mileage/trips/{tripId} Returns a single trip by ID. # Get vehicle Source: https://docs.layerfi.com/api-reference/v1/get-vehicle get /v1/businesses/{businessId}/mileage/vehicles/{vehicleId} Returns a single vehicle by ID. # Import bank statement Source: https://docs.layerfi.com/api-reference/v1/import-bank-statement post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/bank-statement-import Upload one PDF bank statement. The bookkeeping period must be monthly. Only posted transactions are imported after statement validation succeeds. Upload one PDF statement for a custom account using a monthly bookkeeping period. The statement must pass validation before its posted transactions are imported; pending transactions are not imported. Re-uploading the same PDF returns a 400 error, even if the filename changes, and does not create another import. To remove its imported transactions, use [Archive bank statement upload](/api-reference/v1/archive-transaction-upload). Find a monthly `bookkeeping_period_id` with [List bookkeeping periods for a business](/api-reference/v1/bookkeeping/list-bookkeeping-periods-for-a-business). Send `import` as a JSON object in the multipart request alongside the PDF; the request itself is not an `application/json` body. For example: ```bash theme={null} curl --request POST \ --url "https://sandbox.layerfi.com/v1/businesses/$BUSINESS_ID/custom-accounts/$CUSTOM_ACCOUNT_ID/bank-statement-import" \ --header "Authorization: Bearer $TOKEN" \ --form 'import={"bookkeeping_period_id":"BOOKKEEPING_PERIOD_UUID"}' \ --form 'file=@statement.pdf;type=application/pdf' ``` # Import receipt Source: https://docs.layerfi.com/api-reference/v1/import-receipt post /v1/businesses/{businessId}/receipts/import Upload a single receipt for parsing on behalf of a business, such as an image or PDF submitted by a customer or platform. The uploaded file is run through Layer's receipt parsing pipeline, which proposes a vendor, amount, and line items that can be reviewed and turned into a bill. This endpoint expects a multipart upload. # Import transactions Source: https://docs.layerfi.com/api-reference/v1/import-transactions post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/transactions Imports transactions for a custom account. This action will import transactions from the specified start date to the present. If the account has already been imported, this action will overwrite the existing transactions. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 3 requests | 1 second | 6 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Import trial balances Source: https://docs.layerfi.com/api-reference/v1/import-trial-balances post /v1/businesses/{businessId}/documents/trial-balances-import Imports trial balances for a business from a `.zip` archive of Excel (`.xlsx`) files — one sheet per effective date. The earliest trial balance is converted into opening balances for each ledger account, and each subsequent trial balance is imported as a manual journal entry capturing the net change from the prior period. A business may only have one trial balances import at a time; if one already exists, it must be archived first. This endpoint expects a multipart upload. # List bank accounts Source: https://docs.layerfi.com/api-reference/v1/list-bank-accounts get /v1/businesses/{businessId}/bank-accounts Returns a list of bank accounts for the specified business. # List bank transactions Source: https://docs.layerfi.com/api-reference/v1/list-bank-transactions get /v1/businesses/{businessId}/bank-transactions Returns a list of bank transactions for the specified business. Transactions can be filtered by: * Date range ([start\_date](/api-reference/v1/list-bank-transactions#parameter-start-date), [end\_date](/api-reference/v1/list-bank-transactions#parameter-end-date)) * Direction ([direction](/api-reference/v1/list-bank-transactions#parameter-direction)) * Categorization status ([categorization\_status](/api-reference/v1/list-bank-transactions#parameter-categorization-status), [categorized](/api-reference/v1/list-bank-transactions#parameter-categorized), [is\_matched](/api-reference/v1/list-bank-transactions#parameter-is-matched)) * Category ([category](/api-reference/v1/list-bank-transactions#parameter-category)) * Amount range ([amount\_min](/api-reference/v1/list-bank-transactions#parameter-amount-min), [amount\_max](/api-reference/v1/list-bank-transactions#parameter-amount-max)) * Description ([description\_filter](/api-reference/v1/list-bank-transactions#parameter-description-filter), [description\_filter\_regex](/api-reference/v1/list-bank-transactions#parameter-description-filter-regex)) * Merchant name ([merchant\_name\_filter](/api-reference/v1/list-bank-transactions#parameter-merchant-name-filter), [merchant\_name\_filter\_regex](/api-reference/v1/list-bank-transactions#parameter-merchant-name-filter-regex)) * Memo ([memo](/api-reference/v1/list-bank-transactions#parameter-memo), [memo\_contains](/api-reference/v1/list-bank-transactions#parameter-memo-contains)) * Reference number ([reference\_number](/api-reference/v1/list-bank-transactions#parameter-reference-number), [reference\_numbers](/api-reference/v1/list-bank-transactions#parameter-reference-numbers)) * Account ([bank\_account\_ids](/api-reference/v1/list-bank-transactions#parameter-bank-account-ids), [external\_account\_ids](/api-reference/v1/list-bank-transactions#parameter-external-account-ids), [source\_account\_ids](/api-reference/v1/list-bank-transactions#parameter-source-account-ids)) * External transaction ID ([external\_ids](/api-reference/v1/list-bank-transactions#parameter-external-ids)) * Customer ([customer\_id](/api-reference/v1/list-bank-transactions#parameter-customer-id), [customer\_external\_id](/api-reference/v1/list-bank-transactions#parameter-customer-external-id)) * Vendor ([vendor\_id](/api-reference/v1/list-bank-transactions#parameter-vendor-id), [vendor\_external\_id](/api-reference/v1/list-bank-transactions#parameter-vendor-external-id)) * Counterparty ([counterparty\_id](/api-reference/v1/list-bank-transactions#parameter-counterparty-id), [has\_counterparty](/api-reference/v1/list-bank-transactions#parameter-has-counterparty)) * Tag ([tag\_key](/api-reference/v1/list-bank-transactions#parameter-tag-key), [tag\_values](/api-reference/v1/list-bank-transactions#parameter-tag-values)) * Free-text search ([q](/api-reference/v1/list-bank-transactions#parameter-q)) ## Filtering by categorization status Transactions can be categorized in three ways: * [Standard categorization](/api-reference/v1/categorize-bank-transaction#category) * [Split transactions](/api-reference/v1/categorize-bank-transaction#split-categorizations) * [Matched transactions](/api-reference/v1/match-bank-transaction) To filter categorized vs. uncategorized transactions (e.g. get all uncategorized transactions), we recommend you use the [categorized](/api-reference/v1/list-bank-transactions#parameter-categorized) query parameter. To filter categorized based on their categorization status, we recommend you use the [categorization\_status](/api-reference/v1/list-bank-transactions#parameter-categorization-status) query parameter. ## Sorting You can use [sort\_by](/api-reference/v1/list-bank-transactions#parameter-sort-by) query parameter to sort transactions by `date`, `amount`, `counterparty name`, or `description`. This defaults sorting by `date` in ascending order. You can use [sort\_order](/api-reference/v1/list-bank-transactions#parameter-sort-order) query parameter to sort transactions in ascending or descending order. This defaults to ascending order. ## Pagination See [Pagination](/api-details/pagination) for cursor and limit behavior. # List bill payments Source: https://docs.layerfi.com/api-reference/v1/list-bill-payments get /v1/businesses/{businessId}/bills/bill-payments Returns a list of bill payments for the specified business. Payments can be filtered by method and date range. # List bills Source: https://docs.layerfi.com/api-reference/v1/list-bills get /v1/businesses/{businessId}/bills Returns a list of bills for the specified business. Bills can be filtered by status and date range. Results will be paginated. List Bills supports cursor-based pagination through `sort_by`, `sort_order`, `cursor`, `limit`, and `show_total_count`. Responses include bill records in `data` and pagination details in `meta.pagination`; see [Pagination](/api-details/pagination) for the shared response contract. # List bookkeeping businesses Source: https://docs.layerfi.com/api-reference/v1/list-bookkeeping-businesses get /v1/reports/bookkeeping Returns a paginated list of businesses enrolled in bookkeeping for the authenticated client. Businesses with NOT_PURCHASED status are excluded. Designed for lightweight discovery and analytics dashboards. Returns businesses enrolled in bookkeeping for your client. Businesses with `NOT_PURCHASED` status are excluded. Each business includes `enrollment_status` and `onboarding_status`. `onboarding_status` is derived from `onboarding_date` and active `BOOKKEEPING_ONBOARDING` call bookings: | Value | Meaning | | - | - | | `UNSCHEDULED` | No onboarding call has been booked. | | `SCHEDULED` | Waiting for a booked onboarding call. | | `NO_SHOWED` | Customer booked their onboarding but did not appear. No follow up has been booked yet. | | `RESCHEDULED` | After no-showing, a new onboarding call is booked. | | `ONBOARDED` | Onboarding call has occurred. | Results are paginated. The cursor for the next page is returned in `meta.pagination.cursor`, alongside `has_more` and (when requested with `show_total_count`) `total_count`. For full cursor and limit behavior, see [Pagination](/api-details/pagination). # List business emails Source: https://docs.layerfi.com/api-reference/v1/list-business-emails get /v1/businesses/{businessId}/support-emails Lists messages in threads linked to this business, including received emails and sent replies. A linked thread may also contain third-party notifications. Results are ordered by `received_at` descending, then message ID descending. The public API does not support searching email content. List results include attachment metadata, not download URLs. # List businesses Source: https://docs.layerfi.com/api-reference/v1/list-businesses get /v1/businesses Returns a list of all active businesses that have been registered to a client in Layer. # List Check payroll configs Source: https://docs.layerfi.com/api-reference/v1/list-check-payroll-configs get /v1/businesses/{businessId}/payroll/check/configs Returns all Check payroll configurations for the given business. # List customer credits Source: https://docs.layerfi.com/api-reference/v1/list-customer-credits get /v1/businesses/{businessId}/invoices/customer-credits Returns a list of customer credits for the specified business. Customer credits can be filtered by date range and customer. Results will be paginated. # List demo businesses Source: https://docs.layerfi.com/api-reference/v1/list-demo-businesses get /v1/businesses/demo Returns a list of all demo businesses that have been created for the authenticated client. Demo businesses are used for testing and demonstration purposes and are separate from regular businesses. # List documents Source: https://docs.layerfi.com/api-reference/v1/list-documents get /v1/businesses/{businessId}/documents Returns a list of completed documents for the specified business, sorted newest first. Archived documents and documents whose upload has not completed are excluded. Documents can be filtered by document type and file type. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List expenses Source: https://docs.layerfi.com/api-reference/v1/list-expenses get /v1/businesses/{businessId}/bills Returns a list of bills for the specified business. Bills can be filtered by status and date range. Results will be paginated. An expense is a type of bill. To list expenses, use [List bills](/api-reference/v1/list-bills) with `is_expense=true`: ```http theme={null} GET /v1/businesses/{business_id}/bills?is_expense=true ``` Always include `is_expense=true` when you want only expenses. Without this filter, the response can include both expenses and standard bills. You can combine `is_expense=true` with the same filters supported by List bills, including status, date range, vendor, amount, and pagination filters. See the [Expense object](/api-reference/bill/expense) for more on expenses vs. standard bills. # List exports Source: https://docs.layerfi.com/api-reference/v1/list-exports get /v1/exports Returns async export requests for the authenticated client, newest first. Optionally filter by business_id or export_type. Returns async export requests for your client, newest first. Optionally filter with `business_id` or `export_type` (for example, `bookkeeping_status_report`). For the submit → poll → download workflow, see [Generating async reports](/guides/async-reports). # List external accounts Source: https://docs.layerfi.com/api-reference/v1/list-external-accounts get /v1/businesses/{businessId}/external-accounts Fetches a list of external accounts for a business. External accounts represent all connected financial accounts, including bank accounts, credit cards, loans, etc. # List invoices Source: https://docs.layerfi.com/api-reference/v1/list-invoices get /v1/businesses/{businessId}/invoices Returns a list of invoices for the specified business. Invoices can be filtered by status and date range. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List ledger accounts Source: https://docs.layerfi.com/api-reference/v1/list-ledger-accounts get /v1/businesses/{businessId}/ledger/accounts Returns all ledger accounts for the business with their current balances in a nested tree structure. # List ledger entries Source: https://docs.layerfi.com/api-reference/v1/list-ledger-entries get /v1/businesses/{businessId}/ledger/entries Returns ledger entries (journal entries) for the business. Supports filtering by date range, reporting basis, customer, vendor, and tags. Results are paginated. # List payments Source: https://docs.layerfi.com/api-reference/v1/list-payments get /v1/businesses/{businessId}/invoices/payments Returns a list of invoice payments for the specified business. Payments can be filtered by method and date range. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List payouts Source: https://docs.layerfi.com/api-reference/v1/list-payouts get /v1/businesses/{businessId}/payouts Fetches a list of payouts for a business. Payouts can be filtered by external ID, memo content, completion date range, and amount range. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List Quickbooks accounts Source: https://docs.layerfi.com/api-reference/v1/list-quickbooks-accounts get /v1/businesses/{businessId}/quickbooks/ledger/accounts This API call lists all Quickbooks accounts for a business. # List refund payments Source: https://docs.layerfi.com/api-reference/v1/list-refund-payments get /v1/businesses/{businessId}/invoices/refunds/payments Fetches a list of customer refund payments for a business. Results can be filtered by various criteria and will be paginated, see [Pagination](/api-details/pagination) for details. # List refunds Source: https://docs.layerfi.com/api-reference/v1/list-refunds get /v1/businesses/{businessId}/invoices/refunds Fetches a list of refunds for a business. Refunds can be filtered by external ID, status, completion date range, amount range, customer, and payout inclusion. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List tag dimensions Source: https://docs.layerfi.com/api-reference/v1/list-tag-dimensions get /v1/businesses/{businessId}/tags/dimensions Returns a list of tag dimensions for the business. Tag dimensions define the structure and constraints for tags. # List tag values Source: https://docs.layerfi.com/api-reference/v1/list-tag-value get /v1/businesses/{businessId}/tags/values Returns a list of tag values for the business. These are the predefined values that can be used when creating tags. # List tasks Source: https://docs.layerfi.com/api-reference/v1/list-tasks get /v1/businesses/{businessId}/tasks Fetches a list of tasks for a business. Tasks only exist for businesses enrolled in bookkeeping services, and task lifecycle management is handled by Layer's bookkeeping team. # List tax packets Source: https://docs.layerfi.com/api-reference/v1/list-tax-packets get /v1/businesses/{businessId}/reports/tax-packets Returns a list of tax packet requests for the business, optionally filtered by year or including archived requests. # List transaction documents Source: https://docs.layerfi.com/api-reference/v1/list-transaction-documents get /v1/businesses/{businessId}/bank-transactions/{transactionId}/documents Returns the documents associated with the provided bank transaction id. Bank transaction documents are most commonly receipts, but any document may be uploaded, such as an invoice. Images (`jpg` & `png`) and PDFs are supported. Each document will be served as a presigned URL, which is a secure, temporarily available link to the document. # List trips Source: https://docs.layerfi.com/api-reference/v1/list-trips get /v1/businesses/{businessId}/mileage/trips Returns a paginated list of trips for the specified business. Trips can be filtered by date range, purpose, vehicle, and search query. # List vehicles Source: https://docs.layerfi.com/api-reference/v1/list-vehicles get /v1/businesses/{businessId}/mileage/vehicles Returns a list of all vehicles for the specified business. Vehicles can be filtered by archived and deleted status. # List vendor credits Source: https://docs.layerfi.com/api-reference/v1/list-vendor-credits get /v1/businesses/{businessId}/bills/vendor-credits Returns a list of vendor credits for the specified business. Vendor credits can be filtered by date range and vendor. Results will be paginated. # List vendor payouts Source: https://docs.layerfi.com/api-reference/v1/list-vendor-payouts get /v1/businesses/{businessId}/vendor-payouts Fetches a list of vendor payouts for a business. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List vendors Source: https://docs.layerfi.com/api-reference/v1/list-vendors get /v1/businesses/{businessId}/vendors Returns a list of vendors for the specified business. # Archive a loan Source: https://docs.layerfi.com/api-reference/v1/loans/archive-loan delete /v1/businesses/{businessId}/loans/{loanId} Archives a loan. Archived loans are excluded from list responses. # Archive a loan payment Source: https://docs.layerfi.com/api-reference/v1/loans/archive-loan-payment delete /v1/businesses/{businessId}/loans/payments/{paymentId} Archives a loan payment. A payment that is part of a customer payout cannot be archived. # Archive a loan proceed Source: https://docs.layerfi.com/api-reference/v1/loans/archive-loan-proceed delete /v1/businesses/{businessId}/loans/{loanId}/proceeds/{proceedId} Archives a loan proceed and reverses its ledger entries. The loan's total disbursed proceeds must still cover the principal that has been repaid, otherwise the request is rejected. # Bulk create loan payments Source: https://docs.layerfi.com/api-reference/v1/loans/bulk-create-loan-payments post /v1/businesses/{businessId}/loans/{loanId}/payments/bulk Creates or updates payments for a loan in a single atomic request. Items are upserted by `external_id`: payments matching an existing `external_id` are updated, all others are created. The response returns payments in request order. If any item is invalid, the entire batch is rejected. Items may omit `loan_id` and `loan_external_id`; if provided, they must match the loan in the request path. # Create a loan Source: https://docs.layerfi.com/api-reference/v1/loans/create-loan post /v1/businesses/{businessId}/loans Creates a new loan for the specified business, or updates an existing one. If a loan with the same `external_id` already exists it is upserted: the loan fields are updated and, when `proceeds` is provided, its proceeds are reconciled by proceed `external_id`. A dedicated ledger account is created for new loans. The request shape depends on `loan_type`. # Create a loan payment Source: https://docs.layerfi.com/api-reference/v1/loans/create-loan-payment post /v1/businesses/{businessId}/loans/payments Records a payment against a loan, split into principal, interest, and fee portions. Identify the loan with either `loan_id` or `loan_external_id`. # Create a loan proceed Source: https://docs.layerfi.com/api-reference/v1/loans/create-loan-proceed post /v1/businesses/{businessId}/loans/{loanId}/proceeds Adds a proceed to a loan. A proceed is either a cash `DISBURSEMENT` or an `ASSET` the loan financed. # Fetch a loan Source: https://docs.layerfi.com/api-reference/v1/loans/fetch-loan get /v1/businesses/{businessId}/loans/{loanId} Returns a single loan by ID. # Fetch a loan payment Source: https://docs.layerfi.com/api-reference/v1/loans/fetch-loan-payment get /v1/businesses/{businessId}/loans/payments/{paymentId} Returns a single loan payment by ID. # Fetch a loan proceed Source: https://docs.layerfi.com/api-reference/v1/loans/fetch-loan-proceed get /v1/businesses/{businessId}/loans/{loanId}/proceeds/{proceedId} Returns a single loan proceed by ID. # List loan payments Source: https://docs.layerfi.com/api-reference/v1/loans/list-loan-payments get /v1/businesses/{businessId}/loans/payments Returns a list of loan payments across all loans for the specified business. Results are paginated; see [Pagination](/api-details/pagination) for details. # List loan proceeds Source: https://docs.layerfi.com/api-reference/v1/loans/list-loan-proceeds get /v1/businesses/{businessId}/loans/{loanId}/proceeds Returns all proceeds for a specific loan. # List loans Source: https://docs.layerfi.com/api-reference/v1/loans/list-loans get /v1/businesses/{businessId}/loans Returns a list of loans for the specified business. Results are paginated; see [Pagination](/api-details/pagination) for details. # List payments for a loan Source: https://docs.layerfi.com/api-reference/v1/loans/list-payments-for-loan get /v1/businesses/{businessId}/loans/{loanId}/payments Returns all payments recorded against a specific loan. # Update a loan Source: https://docs.layerfi.com/api-reference/v1/loans/update-loan patch /v1/businesses/{businessId}/loans/{loanId} Updates a loan. Only the fields you include are changed. The request shape depends on `loan_type`. # Update a loan payment Source: https://docs.layerfi.com/api-reference/v1/loans/update-loan-payment patch /v1/businesses/{businessId}/loans/payments/{paymentId} Updates a loan payment. Only the fields you include are changed. A payment that is part of a customer payout cannot be updated. # Update a loan proceed Source: https://docs.layerfi.com/api-reference/v1/loans/update-loan-proceed patch /v1/businesses/{businessId}/loans/{loanId}/proceeds/{proceedId} Updates a loan proceed. Only the fields you include are changed; the underlying ledger entries are reversed and re-posted to reflect the change. Reducing a proceed below the principal that has already been repaid is rejected. # Mark task completed Source: https://docs.layerfi.com/api-reference/v1/mark-task-completed post /v1/businesses/{businessId}/tasks/{taskId}/mark-user-completed Marks a task as completed by the user. Tasks only exist for businesses enrolled in bookkeeping services, and task lifecycle management is handled by Layer's bookkeeping team. This endpoint is used by Layer's `` component to mark tasks as user completed, and if you use embedded components, you should not need to call this endpoint directly. # Match bank transaction Source: https://docs.layerfi.com/api-reference/v1/match-bank-transaction put /v1/businesses/{businessId}/bank-transactions/{transactionId}/match Match a bank transaction to a financial event such as an invoice payment or a payout. This should be used when platforms have pre-existing knowledge of what bank transactions are associated with a financial event, or when a user confirms a suggested match in a UI. If you are using Layer's [Bank Transactions](/embedded-components/components/bank-transactions) embedded component, you are unlikely to need to call this endpoint directly. Suggested matches can be found on a [Bank Transaction Object](/api-reference/bank-transaction/bank-transaction). # Multipart Upload Guide Source: https://docs.layerfi.com/api-reference/v1/multipart-upload-guide Documents are uploaded directly to S3 using a multipart upload. Layer issues presigned URLs for each part, you `PUT` the file bytes straight to S3, and then tell Layer to assemble the parts. This keeps large files off Layer's servers and supports files that exceed standard single-request limits. The flow uses three endpoints: 1. [**Create**](/api-reference/v1/create-document-upload) — register the document and get presigned URLs for each part. 2. [**Complete**](/api-reference/v1/complete-document-upload) — finalize the upload once every part is uploaded. 3. [**Abort**](/api-reference/v1/abort-document-upload) — cancel the upload and discard any uploaded parts. `POST /v1/businesses/{businessId}/documents` with the document metadata. The response contains the `document_id`, the S3 `upload_id`, the `part_size_bytes` each part must be, and a `parts` array of presigned URLs (one per part). ```json Request theme={null} { "document_type": "OTHER", "file_name": "LargeZip.zip", "file_type": "application/zip", "file_size_bytes": 167773989 } ``` ```json Response (201) theme={null} { "document_id": "86e30ada-1f5d-4b44-84f1-950a7c75ab33", "upload_id": "wSHGMiqwSlI7jq_Sbqe...", "part_size_bytes": 8388608, "parts": [ { "part_number": 1, "url": "https://s3.../part-1?X-Amz-Signature=..." }, { "part_number": 2, "url": "https://s3.../part-2?X-Amz-Signature=..." } ] } ``` `document_type` is one of `RECEIPT`, `UNSTRUCTURED_BOOKKEEPING_CONTEXT`, or `OTHER`. Split the file into chunks of exactly `part_size_bytes` (the final part may be smaller) and `PUT` each chunk to its presigned `url`. These requests go directly to S3, **not** to the Layer API, and need no `Authorization` header. Capture the `ETag` response header from each `PUT` — you'll need it to complete the upload. Keep each part the full `part_size_bytes` (except the last), and pair every ETag with the correct `part_number`. A mismatched size or a missing/misnumbered ETag will cause the complete step to fail. Parts are independent and can be uploaded in **any order and in parallel**. The examples below loop sequentially for clarity, but in production upload several parts concurrently (a worker pool of \~4–8 is a good default) to cut total upload time significantly — just make sure each ETag stays matched to its `part_number`, and sort the `parts` list by `part_number` before calling complete. `POST /v1/businesses/{businessId}/documents/{documentId}/complete` with the `upload_id` and the collected `{ part_number, etag }` pairs. S3 stitches the parts into the final object and Layer returns the stored document. ```json Request theme={null} { "upload_id": "wSHGMiqwSlI7jq_Sbqe...", "parts": [ { "part_number": 1, "etag": "5384e6f5dc735116fc4732ab74fa8398" }, { "part_number": 2, "etag": "6494f12f6382e115546a1a6f1462a6ae" } ] } ``` ```json Response (200) theme={null} { "id": "86e30ada-1f5d-4b44-84f1-950a7c75ab33", "file_name": "LargeZip.zip", "file_type": "application/zip", "document_type": "OTHER", "presigned_url": { "type": "S3_Presigned_Url", "presignedUrl": "https://s3.../LargeZip.zip?X-Amz-Signature=...", "fileType": "application/zip", "fileName": "LargeZip.zip", "createdAt": "2026-08-14T17:00:00Z", "documentId": "86e30ada-1f5d-4b44-84f1-950a7c75ab33", "document_type": "OTHER" } } ``` ## Aborting an upload If an upload fails partway through or is no longer needed, call [Abort](/api-reference/v1/abort-document-upload) to release the uploaded parts. Pass the `upload_id` from the create step: ```json Request theme={null} { "upload_id": "wSHGMiqwSlI7jq_Sbqe..." } ``` `POST /v1/businesses/{businessId}/documents/{documentId}/abort` returns an empty `200` response. ## End-to-end example The following uploads a file through all three steps. `access_token` is a Bearer token obtained via [scoped authentication](/api-reference/v1/create-business-auth-token). ```bash cURL theme={null} BASE="https://api.layerfi.com" BUSINESS_ID="..." TOKEN="$ACCESS_TOKEN" FILE="LargeZip.zip" # 1. Create — get presigned part URLs CREATE=$(curl -s -X POST "$BASE/v1/businesses/$BUSINESS_ID/documents" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d "{\"document_type\":\"OTHER\",\"file_name\":\"$FILE\",\"file_type\":\"application/zip\",\"file_size_bytes\":$(wc -c < "$FILE")}") DOCUMENT_ID=$(echo "$CREATE" | jq -r .document_id) UPLOAD_ID=$(echo "$CREATE" | jq -r .upload_id) PART_SIZE=$(echo "$CREATE" | jq -r .part_size_bytes) # 2. Split the file into parts and PUT each one to S3, capturing ETags. # Use a fresh temp dir so stale chunks from a previous run can't leak in. PARTS_DIR=$(mktemp -d) trap 'rm -rf "$PARTS_DIR"' EXIT split -b "$PART_SIZE" "$FILE" "$PARTS_DIR/part_" PARTS="[]"; i=0 for chunk in "$PARTS_DIR"/part_*; do i=$((i + 1)) URL=$(echo "$CREATE" | jq -r ".parts[$((i - 1))].url") ETAG=$(curl -s -X PUT --data-binary "@$chunk" -D - -o /dev/null "$URL" \ | tr -d '\r' | awk -F'"' '/^[Ee][Tt][Aa][Gg]:/ {print $2}') PARTS=$(echo "$PARTS" | jq ". + [{\"part_number\":$i,\"etag\":\"$ETAG\"}]") done # 3. Complete the upload curl -s -X POST "$BASE/v1/businesses/$BUSINESS_ID/documents/$DOCUMENT_ID/complete" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d "{\"upload_id\":\"$UPLOAD_ID\",\"parts\":$PARTS}" ``` ```python Python theme={null} import os, requests BASE = "https://api.layerfi.com" business_id = "..." file_path = "LargeZip.zip" auth = {"Authorization": f"Bearer {access_token}"} # 1. Create — get presigned part URLs create = requests.post( f"{BASE}/v1/businesses/{business_id}/documents", headers={**auth, "Content-Type": "application/json"}, json={ "document_type": "OTHER", "file_name": os.path.basename(file_path), "file_type": "application/zip", "file_size_bytes": os.path.getsize(file_path), }, ).json() document_id = create["document_id"] upload_id = create["upload_id"] part_size = create["part_size_bytes"] parts = sorted(create["parts"], key=lambda p: p["part_number"]) # 2. Upload each part directly to S3, capturing ETags completed = [] with open(file_path, "rb") as f: for p in parts: chunk = f.read(part_size) if not chunk: break put = requests.put(p["url"], data=chunk) put.raise_for_status() completed.append({ "part_number": p["part_number"], "etag": put.headers["ETag"].strip('"'), }) # 3. Complete the upload doc = requests.post( f"{BASE}/v1/businesses/{business_id}/documents/{document_id}/complete", headers={**auth, "Content-Type": "application/json"}, json={"upload_id": upload_id, "parts": completed}, ).json() print("Uploaded document:", doc["id"]) ``` ```javascript JavaScript theme={null} import { readFileSync, statSync } from "fs"; const BASE = "https://api.layerfi.com"; const businessId = "..."; const filePath = "LargeZip.zip"; const auth = { Authorization: `Bearer ${accessToken}` }; // 1. Create — get presigned part URLs const create = await fetch(`${BASE}/v1/businesses/${businessId}/documents`, { method: "POST", headers: { ...auth, "Content-Type": "application/json" }, body: JSON.stringify({ document_type: "OTHER", file_name: "LargeZip.zip", file_type: "application/zip", file_size_bytes: statSync(filePath).size, }), }).then((r) => r.json()); const { document_id, upload_id, part_size_bytes, parts } = create; // 2. Upload each part to S3, capturing ETags const file = readFileSync(filePath); const completed = []; for (const { part_number, url } of parts.sort((a, b) => a.part_number - b.part_number)) { const start = (part_number - 1) * part_size_bytes; const chunk = file.subarray(start, start + part_size_bytes); const res = await fetch(url, { method: "PUT", body: chunk }); completed.push({ part_number, etag: res.headers.get("etag").replaceAll('"', "") }); } // 3. Complete the upload const doc = await fetch( `${BASE}/v1/businesses/${businessId}/documents/${document_id}/complete`, { method: "POST", headers: { ...auth, "Content-Type": "application/json" }, body: JSON.stringify({ upload_id, parts: completed }), }, ).then((r) => r.json()); console.log("Uploaded document:", doc.id); ``` ```php PHP theme={null} true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array_merge($auth, ["Content-Type: application/json"]), CURLOPT_POSTFIELDS => json_encode($payload), ]); return json_decode(curl_exec($ch), true); } // 1. Create — get presigned part URLs $create = postJson("$base/v1/businesses/$businessId/documents", $auth, [ "document_type" => "OTHER", "file_name" => "LargeZip.zip", "file_type" => "application/zip", "file_size_bytes" => filesize($filePath), ]); $documentId = $create["document_id"]; $partSize = $create["part_size_bytes"]; // 2. Upload each part to S3, capturing ETags $handle = fopen($filePath, "rb"); $completed = []; foreach ($create["parts"] as $part) { $chunk = fread($handle, $partSize); $ch = curl_init($part["url"]); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_POSTFIELDS => $chunk, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, ]); $response = curl_exec($ch); $headers = substr($response, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); preg_match('/etag:\s*"?([^"\r\n]+)"?/i', $headers, $m); $completed[] = ["part_number" => $part["part_number"], "etag" => $m[1]]; } fclose($handle); // 3. Complete the upload $doc = postJson("$base/v1/businesses/$businessId/documents/$documentId/complete", $auth, [ "upload_id" => $create["upload_id"], "parts" => $completed, ]); echo "Uploaded document: " . $doc["id"]; ``` ```go Go theme={null} package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "os" "sort" "strings" ) const base = "https://api.layerfi.com" func main() { businessID, filePath, token := "...", "LargeZip.zip", accessToken info, _ := os.Stat(filePath) // 1. Create — get presigned part URLs body, _ := json.Marshal(map[string]any{ "document_type": "OTHER", "file_name": "LargeZip.zip", "file_type": "application/zip", "file_size_bytes": info.Size(), }) req, _ := http.NewRequest("POST", base+"/v1/businesses/"+businessID+"/documents", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) var create struct { DocumentID string `json:"document_id"` UploadID string `json:"upload_id"` PartSizeBytes int64 `json:"part_size_bytes"` Parts []struct { PartNumber int `json:"part_number"` URL string `json:"url"` } `json:"parts"` } json.NewDecoder(resp.Body).Decode(&create) sort.Slice(create.Parts, func(i, j int) bool { return create.Parts[i].PartNumber < create.Parts[j].PartNumber }) // 2. Upload each part to S3, capturing ETags f, _ := os.Open(filePath) defer f.Close() type part struct { PartNumber int `json:"part_number"` ETag string `json:"etag"` } var completed []part buf := make([]byte, create.PartSizeBytes) for _, p := range create.Parts { n, _ := io.ReadFull(f, buf) put, _ := http.NewRequest("PUT", p.URL, bytes.NewReader(buf[:n])) pr, _ := http.DefaultClient.Do(put) completed = append(completed, part{p.PartNumber, strings.Trim(pr.Header.Get("ETag"), "\"")}) } // 3. Complete the upload cb, _ := json.Marshal(map[string]any{"upload_id": create.UploadID, "parts": completed}) cReq, _ := http.NewRequest("POST", base+"/v1/businesses/"+businessID+"/documents/"+create.DocumentID+"/complete", bytes.NewReader(cb)) cReq.Header.Set("Authorization", "Bearer "+token) cReq.Header.Set("Content-Type", "application/json") cResp, _ := http.DefaultClient.Do(cReq) out, _ := io.ReadAll(cResp.Body) fmt.Println(string(out)) } ``` ```java Java theme={null} // Java 11+ (java.net.http). Use a JSON library (e.g. Jackson) to parse/build the // create response and complete request; field access is shown in comments. import java.net.URI; import java.net.http.*; import java.nio.file.*; import java.util.*; var base = "https://api.layerfi.com"; var businessId = "..."; var filePath = Path.of("LargeZip.zip"); var client = HttpClient.newHttpClient(); // 1. Create — get presigned part URLs var createBody = """ {"document_type":"OTHER","file_name":"LargeZip.zip","file_type":"application/zip","file_size_bytes":%d}""" .formatted(Files.size(filePath)); var create = client.send( HttpRequest.newBuilder(URI.create(base + "/v1/businesses/" + businessId + "/documents")) .header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(createBody)).build(), HttpResponse.BodyHandlers.ofString()); // Parse from create.body(): documentId, uploadId, partSize, parts[] (each part_number + url). // 2. Upload each part to S3, capturing ETags byte[] file = Files.readAllBytes(filePath); List> completed = new ArrayList<>(); for (var part : parts) { // for each {partNumber, url} int start = (part.partNumber - 1) * partSize; byte[] chunk = Arrays.copyOfRange(file, start, Math.min(start + partSize, file.length)); var put = client.send( HttpRequest.newBuilder(URI.create(part.url)) .PUT(HttpRequest.BodyPublishers.ofByteArray(chunk)).build(), HttpResponse.BodyHandlers.discarding()); String etag = put.headers().firstValue("etag").orElseThrow().replace("\"", ""); completed.add(Map.of("part_number", part.partNumber, "etag", etag)); } // 3. Complete the upload — POST {"upload_id": uploadId, "parts": completed} (serialize with your JSON lib) // to /v1/businesses/{businessId}/documents/{documentId}/complete ``` ```ruby Ruby theme={null} require "net/http" require "json" require "uri" base = "https://api.layerfi.com" business_id = "..." file_path = "LargeZip.zip" auth = { "Authorization" => "Bearer #{access_token}" } # 1. Create — get presigned part URLs create = Net::HTTP.post( URI("#{base}/v1/businesses/#{business_id}/documents"), { document_type: "OTHER", file_name: "LargeZip.zip", file_type: "application/zip", file_size_bytes: File.size(file_path) }.to_json, auth.merge("Content-Type" => "application/json")) data = JSON.parse(create.body) document_id, upload_id, part_size = data["document_id"], data["upload_id"], data["part_size_bytes"] # 2. Upload each part to S3, capturing ETags completed = [] File.open(file_path, "rb") do |f| data["parts"].sort_by { |p| p["part_number"] }.each do |part| chunk = f.read(part_size) break if chunk.nil? uri = URI(part["url"]) res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| req = Net::HTTP::Put.new(uri) req.body = chunk http.request(req) end completed << { part_number: part["part_number"], etag: res["etag"].delete('"') } end end # 3. Complete the upload doc = Net::HTTP.post( URI("#{base}/v1/businesses/#{business_id}/documents/#{document_id}/complete"), { upload_id: upload_id, parts: completed }.to_json, auth.merge("Content-Type" => "application/json")) puts "Uploaded document: #{JSON.parse(doc.body)["id"]}" ``` Presigned URLs are time-limited. Upload the parts and call complete promptly after creating the upload; if a URL expires, start over with a new create request (and optionally abort the old `upload_id`). # Patch accounting configuration Source: https://docs.layerfi.com/api-reference/v1/patch-accounting-configuration patch /v1/businesses/{businessId}/accounting-config Updates the accounting configuration associated for the provided business. This is the means by which you can update things such as the default reporting basis for a business or mark the books as closed. # Patch custom account Source: https://docs.layerfi.com/api-reference/v1/patch-custom-account patch /v1/businesses/{businessId}/custom-accounts/{customAccountId} Updates a custom account for a business. Patch style update will only change specified fields. # Patch invoice Source: https://docs.layerfi.com/api-reference/v1/patch-invoice patch /v1/businesses/{businessId}/invoices/{invoiceId} Partially updates an existing invoice. Provide only the fields you want to change. At least one field is required. Payments, refunds, and write-offs are not changed, but updates cannot put the invoice into an overpaid state. # Patch refund Source: https://docs.layerfi.com/api-reference/v1/patch-refund patch /v1/businesses/{businessId}/invoices/refunds/{refundId} Partially updates an existing refund. Only the fields provided will be updated. If allocations or payments are provided, they will fully replace the existing allocations or payments respectively, and ledger entries will be reversed and recreated. # Patch transaction metadata Source: https://docs.layerfi.com/api-reference/v1/patch-transaction-metadata patch /v1/businesses/{businessId}/bank-transactions/{transactionId}/metadata Updates the metadata for the provided bank transaction. Include only the fields you want to change. Omitted fields stay unchanged. Send null for a field to clear it. # Patch update customer Source: https://docs.layerfi.com/api-reference/v1/patch-update-customer patch /v1/businesses/{businessId}/customers/{customerId} Patch (partially) updates an existing customer. # Patch update ledger account Source: https://docs.layerfi.com/api-reference/v1/patch-update-ledger-account patch /v1/businesses/{businessId}/ledger/accounts/{accountId} Partially updates a ledger account based on the provided fields. # Patch update vendor Source: https://docs.layerfi.com/api-reference/v1/patch-update-vendor patch /v1/businesses/{businessId}/vendors/{vendorId} Patches (partially updates) an existing vendor. # Preview retained earnings Source: https://docs.layerfi.com/api-reference/v1/preview-retained-earnings-closing-action post /v1/businesses/{businessId}/closing/retained-earnings/preview Dry-run a retained earnings adjustment without creating it. # Reactivate custom account Source: https://docs.layerfi.com/api-reference/v1/reactivate-custom-account post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/reactivate Reactivates a custom account for a business. This action will allow the account to sync new transactions and will add the account back to the Layer dashboard. # Reactivate vehicle Source: https://docs.layerfi.com/api-reference/v1/reactivate-vehicle post /v1/businesses/{businessId}/mileage/vehicles/{vehicleId}/reactivate Reactivates an archived vehicle, making it visible in the default vehicle list again. # Record a payment Source: https://docs.layerfi.com/api-reference/v1/record-a-payment post /v1/businesses/{businessId}/invoices/payments Records a payment that can be allocated to one or more invoices and/or ledger accounts. # Record write-off Source: https://docs.layerfi.com/api-reference/v1/record-write-off post /v1/businesses/{businessId}/invoices/{invoiceId}/write-off This endpoint records a write-off of an invoice in Layer. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 5 requests | 1 second | 5 requests | | Production | 25 requests | 1 second | 25 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Request business data deletion Source: https://docs.layerfi.com/api-reference/v1/request-business-data-deletion post /v1/businesses/{businessId}/request-data-deletion Permanently deletes the business and business-owned data associated with the provided business id. This hard deletion endpoint is intended for CCPA and GDPR compliance requests. Unlike archiving a business, this operation is irreversible. # Set bookkeeping start date Source: https://docs.layerfi.com/api-reference/v1/set-bookkeeping-start-date post /v1/businesses/{businessId}/bookkeeping/start-date Set the first month of bookkeeping. This can be a historical month when a customer wants catchup bookkeeping or a future month when a customer wants to begin bookkeeping. # Set business read-only status Source: https://docs.layerfi.com/api-reference/v1/set-business-readonly-status put /v1/businesses/{businessId}/readonly-status Sets or clears the business's read-only mode. While a business is on read-only mode, any mutating request (POST, PUT, PATCH, DELETE) under `/v1/businesses/{businessId}` is rejected with an HTTP 403 response. ```json theme={null} { "errors":[ { "type":"InvalidState", "description":"Business is readonly", "error_enum":"ReadOnlyBusiness" } ] } ``` This PUT endpoint is exempt from that rejection. You can always call it to set or clear the flag, including while the business is read-only. Read (GET) requests are unaffected. ## Bank connections and reversibility Enabling read-only mode disconnects the business's bank connections that are linked through Plaid (the business's `plaid_items`) as part of the same request. Clearing the flag restores writes, but it does not reconnect them. Disconnecting bank connections is irreversible. Clearing read-only mode does not reconnect them. ## Response A successful request returns the full, updated business in `data`, the same representation returned by [Fetch a business](/api-reference/v1/fetch-business). Its `readonly` field reflects the resulting read-only state. # Set opening balance Source: https://docs.layerfi.com/api-reference/v1/set-opening-balance post /v1/businesses/{businessId}/custom-accounts/{customAccountId}/balance Sets the balance of the account at a specific time, which is necessary for showing both a current balance and a correct opening balance. This is useful when configuring the account for the first time or when accounting features are enabled starting at a time after the account was created. # Submit task response Source: https://docs.layerfi.com/api-reference/v1/submit-task-response post /v1/businesses/{businessId}/tasks/{taskId}/user-response Submits or updates a task user response for a business. Tasks only exist for businesses enrolled in bookkeeping services, and task lifecycle management is handled by Layer's bookkeeping team. This endpoint is used by Layer's `` component to submit user responses, and if you use embedded components, you should not need to call this endpoint directly. # Sync from Quickbooks Source: https://docs.layerfi.com/api-reference/v1/sync-from-quickbooks post /v1/businesses/{businessId}/quickbooks/sync-from Syncs Quickbooks data for a business. This endpoint can be used to manually trigger a sync from Quickbooks. # Tag entities Source: https://docs.layerfi.com/api-reference/v1/tag-entities post /v1/businesses/{businessId}/tags Tag entities of a specified type with custom tags. This generic endpoint allows tagging of any supported entity type. When tagging a BANK_ACCOUNT, the tags are automatically applied to all transactions and opening balances associated with that bank account. # Create tax profile Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/create-tax-profile post /v1/businesses/{businessId}/tax-estimates/profile Creates a new tax profile for the business. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Creates the business's [tax profile](/api-reference/v1/tax-estimates/get-tax-profile): the inputs that drive every Tax Estimates calculation. Call this once when the user first configures their tax settings; subsequent updates should use [Update tax profile](/api-reference/v1/tax-estimates/update-tax-profile). The request body is an `ApiTaxProfile` object covering federal filing status, W-2/withholding inputs, state and state withholding, deductions configuration (home office, vehicle/mileage), and optional business revenue/expense estimates. See the [Get tax profile](/api-reference/v1/tax-estimates/get-tax-profile) response schema for the full field list. Returns `400` if a profile already exists for the business. In that case use [Update tax profile](/api-reference/v1/tax-estimates/update-tax-profile) (PATCH) instead. Once created, `user_has_saved_tax_profile` becomes `true` and the `MISSING_PROFILE` item is removed from the [tax checklist](/api-reference/v1/tax-estimates/get-tax-checklist). # Export tax documents Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/export-tax-documents post /v1/businesses/{businessId}/tax-estimates/export Generates tax documents for download. Returns a pre-signed S3 URL. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Generates a downloadable tax document for the requested `year` and returns a pre-signed S3 URL. The URL is time-limited; download the document promptly after receiving it. ## Document types The `type` query parameter selects which document to export: * `TAX_PACKET`: a combined packet containing the business's tax summary and supporting detail for the year, suitable for sharing with a tax preparer. * `SCHEDULE_C`: a Schedule C (profit or loss from business) export derived from the business's P\&L data for the year. * `PAYMENT_HISTORY`: the quarterly estimated tax payment history, mirroring [Get tax payments](/api-reference/v1/tax-estimates/get-tax-payments) in downloadable form. # Get tax checklist Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-checklist get /v1/businesses/{businessId}/tax-estimates/checklist Returns actionable items that need user attention for tax preparation. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns actionable items that need the business owner's attention before their tax estimate can be considered complete. Use this to surface a "to-do" list in your UI. ## Checklist item types Each item has a `type` that indicates what needs attention: * `UNCATEGORIZED_DEDUCTIONS`: deductible transactions that have not yet been categorized. `amount` is the uncategorized total in cents; `count` is the number of transactions. These reduce the accuracy of the deduction total in [Get tax details](/api-reference/v1/tax-estimates/get-tax-details) until categorized. * `UNCATEGORIZED_DEPOSITS`: income transactions that have not yet been categorized. These reduce the accuracy of the income total in the calculation. * `MISSING_PROFILE`: the business has not yet saved a [tax profile](/api-reference/v1/tax-estimates/get-tax-profile), so the calculation is running with default assumptions (e.g. `SINGLE` filing status, no W-2 income, no state). Each item includes a human-readable `description` and an optional `action_url` deep link that your UI can open to help the user resolve it. Resolving checklist items improves the accuracy of [Get tax summary](/api-reference/v1/tax-estimates/get-tax-summary), [Get tax overview](/api-reference/v1/tax-estimates/get-tax-overview), and [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). # Get tax details Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-details get /v1/businesses/{businessId}/tax-estimates/details Returns detailed breakdown of tax calculations including adjusted gross income, deductions, and federal taxes. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns the full itemized breakdown of how a business's projected tax liability is calculated for the year. This is the most detailed of the Tax Estimates endpoints; use it when you need to show or reconcile the individual components behind the numbers surfaced by [Get tax summary](/api-reference/v1/tax-estimates/get-tax-summary) and [Get tax overview](/api-reference/v1/tax-estimates/get-tax-overview). ## Inputs to tax calculation The calculation combines two sources: 1. The business's [tax profile](/api-reference/v1/tax-estimates/get-tax-profile): filing status, W-2 income, tip/overtime income, withholding, state, deductions configuration (home office, vehicle/mileage), and any user-estimated business revenue/expense overrides. 2. The business's year-to-date financials on the requested `reporting_basis`: business revenue and deductible expenses are pulled from the same P\&L data that powers the [P\&L report](/api-reference/v1/fetch-p\&l-report). When `full_year_projection=true`, year-to-date income and expenses are projected forward to estimate a full-year figure before taxes are computed. The parameter defaults to `false`, so you must opt in to projection. For past years, the calculation always uses actual full-year data and `full_year_projection` has no effect. All monetary fields in the response are in cents. ## Income and expense calculation Business revenue and deductible expenses are not pulled from the P\&L directly. They are derived from the **Schedule C report**, which maps each categorized ledger account to a specific IRS Schedule C line. You can fetch that raw line-item report yourself with the [Schedule C report](/api-reference/v1/fetch-schedule-c-report) endpoint. **Income (taxable business revenue)** comes from Schedule C Part I: * Line 1 (Gross receipts) minus Line 2 (Returns and allowances), plus Line 6 (Other income). **Deductible expenses** come from Schedule C Part II (operating expenses), Part III (cost of goods sold), Part V (other expenses), and Schedule A (charitable contributions). The vehicle expense (Line 9) is pulled out separately so the calculation can apply the mileage vs. actual-expense method from the [tax profile](/api-reference/v1/tax-estimates/get-tax-profile); see `vehicle_expense` in the deductions breakdown above. **Categories excluded from the tax calculation** are those mapped to non-applicable Schedule C boxes: * Equity accounts (owner's draw, capital contributions, personal expenses). * Non-deductible items (accounts explicitly marked non-deductible). * Capitalized assets (these belong on the balance sheet, not the P\&L). * Clearing and liability accounts (temporary or non-business accounts). * Uncategorized expenses awaiting review (see [Pending and uncategorized transactions](#pending-and-uncategorized-transactions) below). One special rule: meals are reduced by 50% per IRS rules before being counted as a deductible expense. ### Pending and uncategorized transactions Only **categorized** transactions appear in the Schedule C report and therefore in the tax calculation. Transactions that have not yet been categorized do not have ledger entries and are implicitly excluded from every income and expense figure in this response. There is no query parameter to include pending transactions in the calculation. `total_income`, `total_deductions` and every downstream number can shift as the user categorizes more transactions. To surface the amounts that are currently missing from the calculation, use [Get tax checklist](/api-reference/v1/tax-estimates/get-tax-checklist), which returns the uncategorized deduction and deposit totals with counts. # Get tax overview Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-overview get /v1/businesses/{businessId}/tax-estimates/overview Returns high-level tax summary for dashboard display. Each summary field includes a corresponding URL for retrieving itemized breakdowns. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns the highest-level tax roll-up for top-of-dashboard display. This is the lightest of the Tax Estimates endpoints; use it for headline numbers, and use [Get tax details](/api-reference/v1/tax-estimates/get-tax-details) for the itemized calculation behind them. ## What the numbers mean Each field is derived from the same calculation as [Get tax details](/api-reference/v1/tax-estimates/get-tax-details), rolled up: * `total_income`: total business income (Schedule C revenue) plus any W-2/other income included in the calculation, in cents. * `total_deductions`: total deductions applied (business expenses, vehicle, home office, qualified tip/overtime, self-employment tax deduction), in cents. * `taxable_income_estimate`: the estimated taxable income after deductions, in cents. * `estimated_taxes_owed`: total projected tax liability (federal + state), in cents. * `taxes_due_date`: the next tax deadline in ISO-8601 date format. # Get tax payments Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-payments get /v1/businesses/{businessId}/tax-estimates/payments Returns quarterly tax payment history and tracking. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns the quarterly estimated tax payment history for the year, including roll-overs from prior quarters. Use this to show what has been paid and what remains due each quarter; for the underlying liability calculation, use [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). ## Quarterly payment calculation Each quarter in `quarters` reflects the split of the annual projected liability (from [Get tax details](/api-reference/v1/tax-estimates/get-tax-details)) into four estimated payments, combined with the actual payments the business has recorded. Note: Federal tax periods are not all the same length, and quarterly tax estimates are not equal across all quarters in a year. * `owed_this_quarter`: the projected liability allocated to this quarter, in cents. * `total_paid`: payments already recorded against this quarter, in cents. * `owed_rolled_over_from_previous`: the unpaid balance (positive) or overpayment (negative) carried forward from the previous quarter, in cents. * `total`: the net balance for the quarter, in cents, accounting for this quarter's owed amount, prior roll-overs, and payments made. Typical federal quarterly due dates are April 15, June 15, September 15, and January 15 of the following year; state due dates may differ and are returned per quarter via [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). # Get tax profile Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-profile get /v1/businesses/{businessId}/tax-estimates/profile Returns the current tax profile configuration. Does NOT create or modify data. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns the business's current tax profile: the inputs that drive the tax calculations in [Get tax summary](/api-reference/v1/tax-estimates/get-tax-summary), [Get tax overview](/api-reference/v1/tax-estimates/get-tax-overview), and [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). The profile includes: * `tax_country_code`: the country the calculation targets. * `us_configuration.federal`: federal filing status, annual W-2 income, tip/overtime income, and withholding (custom amount or default). * `us_configuration.state`: the targeted state for tax, state filing status, exemptions, and state withholding. * `us_configuration.deductions`: home office and vehicle/mileage deduction configuration. * `us_configuration.business_estimates`: optional user-estimated annual business revenue and expenses that override the year-to-date figures pulled from the P\&L. * `user_has_saved_tax_profile`: whether the user has explicitly saved a profile. When `false`, calculations run with default assumptions and a `MISSING_PROFILE` item appears on the [tax checklist](/api-reference/v1/tax-estimates/get-tax-checklist). # Get tax summary Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/get-tax-summary get /v1/businesses/{businessId}/tax-estimates/summary Returns a summary of projected taxes owed with breakdown by federal and state tax components. This provides a high-level overview of total taxes due, what has been paid, and what remains owed. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Returns a dashboard-ready summary of the business's projected tax liability for the year, broken out by federal and state components and net of payments already made. Use this for "what you owe" UIs; for the full itemized calculation behind these numbers, use [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). ## Summary calculation details The summary is a roll-up of the same calculation that powers [Get tax details](/api-reference/v1/tax-estimates/get-tax-details): * `projected_taxes_owed` is the total projected annual liability (federal income + self-employment + Medicare surtax + state income + state additional taxes), in cents, after applying the requested `reporting_basis` and `full_year_projection` behavior described below. * `taxes_due_at` is the due date of the next quarterly estimated tax payment. * `uncategorized_tax_payments` is the portion of recorded tax payments that have not yet been categorized as federal or state; these are excluded from the per-section `taxes_paid` totals until categorized. * `sections` breaks the total down by component (e.g. "Federal Income & Self-Employment Tax", "State Income Tax"). For each section: * `total` is the projected gross liability for that component, before any payments. * `taxes_paid` is the amount already paid toward that component. * `taxes_owed` = `total` − `taxes_paid` is the remaining balance for that component. Summing `taxes_owed` across `sections` (and accounting for `uncategorized_tax_payments`) reconciles to the overall amount still due. # Overview Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/overview Tax Estimates is a suite of endpoints that project a business's federal and state tax liability for a given year, based on their categorized income, deductible expenses, and tax profile. To enable the Tax Estimates feature for your customers, request access from your Layer representative. ## Core components * [Get tax overview](/api-reference/v1/tax-estimates/get-tax-overview) and [Get tax summary](/api-reference/v1/tax-estimates/get-tax-summary): high-level, dashboard-ready roll-ups of projected taxes owed. * [Get tax details](/api-reference/v1/tax-estimates/get-tax-details): the full itemized calculation (AGI, deductions, federal income tax, self-employment tax, state tax, quarterly estimates). * [Get tax payments](/api-reference/v1/tax-estimates/get-tax-payments): quarterly estimated tax payment history and balances. * [Get tax checklist](/api-reference/v1/tax-estimates/get-tax-checklist): actionable items that need the business owner's attention before the estimate is complete. * [Get tax profile](/api-reference/v1/tax-estimates/get-tax-profile), [Create tax profile](/api-reference/v1/tax-estimates/create-tax-profile), and [Update tax profile](/api-reference/v1/tax-estimates/update-tax-profile): the filing inputs (filing status, W-2 income, withholding, state, deductions) that drive every calculation. * [Export tax documents](/api-reference/v1/tax-estimates/export-tax-documents): generate downloadable tax packets, Schedule C, and payment history. ## Tax calculation overview Business revenue and deductible expenses are derived from the business's categorized ledger data via the Schedule C report. Only categorized transactions are included; uncategorized transactions are excluded from the calculation but surfaced on the [tax checklist](/api-reference/v1/tax-estimates/get-tax-checklist). For the full breakdown of how each number is computed, see [Get tax details](/api-reference/v1/tax-estimates/get-tax-details). # Update tax profile Source: https://docs.layerfi.com/api-reference/v1/tax-estimates/update-tax-profile patch /v1/businesses/{businessId}/tax-estimates/profile Updates an existing tax profile for the business. To enable the Tax Estimates feature for your customers, request access from your Layer representative. Updates an existing [tax profile](/api-reference/v1/tax-estimates/get-tax-profile) with a partial set of fields. Only the fields included in the request body are changed; omitted fields retain their current values. Use this for incremental edits to filing status, withholding, deductions, or business estimates. To replace the entire profile (treating omitted fields as cleared), issue a PUT to `/v1/businesses/{businessId}/tax-estimates/profile`. To create a profile that does not yet exist, use [Create tax profile](/api-reference/v1/tax-estimates/create-tax-profile) (POST). Any change to the profile immediately affects the outputs of [Get tax summary](/api-reference/v1/tax-estimates/get-tax-summary), [Get tax overview](/api-reference/v1/tax-estimates/get-tax-overview), [Get tax details](/api-reference/v1/tax-estimates/get-tax-details), and [Get tax payments](/api-reference/v1/tax-estimates/get-tax-payments) on their next call. Returns `404` if no tax profile exists for the business. # Bulk create time entries Source: https://docs.layerfi.com/api-reference/v1/time-tracking/bulk-create-time-entries post /v1/businesses/{businessId}/time-tracking/time-entries/bulk Creates multiple time entries in a single request (maximum 100). Each entry follows the same create-or-update logic based on external_id. # Create time entry Source: https://docs.layerfi.com/api-reference/v1/time-tracking/create-time-entry post /v1/businesses/{businessId}/time-tracking/time-entries Creates a new time entry. If a time entry with the same external_id already exists, it will be updated instead. # Preview invoice from time entries Source: https://docs.layerfi.com/api-reference/v1/time-tracking/get-invoice-preview get /v1/businesses/{businessId}/time-tracking/invoice-preview Generates an invoice preview from unbilled billable time entries for a specific customer. Returns invoice parameters that can be used to create an invoice. # Get time entry Source: https://docs.layerfi.com/api-reference/v1/time-tracking/get-time-entry get /v1/businesses/{businessId}/time-tracking/time-entries/{timeEntryId} Retrieves a single time entry by ID. # Get time entry summary Source: https://docs.layerfi.com/api-reference/v1/time-tracking/get-time-entry-summary get /v1/businesses/{businessId}/time-tracking/time-entries/summary Returns aggregated summary statistics for time entries, including totals and breakdowns by customer and service. # List time entries Source: https://docs.layerfi.com/api-reference/v1/time-tracking/list-time-entries get /v1/businesses/{businessId}/time-tracking/time-entries Returns a paginated list of time entries for the specified business with optional filters. # Update time entry Source: https://docs.layerfi.com/api-reference/v1/time-tracking/update-time-entry patch /v1/businesses/{businessId}/time-tracking/time-entries/{timeEntryId} Partially updates a time entry. Only the fields provided in the request body will be updated. # Unarchive business Source: https://docs.layerfi.com/api-reference/v1/unarchive-business post /v1/businesses/{businessId}/unarchive Unarchiving a business will re-activate it. All other endpoints will be able to access the business data again. No additional data syncing or modification will have taken place during the archived period. This is the only method available on a business while it is archived. # Unarchive vendor Source: https://docs.layerfi.com/api-reference/v1/unarchive-vendor post /v1/businesses/{businessId}/vendors/{vendorId}/unarchive Unarchives an existing vendor. # Uncategorize and archive external account Source: https://docs.layerfi.com/api-reference/v1/uncategorize-and-archive-external-account post /v1/businesses/{businessId}/external-accounts/{externalAccountId}/uncategorize-and-archive Uncategorizes all transactions and archives an external account. This purges the account by reverting all transaction categorizations and then archiving the account. The account will no longer sync new transactions and will be removed from the Layer dashboard. # Uncategorize bank transaction Source: https://docs.layerfi.com/api-reference/v1/uncategorize-bank-transaction put /v1/businesses/{businessId}/bank-transactions/{transactionId}/uncategorize Uncategorize a bank transaction. This will remove any categorization or match that has been applied to the transaction and reverse any ledger entries from the previous classification. # Update bank account Source: https://docs.layerfi.com/api-reference/v1/update-bank-account patch /v1/businesses/{businessId}/bank-accounts/{bankAccountId} Updates the specified bank account. Only provided fields are updated; omitted fields are left unchanged. # Update bill Source: https://docs.layerfi.com/api-reference/v1/update-bill post /v1/businesses/{businessId}/bills/{billId}/update Updates an existing bill. # Update bill payment Source: https://docs.layerfi.com/api-reference/v1/update-bill-payment post /v1/businesses/{businessId}/bills/bill-payments/{paymentId}/update Updates an existing bill payment. # Update business Source: https://docs.layerfi.com/api-reference/v1/update-business put /v1/businesses/{businessId} Updates the business associated with the provided business id. Note that all fields are optional and can be omitted. # Update client accounting configuration Source: https://docs.layerfi.com/api-reference/v1/update-client-accounting-configuration patch /v1/configure/{clientId}/accounting Updates the accounting configuration for the specified client. This allows you to modify settings such as the default reporting basis and mark books as closed at the client level. # Update custom account Source: https://docs.layerfi.com/api-reference/v1/update-custom-account put /v1/businesses/{businessId}/custom-accounts/{customAccountId} Updates a custom account for a business. Put style update will replace all fields. # Update customer credit Source: https://docs.layerfi.com/api-reference/v1/update-customer-credit patch /v1/businesses/{businessId}/invoices/customer-credits/{customerCreditId} Updates an existing customer credit. # Update dedicated invoice payment Source: https://docs.layerfi.com/api-reference/v1/update-dedicated-invoice-payment put /v1/businesses/{businessId}/invoices/{invoiceId}/payment/{paymentId} Updates a payment that is dedicated to a specific invoice. # Update invoice Source: https://docs.layerfi.com/api-reference/v1/update-invoice put /v1/businesses/{businessId}/invoices/{invoiceId} Updates an existing invoice. Payments, refunds and writeoffs are not changed, but updates to invoice cannot put the invoice into an overpaid state. # Update ledger account Source: https://docs.layerfi.com/api-reference/v1/update-ledger-account put /v1/businesses/{businessId}/ledger/accounts/{accountId} Fully updates a ledger account. All fields must be provided. # Update payment Source: https://docs.layerfi.com/api-reference/v1/update-payment patch /v1/businesses/{businessId}/invoices/payments/{paymentId} Update an invoice payment. Updates to information such as the amount or time will cause reversal of previous journal entries and creation of new entries. # Update payout Source: https://docs.layerfi.com/api-reference/v1/update-payout post /v1/businesses/{businessId}/payouts/{payoutId}/update Updates a payout for a business. Ledger entries will be reversed and new entries created for the updated payout. To keep ledger entries most understandable, we recommend updating payouts rather than deleting and recreating when the intent is to fix or update information from the same payout. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 1 requests | 1 second | 2 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Update Quickbooks account mapping Source: https://docs.layerfi.com/api-reference/v1/update-quickbooks-account-mapping post /v1/businesses/{businessId}/quickbooks/ledger/accounts/{accountId}/update-mapping This API call updates the mapping of a Quickbooks account to a Layer ledger account. # Update Quickbooks configuration Source: https://docs.layerfi.com/api-reference/v1/update-quickbooks-configuration put /v1/configure/quickbooks Update the current platform Quickbooks configuration. # Update refund Source: https://docs.layerfi.com/api-reference/v1/update-refund put /v1/businesses/{businessId}/invoices/refunds/{refundId} Fully replaces an existing refund. All allocations and payments will be replaced with the new values provided. This will reverse any existing ledger entries and create new ones based on the updated refund data. # Update SMS configuration Source: https://docs.layerfi.com/api-reference/v1/update-sms-configuration put /v1/businesses/{businessId}/sms Updates the SMS settings for the business associated with the provided business id. Currently this setting is an `enabled` flag. # Update Stripe configuration Source: https://docs.layerfi.com/api-reference/v1/update-stripe-configuration put /v1/configure/stripe Update the current platform Stripe configuration. Platform configuration includes the stripe secret used for API access, while business-level configuration includes specific Stripe entity IDs such as a Stripe connect account. # Update tag dimension Source: https://docs.layerfi.com/api-reference/v1/update-tag-dimension patch /v1/businesses/{businessId}/tags/dimensions/{dimensionId} Updates a specific tag dimension. All fields are optional. # Update tag dimension by key Source: https://docs.layerfi.com/api-reference/v1/update-tag-dimension-by-key patch /v1/businesses/{businessId}/tags/dimensions/key/{dimensionKey} Updates a specific tag dimension by its key string. All fields are optional. # Update tag value Source: https://docs.layerfi.com/api-reference/v1/update-tag-value patch /v1/businesses/{businessId}/tags/dimensions/{dimensionId}/values/{valueId} Updates an existing tag value definition, including archiving/unarchiving functionality. # Update transaction metadata Source: https://docs.layerfi.com/api-reference/v1/update-transaction-metadata put /v1/businesses/{businessId}/bank-transactions/{transactionId}/metadata Replaces the metadata associated with the provided bank transaction id. Include customer_id and vendor_id to set or keep those associations. Omit either field, or send null, to clear it. # Update trip Source: https://docs.layerfi.com/api-reference/v1/update-trip patch /v1/businesses/{businessId}/mileage/trips/{tripId} Partially updates a trip. Only provided fields will be updated. If `google_start_place_id` or `google_end_place_id` change and no `distance` is provided, the driving distance is recomputed automatically and `distance_source` becomes `COMPUTED`. Providing an explicit `distance` always takes precedence and sets `distance_source` to `MANUAL`. Changing the place IDs to an incomplete pair without providing a distance returns a 400. # Update vehicle Source: https://docs.layerfi.com/api-reference/v1/update-vehicle patch /v1/businesses/{businessId}/mileage/vehicles/{vehicleId} Partially updates a vehicle. Only provided fields will be updated. # Update vendor Source: https://docs.layerfi.com/api-reference/v1/update-vendor put /v1/businesses/{businessId}/vendors/{vendorId} Replaces an existing vendor. # Update vendor credit Source: https://docs.layerfi.com/api-reference/v1/update-vendor-credit patch /v1/businesses/{businessId}/bills/vendor-credits/{vendorCreditId} Updates an existing vendor credit. # Update vendor payout Source: https://docs.layerfi.com/api-reference/v1/update-vendor-payout put /v1/businesses/{businessId}/vendor-payouts/{payoutId} Updates a vendor payout for a business. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Upload transaction document Source: https://docs.layerfi.com/api-reference/v1/upload-transaction-document post /v1/businesses/{businessId}/bank-transactions/{transactionId}/documents Upload a document for a transaction, such as a receipt or invoice. Images (`jpg` & `png`) and PDFs are supported. The document will be associated with the provided transaction id. This functionality is built into Layer's `` embedded component, but can be used directly if needed. This endpoint expects a multipart upload. # Create vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/create-vendor-refund post /v1/businesses/{businessId}/bills/refunds Creates a new vendor refund for a business or updates existing vendor refund. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will update or no-op. # Create vendor refund payment Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/create-vendor-refund-payment post /v1/businesses/{businessId}/bills/refunds/{refundId}/payments Creates a new payment for a vendor refund. This endpoint is idempotent using the `external_id` field as the idempotency key, so subsequent requests with the same `external_id` will no-op. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Delete vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/delete-vendor-refund delete /v1/businesses/{businessId}/bills/refunds/{refundId} Deletes a vendor refund for a business. ## Rate Limiting This endpoint has a custom rate limit policy. **Rate Limit Details:** | Environment | Limit | Refill Period | Initial Size | | - | - | - | - | | Sandbox | 20 requests | 1 second | 40 requests | | Production | 20 requests | 1 second | 40 requests | **Response Headers:** All responses include the following rate limit headers: * **X-RateLimit-Limit**: The rate limit bucket capacity * **X-RateLimit-Remaining**: The number of tokens remaining in the bucket * **X-RateLimit-Reset**: UTC timestamp (in seconds) when the bucket will be refilled For more details on rate limiting, see [Rate Limiting](/api-details/rate-limiting). # Delete vendor refund payment Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/delete-vendor-refund-payment delete /v1/businesses/{businessId}/bills/refunds/{refundId}/payments/{paymentId} Deletes a payment for a vendor refund. # Fetch vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/fetch-vendor-refund get /v1/businesses/{businessId}/bills/refunds/{refundId} Fetches a vendor refund for a business. # Fetch vendor refund payment Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/fetch-vendor-refund-payment get /v1/businesses/{businessId}/bills/refunds/{refundId}/payments/{paymentId} Fetches a specific payment for a vendor refund. # List vendor refund payments Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/list-vendor-refund-payments get /v1/businesses/{businessId}/bills/refunds/payments Fetches a list of vendor refund payments for a business. Results will be paginated, see [Pagination](/api-details/pagination) for details. # List payments for vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/list-vendor-refund-payments-for-refund get /v1/businesses/{businessId}/bills/refunds/{refundId}/payments Fetches a list of payments for a specific vendor refund. # List vendor refunds Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/list-vendor-refunds get /v1/businesses/{businessId}/bills/refunds Fetches a list of vendor refunds for a business. Vendor refunds can be filtered by external ID, status, completion date range, amount range, and vendor. Results will be paginated, see [Pagination](/api-details/pagination) for details. # Patch vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/patch-vendor-refund patch /v1/businesses/{businessId}/bills/refunds/{refundId} Partially updates an existing vendor refund. Only the fields provided will be updated. If allocations or payments are provided, they will fully replace the existing allocations or payments respectively, and ledger entries will be reversed and recreated. # Update vendor refund Source: https://docs.layerfi.com/api-reference/v1/vendor-refunds/update-vendor-refund put /v1/businesses/{businessId}/bills/refunds/{refundId} Fully replaces an existing vendor refund. All allocations and payments will be replaced with the new values provided. This will reverse any existing ledger entries and create new ones based on the updated refund data. # Void bill Source: https://docs.layerfi.com/api-reference/v1/void-bill post /v1/businesses/{businessId}/bills/{billId}/void Voids an existing bill. # Vendor credit object Source: https://docs.layerfi.com/api-reference/vendor-credits/vendor-credit A Vendor Credit represents a transaction that reduces accounts payable to a vendor, typically due to returned goods. Each vendor credit has one or more line items specifying credited expense accounts, and zero or more allocations applying portions of the credit to bills. ### Attributes Unique identifier for the vendor credit. Unique ID of the vendor credit in your system for linking purposes. **Idempotency key**. The [Vendor](/api-reference/vendor/vendor) associated with this credit. Time when the vendor credit was received. Line items included in this vendor credit. See [Vendor Credit Line Item Object](#vendor-credit-line-item-object) for details. Allocations of this vendor credit to bills. See [Vendor Credit Allocation Object](#vendor-credit-allocation-object) for details. Time when the vendor credit was created in Layer. Time when the vendor credit was last updated in Layer. Time when the vendor credit was deleted, if applicable. Tags associated with the vendor credit. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Arbitrary metadata you can include with the vendor credit Any (typically user-visible) identifier you would like to associate with the vendor credit. Can be used to filter when listing vendor credits. ### Vendor Credit Line Item Object A Vendor Credit Line Item represents an individual expense account being credited by the Vendor Credit. Unique identifier for the vendor credit line item. [Ledger account](/api-reference/ledger/chart#ledger-account-object) associated with this line item. This is what you're specifying with the 'expense\_account\_identifier' in the create parameters. Amount for the line item in cents. Description or notes for the line item. Arbitrary metadata you can include with the vendor credit line item Any (typically user-visible) identifier you would like to associate with the vendor credit line item. ### Vendor Credit Allocation Object A Vendor Credit Allocation represents how a portion of a vendor credit is applied to a specific bill. By allocating vendor credits to bills, the amount owed to vendors can be reduced accordingly. Unique identifier for the vendor credit allocation. ID of the vendor credit this allocation belongs to. ID of the bill this allocation is for. Amount of the allocation in cents. ```json Response theme={null} { "data": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "vc001", "vendor": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "abc123", "individual_name": null, "company_name": "Vanguard Commercial Real Estate", "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE", "transaction_tags": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "key": "ExampleTagKey", "value": "ExampleTagValue", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ] }, "received_at": "2023-11-07T05:31:56Z", "line_items": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledger_account": { "id": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "name": "Rent", "stable_name": { "type": "StableName", "stable_name": "RENT" }, "normality": "DEBIT", "account_type": { "value": "EXPENSE", "display_name": "Expense" }, "account_subtype": { "value": "OPERATING_EXPENSES", "display_name": "Operating Expenses" } }, "amount": 123, "memo": null } ], "allocations": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendor_credit_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bill_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 123 } ], "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null, "transaction_tags": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "key": "ExampleTagKey", "value": "ExampleTagValue", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "metadata": null } } ``` # Vendor Payout object Source: https://docs.layerfi.com/api-reference/vendor-payouts/vendor-payout A Vendor Payout represents a transfer of funds from a Business to vendors through a payment processor or platform. Vendor payouts typically include the total amount of bill payments made to vendors, minus any vendor refunds received, and are the AP equivalent of [Customer Payouts]("api-reference/customer-payouts/payout"). ### Attributes Unique identifier for the vendor payout. Unique ID of the vendor payout in your system for linking purposes and idempotency. ID of the Business that made the vendor payout. The amount of the vendor payout, in cents. This amount can be negative if vendor refunds exceed bill payments. Processor used to make the payment. Any processor name can be provided and will be tracked. If not null, every bill payment or vendor refund payment associated with the vendor payout must have the same processor. Timestamp of when the vendor payout was imported into Layer. Timestamp of when the vendor payout was completed. The transaction match associated with the vendor payout, if any. A list of [Bill Payments](/api-reference/bill/payments) associated with the vendor payout. Note: Unlike customer payouts, you must reference existing bill payments - new bill payments cannot be created as part of vendor payout creation. List of [Vendor Refund Payments](/api-reference/vendor-refunds/vendor-refund#vendor-refund-payment-object) associated with this vendor payout. Note: You must reference existing vendor refund payments, not vendor refunds themselves. A list of other transactions associated with the vendor payout for adjustments or fees. Unique identifier for the transaction Amount of the transaction, in cents (must be positive) Direction of the transaction (MONEY\_IN or MONEY\_OUT) Account identifier for the transaction Description of the transaction External ID of the transaction in your system List of suggested bank transaction matches for the vendor payout. Tags associated with the vendor payout. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the vendor payout (for example, to display to end users). Arbitrary metadata you can include with the vendor payout ```json Response theme={null} { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "vendor-payout-1234", "business_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paid_out_amount": 15000, "processor": "STRIPE", "imported_at": "2023-11-07T05:31:56Z", "completed_at": "2023-11-07T05:31:56Z", "match": { "id": "6b0a3734-f4ef-4fb0-9fc1-3f59b0c1cf99", "match_type": "VENDOR_PAYOUT", "bank_transaction": { "type": "Bank_Transaction_Data", "id": "a703c8d6-cfe8-453d-a275-b92eacc6fc6e", "business_id": "738ec216-e8e5-48f2-b7f2-cdc89c96b3d4", "source": "PLAID", "source_transaction_id": "trxn_1sdOeLQiFAKE2LQBkcvrJw95f", "source_account_id": "738ec216-e154-48f2-1111-cdc89c96b3d4", "imported_at": "2024-03-19T22:09:53.290591Z", "date": "2024-03-06T06:06:40Z", "direction": "DEBIT", "amount": 15000, "counterparty_name": "Stripe", "description": "Stripe Payment", "account_name": "Layer Banking", "categorization_status": "MATCHED" }, "details": { "type": "Vendor_Payout_Match", "id": "d224508b-b05e-41da-89de-0fbd8a573507", "amount": 15000, "date": "2024-03-06T00:00:00Z", "description": "Vendor payout via STRIPE", "adjustment": null } }, "suggested_matches": [ { "id": "f81ca739-7931-475e-b88f-c2b324523f3a", "matchType": "VENDOR_PAYOUT", "details": { "type": "Vendor_Payout_Match", "id": "d224508b-b05e-41da-89de-0fbd8a573507", "amount": 15000, "date": "2024-03-06T00:00:00Z", "description": "Vendor payout via STRIPE", "adjustment": null } } ], "payments": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "bill-payment-1", "business_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendor_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paid_to_vendor_amount": 10000, "platform_fee": 50, "processor": "STRIPE", "paid_at": "2023-11-07T05:31:56Z", "imported_at": "2023-11-07T05:31:56Z", "allocations": [ { "bill_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "payment_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 10000, "transaction_tags": [] } ], "transaction_tags": [] }, { "id": "4d91d4dd-1e55-5c61-9999-9ee36847163b", "external_id": "bill-payment-2", "business_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendor_id": "4d91d4dd-1e55-5c61-9999-9ee36847163b", "paid_to_vendor_amount": 5000, "platform_fee": 25, "processor": "STRIPE", "paid_at": "2023-11-07T05:31:56Z", "imported_at": "2023-11-07T05:31:56Z", "allocations": [ { "bill_id": "4d91d4dd-1e55-5c61-9999-9ee36847163b", "payment_id": "4d91d4dd-1e55-5c61-9999-9ee36847163b", "amount": 5000, "transaction_tags": [] } ], "transaction_tags": [] } ], "refunds": [], "other_transactions": [], "transaction_tags": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "key": "Department", "value": "Operations", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": "Weekly vendor payments batch", "metadata": { "batch_id": "batch-789", "approval_code": "MGR-456" } } ``` # Vendor Refund object Source: https://docs.layerfi.com/api-reference/vendor-refunds/vendor-refund A Vendor Refund represents a transaction where a vendor returns value to a business. They are the counterpart to [Customer Refunds](/api-reference/refunds/refund). Each vendor refund has one or more Vendor Refund Allocations (targets) and zero or more Vendor Refund Payments. ## Creating Vendor Refunds There are two ways to create vendor refunds: ### Simple Vendor Refunds Use simple vendor refunds when you want to fully refund a single target (bill, bill line item, or bill payment) and the refund is fully paid. Layer automatically: * Calculates the refund amount based on what can be refunded from the target * Creates one allocation that perfectly cancels out the target * Creates one refund payment that pays the refund in full ### Itemized Vendor Refunds Use itemized vendor refunds for more complex scenarios including: * Refunding multiple targets in a single refund * Partial refunds that don't fully cancel out the target * Unpaid refunds (refunds owed but not yet received) * Custom allocation amounts or payment structures With itemized vendor refunds, you specify all allocations and payments explicitly. ## Vendor Refund Object ### Attributes Unique identifier for the vendor refund. Unique ID of the vendor refund in your system for linking purposes. **Idempotency key**. Amount refunded to the business in cents. Status of the vendor refund. Time when the vendor refund was completed. Allocations associated with this vendor refund. See [Vendor Refund Allocation Object](#vendor-refund-allocation-object) for details. Payments associated with this vendor refund. See [Vendor Refund Payment Object](#vendor-refund-payment-object) for details. Tags associated with the vendor refund. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the vendor refund. Arbitrary metadata you can include with the vendor refund. ## Vendor Refund Allocation Object A Vendor Refund Allocation represents one of the targets of a vendor refund. It can reference a specific bill, bill line item, bill payment, or vendor. For example, a vendor refund can apply to two separate bills if the bills are from the same vendor. The total of the amounts of the vendor refund allocations must add up to the refund amount. Unique identifier for the vendor refund allocation. ID of the bill this allocation is associated with. Amount of the allocation in cents. Line items that make up this allocation. See [Vendor Refund Allocation Line Item Object](#vendor-refund-allocation-line-item-object) for details. External ID of the bill this allocation is associated with. ID of the bill line item this allocation is associated with. If specified, must not refer to a different bill than `bill_id` or `bill_external_id`. The external ID of the bill line item to refund. If specified alongside `bill_line_item_id`, they must refer to the same bill line item. ID of the bill payment this allocation is associated with. External ID of the bill payment this allocation is associated with. The [Vendor](/api-reference/vendor/vendor) associated with this vendor refund allocation. Tags associated with the vendor refund allocation. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the vendor refund allocation. Arbitrary metadata you can include with the vendor refund allocation. ## Vendor Refund Allocation Line Item Object A Vendor Refund Allocation Line Item represents a specific line within a vendor refund allocation, allowing for detailed breakdowns of how the allocation amount is distributed across different ledger accounts. External identifier for the line item. Amount of the line item in cents. The ledger account associated with this line item. The prepayment account associated with this line item, if applicable. Tags associated with the line item. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the line item. Arbitrary metadata you can include with the line item. ## Vendor Refund Payment Object A Vendor Refund Payment represents a money movement by which the vendor refund was received by the business. A vendor refund with zero payments represents a refund that is owed to the business but has not yet been received. A vendor refund can have many payments so long as the total of their `refunded_amount`s does not exceed the total amount of the refund. Vendor refund payments are matchable to bank transactions and are therefore the means by which vendor refunds are reconciled with bank accounts. Unique identifier for the payment. Unique ID of the payment in your system for linking purposes. **Idempotency key**. Amount refunded to the business in cents. Fee paid by the business to receive the refund payment (typically a payment processing fee). Time when the payment was completed. Method of the payment (e.g., `CREDIT_CARD`, `ACH`, etc.). Processor used for the payment (e.g., `STRIPE`, `SHOPIFY`, etc.). Tags associated with the vendor refund payment. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted Memo for any text you would like to associate with the vendor refund payment. Arbitrary metadata you can include with the vendor refund payment. ## Simple Vendor Refund Creation Parameters Use these parameters to create a simple vendor refund that fully refunds a single target and is fully paid. Unique ID of the vendor refund in your system for linking purposes. **Idempotency key**. When the vendor refund was completed and paid. The ID of the bill to refund. Cannot be used with other target identifiers. The external ID of the bill to refund. Cannot be used with other target identifiers. The ID of the bill line item to refund. Cannot be used with other target identifiers. The external ID of the bill line item to refund. Cannot be used with other target identifiers. The ID of the bill payment to refund. Cannot be used with other target identifiers. The external ID of the bill payment to refund. Cannot be used with other target identifiers. Fee charged to the business for processing the refund in cents. Defaults to 0. Method of the payment (e.g., `CREDIT_CARD`, `ACH`, etc.). Processor used for the payment (e.g., `STRIPE`, `SHOPIFY`, etc.). Tags to apply to the vendor refund. Tags are key-value pairs that can be used to categorize and filter vendor refunds. The tag dimension key (e.g., "department", "project", "location") Optional display name for the tag dimension. If the dimension doesn't exist, this will be used as its display name. The tag value (e.g., "engineering", "project-alpha", "san-francisco") Optional display name for the tag value. If the value doesn't exist, this will be used as its display name. Memo for any text you would like to associate with the vendor refund. Arbitrary metadata you can include with the vendor refund. ## Itemized Vendor Refund Creation Parameters Use these parameters to create an itemized vendor refund with full control over allocations and payments. Unique ID of the vendor refund in your system for linking purposes. **Idempotency key**. The total amount of the vendor refund in cents. Must equal the sum of all allocation amounts. When the vendor refund was completed. The targets of the vendor refund. Each allocation specifies how much of the refund should be applied to a specific bill, line item, payment, or vendor. External identifier for the allocation. Total amount of this allocation in cents. Must equal the sum of all line item amounts. Line items that make up this allocation. ID of the bill this allocation targets. External ID of the bill this allocation targets. ID of the bill line item this allocation targets. External ID of the bill line item this allocation targets. ID of the bill payment this allocation targets. External ID of the bill payment this allocation targets. ID of the vendor this allocation targets. External ID of the vendor this allocation targets. Tags for this allocation. Memo for this allocation. Metadata for this allocation. The payment methods and amounts used to receive the vendor refund. External identifier for the payment. Amount refunded to the business in cents. Fee charged to the business for processing this payment. When this payment was completed. Payment method used. Processor used for this payment. Tags for this payment. Memo for this payment. Metadata for this payment. List of tags associated with this vendor refund. Memo for any text you would like to associate with the vendor refund. Arbitrary metadata you can include with the vendor refund. ```json Response theme={null} { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "vendor-refund-123", "refunded_amount": 500, "status": "PAID", "completed_at": "2023-11-07T05:31:56Z", "allocations": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bill_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 500, "line_items": [ { "external_id": "line-item-1", "amount": 500, "ledger_account": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "Office Supplies", "account_number": "6200" }, "prepayment_account": null, "transaction_tags": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "department", "value": "sales", "dimension_display_name": "Department", "value_display_name": "Sales Team", "dimension_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890", "definition_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "created_at": "2024-02-27T02:16:40.389772Z", "updated_at": "2024-02-27T02:16:40.389772Z", "deleted_at": null, "archived_at": null } ], "memo": null, "metadata": null } ], "bill_external_id": "bill-456", "bill_line_item_id": null, "bill_line_item_external_id": null, "bill_payment_id": null, "bill_payment_external_id": null, "vendor": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "vendor-789", "individual_name": null, "company_name": "Office Supply Co", "email": "accounts@officesupply.com", "mobile_phone": null, "office_phone": "555-123-4567", "address_string": "456 Supply St, Business City, NY 10001", "notes": "Regular office supply vendor", "status": "ACTIVE", "transaction_tags": [] }, "transaction_tags": [ { "key": "RefundReason", "value": "DefectiveItems", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": "Refund for defective office supplies", "metadata": null } ], "payments": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "payment-321", "refunded_amount": 500, "refund_processing_fee": 5, "completed_at": "2023-11-07T05:31:56Z", "method": "ACH", "processor": "STRIPE", "transaction_tags": [ { "key": "ProcessorReference", "value": "ach_1234567890", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": null, "metadata": null } ], "transaction_tags": [ { "key": "Department", "value": "Procurement", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ], "memo": "Monthly office supply refund", "metadata": null } ``` # Vendor object Source: https://docs.layerfi.com/api-reference/vendor/vendor A Vendor of a business can send bills and have payments applied to their bills. Vendors can be referenced when creating bills using either the Layer `id`, or the `external id`. ### Attributes Unique identifier for the vendor. Unique ID of the vendor in your system for linking and idempotency. Full name of the individual vendor or contact at a corporate vendor. Name of the company vendor. Email address of the vendor. Mobile phone number of the vendor. Office phone number of the vendor. Full address of the vendor. Status of the vendor. Possible values are: `ACTIVE`, `ARCHIVED` Archived vendors will not appear when listing vendors, but their accounting continues to be tracked and they can still be retrieved directly in the API. Unique identifier for the tag The tag's key The tag's value Display name for the tag dimension Display name for the tag value ID of the tag dimension ID of the tag value definition When the tag was created When the tag was last updated When the tag was deleted When the tag was archived Memo for any text you would like to associate with the vendor (for example, to display to end users). Arbitrary custom metadata in JSON format with a size limit of 1KB. Any (typically user-visible) identifier you would like to associate with the vendor. Can be used to filter when listing vendors. ```json Response theme={null} { "data": { "type": "VendorData", "id": "4f7c1b16-e057-4ec0-8b20-50308ba5b9ea", "external_id": "vendor-1", "individual_name": "John Doe", "company_name": "Acme, Inc.", "email": "john@hotmail.com", "mobile_phone": "555-555-5555", "office_phone": "555-555-5555", "address_string": "123 Main St, Phoenix, AZ 85001", "notes": "This is a note", "status": "ACTIVE", "transaction_tags": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "key": "ExampleTagKey", "value": "ExampleTagValue", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": "2023-11-07T05:31:56Z" } ] } } ``` # Write-off object Source: https://docs.layerfi.com/api-reference/write-offs/write-off A Write-off represents an amount of an invoice that a business has decided to forgive or cancel. Write-offs are used to adjust the outstanding balance of an invoice when the business does not expect to collect the full amount. ### Attributes Unique identifier for the write-off. Unique identifier for the invoice the write-off is applied to. Unique ID of the write-off in your system for linking and idempotency. The amount written off in cents. This amount counts towards the invoice total and decreases the outstanding balance of the invoice. If not specified when creating a write-off, it defaults to the entire outstanding balance of the invoice. The amount must be a positive value and cannot exceed the current outstanding balance of the invoice. User-specified memo indicating the reason for the write-off. Expense or contra-revenue account where write-off amount is recorded. Defaults to the bad debt expense account if not specified when creating a write-off. If the write-off is for a different reason, such as a charitable donation, a different ledger expense account can be specified. Timestamp when the write-off should be recognized in the general ledger. This may be the same time as the invoice was created if it is an intentional charitable contribution or it could be months after the invoice is issued when that invoice is deemed uncollectible. Tags associated with the write-off. The tag's key The tag's value When the tag was created When the tag was last updated When the tag was deleted ```json Response theme={null} { "data": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "external_id": "write-off-123", "amount": 123, "memo": "Customer unable to pay due to bankruptcy", "destination_ledger_account": { "type": "AccountId", "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "write_off_at": "2023-11-07T05:31:56Z", "transaction_tags": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "key": "WriteOffReason", "value": "Bankruptcy", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null }, { "id": "4d01d4dd-1e55-5c61-9999-9ee36847163b", "key": "Department", "value": "Finance", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "deleted_at": null } ] } } ``` # Detecting errors Source: https://docs.layerfi.com/embedded-components/callbacks Layer's React components expose error callbacks to notify you of errors that occur within the embedded components. Use the `onError` property on `` to get notified about all exceptions within the components: ```ts theme={null} console.log('My error callback', err)} > {...} ``` This can be done both on the top level `` component and within specific components. ```ts theme={null} console.log('My callback:', e)} /> ``` # Balance Sheet Source: https://docs.layerfi.com/embedded-components/components/balance-sheet The Balance Sheet report. ![Balance Sheet](https://github.com/Layer-Fi/layer-react/assets/1592431/c35a6110-38e3-4845-b725-b1ca4913b831) ```tsx theme={null} import { BalanceSheet } from "@layerfi/components"; … ``` ### Properties Date to open the report at. # Bank Transactions Source: https://docs.layerfi.com/embedded-components/components/bank-transactions Bank account and credit card transactions ingested into Layer. The transaction categorization component displays a list of transactions that have been imported into Layer. By default, the component has two tabs: * **To Review** - Transactions that need to be reviewed/categorized before they will be journaled to the general ledger. * **Categorized** - Transactions that have already been categorized and journaled to the general ledger. Bank Transactions Optional properties and `useBankTransactionsContext` give more control over the transactions list: ```tsx theme={null} /** Using props */ console.error('Transaction error:', error)} /> /** Using hook */ const { setFilters } = useBankTransactionsContext() setFilters({ amount: { min: 0, max: 10000 } }) ``` ### Properties Number of transactions to display per page. Controls pagination size. Controls whether transaction descriptions are displayed in the transaction list. Controls whether receipt upload functionality is available for transactions. Controls whether tooltips are displayed to provide additional information about transactions and categorization. Controls whether the customer/vendor column is displayed in the transactions table. Controls whether transaction tags are displayed and can be managed in the transaction list. A tag picker appears for each user-visible tag dimension that has at least one defined value. Users choose from the values you define through the API; they cannot add a new value. See [Create tag dimension](/api-reference/v1/create-tag-dimension) and [Create tag value](/api-reference/v1/create-tag-value). Tag changes save as the user makes them. Controls whether upload options are displayed for transactions. Controls whether the "To Review" / "Categorized" status toggle is displayed. Controls whether categorization rule suggestions are shown when categorizing transactions. Hides the component header entirely. Collapses the component header into a more compact form. Enables monthly view mode which changes the date filtering behavior to focus on monthly periods. Controls whether the categorization interface is displayed. If not specified, this is automatically determined based on the business's bookkeeping configuration. Indicates whether to use dedicated mobile-oriented layout for smaller screens. Possible values are `mobileList` or `regularList`. Defaults to `regularList`. Callback function that is called when an error occurs in the component. Receives a LayerError object as a parameter. Custom function for rendering in-app navigation links. Receives LinkingMetadata as a parameter and should return a ReactNode. Overrides for default strings in the component. Component header text. Defaults to "Bank Transactions" Overrides for button CTAs in the component. Override the "Approve" button text which saves transaction categorization. Defaults to "Approve". Override for the "Update" button text which updates a transaction categorization. Defaults to "Update". Overrides for the transactions table. Override for the "Date" column header text. Defaults to "Date". Override for the "Transaction" column header text. Defaults to "Transaction". Override for the "Account" column header text representing the name of the source bank account. Defaults to "Account". Override for the "Amount" column header text. Defaults to "Amount". Override for the "Categorize" column header text. Shows only for uncategorized transactions. Defaults to "Categorize". Override for the "Category" column header text. Shows only for categorized transactions. Defaults to "Category". Filters to apply to the transaction list. Range of amounts to filter the transaction list to. Minimum value of transactions to list. Maximum value of transactions to list. Array of Financial Account IDs to filter to. Allows filtering by multiple accounts. Direction of transactions to filter to. Possible values are `CREDIT` or `DEBIT`. Show only unreviewed or categorized transactions. Possible values are `TO_REVIEW` or `CATEGORIZED`. Date range to filter transactions to. Start date to filter transactions to. End date to filter transactions to. Search query to filter transactions by description, counterparty name, or other transaction details. Filter transactions by tags. Allows filtering by specific tag criteria. Indicates whether to apply the global date range filter to the transaction list. If set to true, changing the date range in any Layer component will filter the transaction list to that time range as well. Defaults to `false`. ## Variations * [Bank Transactions with Linked Accounts](/embedded-components/pages/bank-transactions-with-linked-accounts) # Cash Flow Statement Source: https://docs.layerfi.com/embedded-components/components/cash-flow-statement The Cash Flow Statement report. The statement of cashflows component is an interactive table displaying cash changes broken out into investing, financing, and operational activities. It is shown calculated via the standard indirect method. ![Statement of Cash Flows](https://github.com/Layer-Fi/layer-react/assets/1592431/39d92340-405b-46e4-873d-175b6c75f96b) ```tsx theme={null} import { CashFlowStatement } from "@layerfi/components"; … ``` ### Properties Controls the granularity of date selection for the cash flow statement. * `'full'` - Full date range picker * `'month'` - Month picker only Format for monetary values in CSV exports. `'CENTS'` formats as an integer of cents. `'DOLLAR_STRING'` formats as a dollar string. Override for the "Type" column header. Defaults to "Type". Override for the "Total" column header. Defaults to "Total". # Chart of Accounts Source: https://docs.layerfi.com/embedded-components/components/chart-of-accounts List of all accounts within the general ledger. Chart of Accounts The chart of accounts gives direct read and write access into the double entry general ledger underlying Layer's data. It exposes the list of accounts and enables users to create new accounts. ```tsx theme={null} ``` ### Properties Displays a more compact version. Includes a date picker which determines the effective date of account balances displayed. Displays a button to expand and collapse all sub account lists. Overrides for default strings in the component. Overrides for the ledger account component. Overrides for the ledger entry detail component. Override for the title. Defaults to "Ledger Entry Detail". Overrides for the transaction source component. Override for the header. Defaults to "Transaction Source". Override for the "Date" label. Defaults to "Date". Override for the "Amount" label. Defaults to "Amount". Override for the "Direction" label. Defaults to "Direction". Override for the "Counterparty" label. Defaults to "Counterparty". Override for the "Entity Name" label. Defaults to "Entity Name". Override for the "Display Description" label. Defaults to "Display Description". Overrides for the journal entry component. Override for the header. Defaults to "Journal Entry". Override for the "Date" label. Defaults to "Date". Override for the "Creation Date" label. Defaults to "Creation Date". Override for the "Reversal" label. Defaults to "Reversal". Overrides for the line items table. Override for the "Line Items" column header. Defaults to "Line Items". Override for the "Debit" column header. Defaults to "Debit". Override for the "Credit" column header. Defaults to "Credit". Override for the "Total" row header. Defaults to "Total". Overrides for the chart of accounts table. Override for the table header text. Defaults to "Chart of Accounts". Override for the "Add Account" button text. Defaults to "Add Account". Override for the "Download CSV" button text. Defaults to "Download CSV". Override for the "Name" column header text. Defaults to "Name". Override for the "Type" column header text. Defaults to "Type". Override for the "Balance" column header text. Defaults to "Balance". Override for the "Subtype" column header text. Defaults to "Subtype". Overrides for the chart of accounts form. Override for the form header text when editing an account. Defaults to "Edit Account". Override for the form header text when creating a new account. Defaults to "Create Account". Override for the "Cancel" button text. Defaults to "Cancel". Override for the "Retry" button text. Defaults to "Retry". Override for the "Save" button text. Defaults to "Save". Override for the "Parent" label text. Defaults to "Parent". Override for the "Name" label text. Defaults to "Name". Override for the "Type" label text. Defaults to "Type". Override for the "Subtype" label text. Defaults to "Subtype". Override for the "Normality" label text. Defaults to "Normality". Controls visibility of the add account button. Controls whether template accounts can be edited. We recommend this only be true for advanced users. Controls visibility of reversal entries. # Global Date Range Selection Source: https://docs.layerfi.com/embedded-components/components/global-date-range-selection Global date range selection control with period presets and custom start/end dates. The GlobalDateRangeSelection component allows users to select a date range that is shared across the application. When the selected date range changes, any component that relies on the global date range updates automatically. Global Date Range Selection ```tsx theme={null} import { GlobalDateRangeSelection } from '@layerfi/components' {/* With labels visible */} ``` ### Properties Controls whether labels are shown for the report period picker and start/end date fields. # Global Month Picker Source: https://docs.layerfi.com/embedded-components/components/global-month-picker Month picker that controls the global date range. The GlobalMonthPicker component provides a month selection control that is connected to the global date store. When the user selects a month, all components that use the global date range will update accordingly. This is useful for adding a standalone month picker to custom layouts while keeping all data-driven components in sync. Global Month Picker ```tsx theme={null} import { GlobalMonthPicker } from '@layerfi/components' {/* With label visible */} {/* With truncated month name */} ``` ### Properties When `true`, truncates the month name display (e.g., "Jan" instead of "January"). When `true`, displays the "Month" label above the picker. # Invoices Source: https://docs.layerfi.com/embedded-components/components/invoices Invoice management with creation, editing, payment tracking, and status management. The Invoices component handles the invoice lifecycle from creation to payment. It includes summary statistics, invoice listing, forms for editing, and payment management. Invoices Overview The component switches between an overview mode showing all invoices and a detail mode for creating or editing individual invoices. Invoices Detail ```tsx theme={null} ``` ## Features * **Invoice Overview**: Summary statistics for paid amounts, outstanding balances, and overdue invoices * **Invoice Table**: Paginated table with search, status filtering, and sortable columns * **Invoice Detail View**: Invoice creation and editing form with line items, customer selection, and payment terms * **Payment Management**: Record payments, refunds, and view payment history * **Status Management**: Void, write-off, reset, and send invoices * **Form Validation**: Inline validation with error messages * **Customer Integration**: Customer selection and creation within the invoice form * **Tax Calculations**: Configurable tax rates applied per line item * **Payment Terms**: Predefined terms (Net 10, 15, 30, 60, 90) or custom due dates * **Line Item Management**: Add, edit, and remove line items with quantity and unit pricing * **Status Tracking**: Status indicators for Draft, Sent, Paid, Overdue, Void, and Written-off states * **Search and Filtering**: Filter invoices by customer, amount, or status ## Usage Examples **Basic usage:** ```tsx theme={null} ``` **With custom title:** ```tsx theme={null} ``` **With send invoice callback:** ```tsx theme={null} { // Custom logic for sending invoice (e.g., email integration) await sendInvoiceEmail(invoiceId); }} /> ``` **Without title header:** ```tsx theme={null} ``` ## Properties Whether to display the page title header. When set to false, the component renders without the top-level title. Overrides for default strings in the component. Override for the main component title. Defaults to "Invoices". Callback function triggered when an invoice is sent. Receives the invoice ID as a parameter and can return a Promise for async operations like email integration. **Function signature:** `(invoiceId: string) => Promise | void` ### Invoice Overview The default **view** displays: * **Summary Statistics**: Paid amounts (last 30 days), outstanding invoices, and overdue amounts * **Invoice Table**: Columns for invoice number, customer, amount, status, and due date * **Search and Filtering**: Search by customer name or invoice details, filter by status * **Create Invoice Button**: Opens the invoice creation form ### Invoice Detail View Form for creating and editing invoices: * **Customer Selection**: Customer picker with search and inline creation * **Invoice Metadata**: Invoice number, sent date, due date, and payment terms * **Line Items**: Table for adding/editing line items with description, quantity, unit price, and tax * **Tax Calculations**: Subtotals, taxes, discounts, and totals calculated automatically * **Payment Terms**: Predefined options (Net 10, 15, 30, 60, 90) or custom date * **Status Actions**: Send, Void, Write-off, Refund, and Reset actions based on current status ### Payment Management * **Payment Recording**: Record payments with amount, date, and payment method * **Payment History**: List of payments and refunds for the invoice * **Outstanding Balance**: Calculated remaining balance * **Refund Processing**: Process partial or full refunds ### Status States * **Draft**: Invoice being created or edited * **Sent**: Invoice sent to customer, awaiting payment * **Paid**: Invoice fully paid * **Overdue**: Sent invoice past due date * **Void**: Cancelled invoice * **Written-off**: Invoice marked as uncollectible # Journal Source: https://docs.layerfi.com/embedded-components/components/journal All journal entries in the general ledger. The Journal component displays the full history of journal entries and allows users to create journal entries by hand as well. Journal A sidebar expands to display details about the journal entry. Journal sidebar ```tsx theme={null} ``` ### Properties Controls whether tags are displayed when creating journal entries. Controls whether the customer/vendor selector is displayed when creating journal entries. Custom function for rendering in-app navigation links. See the [In-App Linking](/embedded-components/linking) guide for details. Overrides for default strings in the component. Overrides for the journal table. Override for the journal table title. Defaults to `"Journal"`. Override for the journal table subtitle. Defaults to `"Entries"`. Override for the add entry button text. Defaults to `"Add Entry"`. Override for the ID column header. Defaults to `"Id"`. Override for the date column header. Defaults to `"Date"`. Override for the transaction column header. Defaults to `"Transaction"`. Override for the account number column header. Defaults to `"Account Number"`. Override for the account column header. Defaults to `"Account Name"`. Override for the debit column header. Defaults to `"Debit"`. Override for the credit column header. Defaults to `"Credit"`. # Landing Page Source: https://docs.layerfi.com/embedded-components/components/landing-page Landing page showcasing Layer accounting and bookkeeping services. The LandingPage component provides a page-level component that surfaces the Layer accounting and bookkeeping services. It acts as a landing page allowing platforms to showcase the core value proposition and offers/pricing for the platform's end users. It supports Calendly integration for booking calls. Landing Page ```tsx theme={null} import { LandingPage } from '@layerfi/components' ``` ### Properties Platform configuration with branding details. The platform/brand name displayed throughout the component (e.g., "Acme, Inc."). Used in titles, descriptions, and feature text. The target industry for customization (e.g., "e-commerce", "SaaS", "retail"). Used to tailor feature descriptions and messaging. If industry name substitution does not work well, overwrite the value propositions directly. Array specifying which service offerings to display. Can include `'accounting'`, `'bookkeeping'`, or both. Partial overrides for the hero/main content section. All fields are optional and will fall back to defaults. Text overrides for the hero section. Main hero title. Supports `{{platformName}}` and `{{industry}}` template variables. Subtitle text below the title. Supports template variables. First feature heading. Supports template variables. Description for the first feature heading. Second feature heading. Supports template variables. Description for the second feature heading. URL of the hero image displayed next to the main content. Call-to-action button configuration. Primary CTA button. If the URL is a Calendly link, opens a Calendly modal. Otherwise, opens a new tab. Button text label. Destination URL. Secondary "Learn More" button. If not provided, the learn more button is not rendered. Partial overrides for the service offering cards. Title text for the offerings section. Overrides for the accounting service card. Small label/tag on the card (e.g., "Most Popular"). Card heading (e.g., "Self-Service Accounting"). Card description text. Price display (e.g., "\$29"). Billing frequency (e.g., "/month"). URL of the card image. CTA button with label and URL. Calendly URLs open a modal. Whether to show "Starting at" label above the price. Overrides for the bookkeeping service card. Same shape as `accounting`. # Link Accounts (Onboarding) Source: https://docs.layerfi.com/embedded-components/components/link-accounts Onboarding component which walks users through connecting business accounts. The Link Accounts component is intended to be used during onboarding into an accounting experience, regardless of whether the business is additionally enrolling in bookkeeping services or not. It will prompt users to connect all their business accounts in sequence and prompt them to confirm whether any accounts are personal and should be excluded. ```tsx theme={null} navigate('../overview')} /> ``` *** Users will be first prompted to connect their bank. Link Accounts starting state *** After connecting accounts, the component will show cards for each transaction as well as loading progress. Onboarding after linking *** Users will be prompted to confirm which accounts are used by their business. Confirming business accounts ### Properties A function to navigate to the next screen in the onboarding flow. Configuration for using Plaid Hosted Link instead of the embedded Plaid modal. When provided, account linking opens a Plaid-owned page in the browser rather than displaying an embedded modal. Set to `true` when the user will open the hosted link in an `ASWebAuthenticationSession` (iOS) or Android Custom Tab. This tells Plaid to use the correct redirect handling for mobile contexts. Universal Link (iOS) or App Link (Android) that opens your app. Used when Plaid redirects from a third-party OAuth app (e.g., a bank's app) back to your app during app-to-app authentication. URI to redirect to after the user completes the Plaid hosted link flow (e.g., `myapp://plaid-complete`). Recommended for mobile apps to automatically close the hosted link session and return to your app. If not provided, the user sees a "Return to app" message and must navigate back manually. Callback function that navigates the user to the Plaid Hosted Link URL. This function receives the Plaid-owned URL and should open it in the device's browser or an in-app browser. Required for all hosted link configurations. # Linked Accounts Source: https://docs.layerfi.com/embedded-components/components/linked-accounts Bank accounts and credit cards connected to Layer. Displays all accounts connected to Layer including embedded banking, Plaid, and custom accounts. Linked Accounts *** If a bank connection breaks (for example, the customer changed their online banking password), the affected account shows a **Fix account** flag. Disconnected linked account The customer clicks **Fix account**, then **Repair connection** to reconnect their bank. This opens the same Plaid flow used to link an account, so the customer never leaves your product. ```tsx theme={null} ``` ### Properties Stylistic option to highlight the component. Flag to enable or hide the current ledger balance corresponding to this external account. Useful for bank reconciliation workflows. Configuration for using Plaid Hosted Link instead of the embedded Plaid modal. When provided, account linking opens a Plaid-owned page in the browser rather than displaying an embedded modal. Set to `true` when the user will open the hosted link in an `ASWebAuthenticationSession` (iOS) or Android Custom Tab. This tells Plaid to use the correct redirect handling for mobile contexts. Universal Link (iOS) or App Link (Android) that opens your app. Used when Plaid redirects from a third-party OAuth app (e.g., a bank's app) back to your app during app-to-app authentication. URI to redirect to after the user completes the Plaid hosted link flow (e.g., `myapp://plaid-complete`). Recommended for mobile apps to automatically close the hosted link session and return to your app. If not provided, the user sees a "Return to app" message and must navigate back manually. Callback function that navigates the user to the Plaid Hosted Link URL. This function receives the Plaid-owned URL and should open it in the device's browser or an in-app browser. Required for all hosted link configurations. # P&L Breakdown Charts Source: https://docs.layerfi.com/embedded-components/components/pnl-breakdown-charts Itemized breakdown of revenue and expenses. Ths P\&L Detail chart allows exploring the drivers of costs and revenue within a specific month. ```tsx theme={null} import { ProfitAndLoss } from "@layerfi/components"; … ``` ### `ProfitAndLoss.DetailedCharts` Properties Options are `revenue` or `expenses`. If true, shows a dedicated date picker for this component. If not, inherits the current P\&L context date range. Optional styling overrides for the chart. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the revenue chart. Categories are assigned colors in alphabetical order by name; if the list is shorter than the number of categories, colors repeat with reduced opacity. Only applies when `scope` is `revenue`. Same as `revenue`, but only applies when `scope` is `expenses`. Color for the uncategorized slice and its legend swatch. Omit to keep the default dot-pattern donut fill and neutral swatch color. Inner radius of the donut chart. Outer radius of the donut chart. Legacy way to override the colors of the pie chart. Categories are assigned colors in alphabetical order by name. If the list of colors is shorter than the number of categories, the colors will repeat with shifted opacity. Prefer `chartConfig.colors`, which also lets you set a scope-specific palette and an uncategorized color. # Summary Cards Source: https://docs.layerfi.com/embedded-components/components/pnl-cards Summarized Profit & Loss or cash flow metrics. ```tsx theme={null} import { ProfitAndLoss } from "@layerfi/components"; … ``` ### Properties Callback triggered when the user clicks the transactions-to-review CTA on the summary cards. Use this to navigate to the page in your app where users categorize their bank transactions. Optional styling overrides for the mini donut charts and swatch colors on the cards. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the revenue card's mini chart and swatch. Cycles with reduced opacity once exhausted. Ordered palette for the expenses card's mini chart and swatch. Cycles with reduced opacity once exhausted. Color for the uncategorized portion of each card's mini chart and swatch. Omit to keep the default neutral color. Legacy way to override the palette shared by the revenue and expenses cards. Prefer `chartConfig.colors`, which lets you set separate palettes per card and an uncategorized color. Controls which reporting mode the summary cards display. Defaults to profit and loss. With `'profitAndLoss'` (the default), the cards show revenue, expenses, and net profit. With `'cashflow'`, the cards show money in, money out, and net cash flow. Only applies when `type` is `'cashflow'`. Controls whether the money in and money out cards include a categorized vs. uncategorized breakdown footer. Overrides for default strings in the component. Changes the label for revenue in the cards. Can pass in values such as "income" or another term. Defaults to "Revenue". Changes the label for expenses in the cards. Can pass in values such as "costs" or another term. Defaults to "Expenses". Changes the label for net profit in the cards. Can pass in values such as "net income" or another term. Defaults to "Net Profit". Changes the label for money in when using the cashflow reporting variant. Defaults to "Money in". Changes the label for money out when using the cashflow reporting variant. Defaults to "Money out". Changes the label for net cash flow when using the cashflow reporting variant. Defaults to "Net cash flow". # Chart Source: https://docs.layerfi.com/embedded-components/components/pnl-chart Chart of revenue, expenses, and profit for the last 12 months. Profit and Loss chart ```tsx theme={null} import { ProfitAndLoss } from "@layerfi/components"; … ``` ### Properties Optional styling overrides for the chart. Width of the bars, in pixels. Width of the bars when the chart renders in its compact layout (below 620px wide). Defaults to half of `barWidth`. ### CSS variables Colors and line thickness are set with [CSS variables](/embedded-components/styling#css-variables) rather than `chartConfig`, since they apply to a single fixed element rather than a per-category palette. ```css theme={null} body .Layer__component { /* Revenue bars. Also colors the diagonal stripe pattern on the uncategorized portion of the bar. */ --bar-color-income: blue; /* Expense bars. Also colors the diagonal stripe pattern on the uncategorized portion of the bar. */ --bar-color-expenses: red; /* Net profit line color. Defaults to var(--color-base-1000). */ --pnl-chart-line-color: green; /* Net profit line thickness, in pixels. Defaults to 1. */ --pnl-chart-line-stroke-width: 2; } ``` # Report Source: https://docs.layerfi.com/embedded-components/components/pnl-table The full Profit & Loss report. ![Profit And Loss Table](https://github.com/Layer-Fi/layer-react/assets/1592431/8bca34d1-6357-4030-811a-e46fe1f83195) ```tsx theme={null} import { ProfitAndLoss } from "@layerfi/components"; … ``` ### Properties Forces the table to be fully expanded showing all rows. Overrides for default strings in the component. Override for the "Gross Profit" row header text. Defaults to "Gross Profit". Override for the "Profit before taxes" row header text. Deafaults to "Profit before taxes". Override for the "Net Profit" row header text. Defaults to "Net Profit". # Tasks Source: https://docs.layerfi.com/embedded-components/components/tasks Bookkeeping task list for business owners. Tasks component ```tsx theme={null} import { Tasks } from "@layerfi/components"; … navigate('/accounts')} /> ``` ### Properties Enables mobile-optimized layout for the tasks component. Override for the tasks header text. Callback triggered when the user clicks the reconnect-accounts action in the task list. # LayerProvider context Source: https://docs.layerfi.com/embedded-components/layerprovider-context All Layer React components are nested under the `LayerProvider` component. This component takes in the below properties. ```tsx theme={null} import { LayerProvider, SupportedLocale } from "@layerfi/components"; { console.error('Layer error:', error) }} eventCallbacks={{ onEvent: (event) => { console.log('Layer event:', event.type, event.payload) }, onTransactionCategorized: () => { console.log('Transaction categorized') }, }} > {...} ``` ### Properties The ID of the business whose information you're showing. Temporary authentication token scoped to this specific business. See the getting started guide for how to fetch these tokens on your backend. Do not use your Layer API key as the token in production. Retrieve a business-scoped access token from the Layer API and pass that value here instead. The predefined Layer environment to connect to. Defaults to `production`. Use `sandbox` for development and testing. Cannot be used together with `environmentConfigOverride`. Custom configuration to override API and auth endpoints. Use this instead of `environment` when connecting to a non-standard deployment. Cannot be used together with `environment`. Base environment name. Custom API base URL (e.g., `https://custom-api.example.com`). Custom OAuth token endpoint (e.g., `https://custom-auth.example.com/token`). OAuth scope for the token request. Sets the locale for all Layer components. Controls the language used for UI text, date formatting, numerical formatting, and the `Layer-Locale` header sent with API requests. Defaults to `SupportedLocale.enUS`. The `SupportedLocale` enum is exported from `@layerfi/components` and currently includes: * `SupportedLocale.enUS` (`'en-US'`): English (United States) * `SupportedLocale.frCA` (`'fr-CA'`): French (Canada) Customizes the look and feel of the components. See [Styling](/embedded-components/styling) for details. Dark/primary color. Can be specified as HSL (`{ h, s, l }`), RGB (`{ r, g, b }`), or hex (`{ hex }`). Light/accent color. Can be specified as HSL, RGB, or hex. Text color. Can be specified as HSL, RGB, or hex. Overrides whether Plaid sandbox mode is used for bank account linking. Useful for testing. Callback to be notified about exceptions within the components. The `LayerError` object contains `type` (e.g., `'unauthenticated'`, `'api'`, `'render'`), `scope`, and `payload`. Callbacks that will be triggered for specific user events within the components. Callback triggered when users interact with embedded Layer components. Each event is a versioned envelope containing the event type, payload, and metadata. See [UI Events](/embedded-components/ui-events) for the full list of supported events. Callback triggered any time a transaction is categorized, matched, updated, etc. Callback triggered when new transactions are fetched. ### Environment Configuration There are two mutually exclusive ways to configure the Layer environment: **Predefined environment:** ```tsx theme={null} {...} ``` **Custom URL override:** ```tsx theme={null} {...} ``` ### UI Events The `onEvent` callback fires when users interact with embedded Layer components, emitting a versioned event envelope with a type, payload, and metadata. See [UI Events](/embedded-components/ui-events) for the event structure and the full list of supported events. # In-App Linking Source: https://docs.layerfi.com/embedded-components/linking Layer's React components can be configured to display arbitrary React elements. These can be used to display links to external resources, or to navigate to other parts of your application. To do so, you need to implement a function that takes a `LinkingMetadata` object and returns a `ReactNode`. You can use the entityName property (an instance of the `EntityName` enum) to determine the type of entity being linked to (e.g., `Bank Transaction` or `Invoice Payment`), and render different links based on the entity type. ```ts theme={null} const convertLinkingMetadataToLink = (details: LinkingMetadata) => { let path switch (details.entityName) { case EntityName.BankTransaction: path = `bank-transactions/${details.id}` break case EntityName.InvoicePayment: path = details.relatedEntityLinkingMetadata?.[0].id ? `invoices/${details.relatedEntityLinkingMetadata?.[0].id}` : undefined break default: path = undefined } return path ? ( {details.entityName} ) : undefined } ``` There are multiple places where links can be displayed: ### BankTransactions / BankTransactionsWithLinkedAccounts ```ts theme={null} ``` Links will appear in the details of suggested matches ![BankTransactions / BankTransactionsWithLinkedAccounts](https://layer-public.s3.us-west-2.amazonaws.com/documentation-images/bankTransactionMatchLink.png) ### GeneralLedger ```ts theme={null} ``` Links will appear in the details of ledger entries GeneralLedger # Accounting Overview Source: https://docs.layerfi.com/embedded-components/pages/accounting-overview Accounting Overview Page. This view provides an out of the box ready dashboard with an overview of the health, activity, and accounting status of the business. We recommend this layout as the entrypoint to the accounting experience for users who do not have bookkeeping services. Those with bookkeeping services should see the [Bookkeeping Overview](/embedded-components/pages/bookkeeping-overview) page. The overview page consists of the interactive P\&L chart, the monthly revenue & expense breakdowns, and summary cards with a CTA for uncategorized transactions. Accounting Overview ```tsx theme={null} import { AccountingOverview } from '@layerfi/components' { navigate('../bank-transactions') }} /> ``` ### Properties Controls whether the page title/header is displayed. A function which navigates to the bank transactions to review page of your app. This will be triggered when clicking on the transactions-to-review CTA. Custom content rendered between the P\&L chart and the detailed charts. Use this to insert banners, CTAs, or other content into the layout. List of colors to use for the P\&L detail wheels. Specified in hex strings, i.e. `['#FF0000', '#00FF00', '#0000FF']`. Configuration passed through to components within the page layout. Configuration for the P\&L summary cards. Optional styling overrides for the mini donut charts and swatch colors on the summary cards. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the revenue card's mini chart and swatch. Cycles with reduced opacity once exhausted. Ordered palette for the expenses card's mini chart and swatch. Cycles with reduced opacity once exhausted. Color for the uncategorized portion of each card's mini chart and swatch. Omit to keep the default neutral color. Controls which reporting mode the summary cards display. Defaults to profit and loss. With `'profitAndLoss'` (the default), the cards show revenue, expenses, and net profit. With `'cashflow'`, the cards show money in, money out, and net cash flow. Only applies when `type` is `'cashflow'`. Controls whether the money in and money out cards include a categorized vs. uncategorized breakdown footer. Configuration for the P\&L chart. Optional styling overrides for the chart. Width of the bars, in pixels. Width of the bars when the chart renders in its compact layout (below 620px wide). Defaults to half of `barWidth`. Configuration for the revenue and expenses breakdown charts, keyed by scope. Optional styling overrides for the revenue breakdown chart. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the chart. Categories are assigned colors in alphabetical order by name; if the list is shorter than the number of categories, colors repeat with reduced opacity. Color for the uncategorized slice and its legend swatch. Omit to keep the default dot-pattern donut fill and neutral swatch color. Inner radius of the donut chart. Outer radius of the donut chart. Same shape as `revenue.chartConfig` (with `colors.expenses` instead of `colors.revenue`), applied to the expenses breakdown chart. Filters P\&L data by a specific tag (project/category). Display label for the tag filter. The tag key to filter by. Tag values to include. Customize text and labels throughout the page. Override the page title. Defaults to `'Accounting overview'`. Override the P\&L section header text. Defaults to `'Profit & Loss'`. Override the header for the expenses chart. Defaults to `'Expenses'`. Override the header for the revenue chart. Defaults to `'Revenue'`. Label for the revenue summary card. Label for the expenses summary card. Label for the net profit summary card. Label for the money in summary card when using the cashflow reporting variant. Defaults to `'Money in'`. Label for the money out summary card when using the cashflow reporting variant. Defaults to `'Money out'`. Label for the net cash flow summary card when using the cashflow reporting variant. Defaults to `'Net cash flow'`. # Bank Accounts and Transactions Source: https://docs.layerfi.com/embedded-components/pages/bank-transactions-with-linked-accounts Bank Accounts and Transactions Page. Manage transactions and accounts in one page. This view simply groups together the accounts management and the transaction categorization list so they can be managed together. Bank Accounts and Transactions ```tsx theme={null} import { BankTransactionsWithLinkedAccounts } from '@layerfi/components' ``` ### Properties Controls whether the page title/header is displayed. Controls whether transaction descriptions are displayed in the transaction list. Controls whether receipt upload functionality is available for transactions. Controls whether tooltips are displayed to provide additional information about transactions and categorization. Controls whether transaction tags are displayed and can be managed in the transaction list. Controls whether the unlink option is available for linked accounts. Controls whether upload options are displayed for transactions. `mobileList` will use the mobile list view for transactions, while `regularList` will use the regular list view. See the [Bank Transactions](/embedded-components/components/bank-transactions) component for more information on this view. Flag indicating whether to show the ledger balance corresponding to each linked account in the linked account card. This can be useful for users who want to reconcile ledger balances with their bank statements. Flag to enable or hide the customer/vendor column in the transactions table. Applies elevated styling to the `` component. Shows the break-connection option in linked accounts, allowing users to disconnect accounts. Controls whether categorization rule suggestions are shown for bank transactions. Custom function for rendering in-app navigation links. Receives LinkingMetadata as a parameter and should return a ReactNode. See the [In-App Linking](/embedded-components/linking) guide for details. Overrides for default strings in the component. Override for the page title. Defaults to "Bank transactions". String overrides for the linked accounts section. Override for the linked accounts section title. String overrides for the bank transactions section. See BankTransactions component documentation for available options. Configuration for using Plaid Hosted Link instead of the embedded Plaid modal. When provided, account linking and repair flows open a Plaid-owned page in the browser rather than displaying an embedded modal. Set to `true` when the user will open the hosted link in an `ASWebAuthenticationSession` (iOS) or Android Custom Tab. This tells Plaid to use the correct redirect handling for mobile contexts. Universal Link (iOS) or App Link (Android) that opens your app. Used when Plaid redirects from a third-party OAuth app (e.g., a bank's app) back to your app during app-to-app authentication. URI to redirect to after the user completes the Plaid hosted link flow (e.g., `myapp://plaid-complete`). Recommended for mobile apps to automatically close the hosted link session and return to your app. If not provided, the user sees a "Return to app" message and must navigate back manually. Callback function that navigates the user to the Plaid Hosted Link URL. This function receives the Plaid-owned URL and should open it in the device's browser or an in-app browser. Required for all hosted link configurations. # Bookkeeping Overview Source: https://docs.layerfi.com/embedded-components/pages/bookkeeping-overview Bookkeeping Overview Page. This view provides an out of the box ready dashboard for businesses enrolled in bookkeeping services. In addition to the components of the [Accounting Overview](/embedded-components/pages/accounting-overview), it includes the `` component showing all current tasks for a business. The overview page consists of the interactive P\&L chart, the monthly revenue & expense breakdowns, summary cards, and a sidebar with tasks and call booking. Bookkeeping Overview ```tsx theme={null} import { BookkeepingOverview } from '@layerfi/components' navigate('/accounts')} /> ``` ### Properties Controls whether the page title/header is displayed. Callback passed to the `` component, triggered when the user clicks the reconnect-accounts action. Configuration passed through to components within the page layout. Configuration for the P\&L summary cards. Optional styling overrides for the mini donut charts and swatch colors on the summary cards. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the revenue card's mini chart and swatch. Cycles with reduced opacity once exhausted. Ordered palette for the expenses card's mini chart and swatch. Cycles with reduced opacity once exhausted. Color for the uncategorized portion of each card's mini chart and swatch. Omit to keep the default neutral color. Controls which reporting mode the summary cards display. Defaults to profit and loss. With `'profitAndLoss'` (the default), the cards show revenue, expenses, and net profit. With `'cashflow'`, the cards show money in, money out, and net cash flow. Only applies when `type` is `'cashflow'`. Controls whether the money in and money out cards include a categorized vs. uncategorized breakdown footer. Configuration for the P\&L chart. Optional styling overrides for the chart. Width of the bars, in pixels. Width of the bars when the chart renders in its compact layout (below 620px wide). Defaults to half of `barWidth`. Configuration for the revenue and expenses breakdown charts, keyed by scope. Optional styling overrides for the revenue breakdown chart. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the chart. Categories are assigned colors in alphabetical order by name; if the list is shorter than the number of categories, colors repeat with reduced opacity. Color for the uncategorized slice and its legend swatch. Omit to keep the default dot-pattern donut fill and neutral swatch color. Inner radius of the donut chart. Outer radius of the donut chart. Same shape as `revenue.chartConfig` (with `colors.expenses` instead of `colors.revenue`), applied to the expenses breakdown chart. Customize text and labels throughout the page. Override the page title. Defaults to `'Bookkeeping overview'`. Override the header text for the tasks widget. Header text for the P\&L section. Defaults to `'Profit & Loss'`. Header for the expenses chart. Header for the revenue chart. Label for the revenue summary card. Label for the expenses summary card. Label for the net profit summary card. Label for the money in summary card when using the cashflow reporting variant. Defaults to `'Money in'`. Label for the money out summary card when using the cashflow reporting variant. Defaults to `'Money out'`. Label for the net cash flow summary card when using the cashflow reporting variant. Defaults to `'Net cash flow'`. # General Ledger Source: https://docs.layerfi.com/embedded-components/pages/general-ledger-view General Ledger View. The general ledger view offers a consistent UX for accessing the General Ledger. It includes both the chart of accounts and the list of journal entries in a single experience. General Ledger View ```tsx theme={null} import { GeneralLedgerView } from '@layerfi/components' ``` ### Properties Controls whether to display the title. Controls whether tag columns are displayed in the Journal view. Controls whether the customer/vendor selector is displayed when creating journal entries. Custom function for rendering in-app navigation links in the Chart of Accounts and Journal views. See the [In-App Linking](/embedded-components/linking) guide for details. Override for the page title. Defaults to `'General Ledger'`. Text for the chart of accounts toggle option. Defaults to `'Chart of Accounts'`. Text for the journal toggle option. Defaults to `'Journal'`. String overrides specific to the chart of accounts component. See [Chart of Accounts](/embedded-components/components/chart-of-accounts) for available options. String overrides specific to the journal component. See [Journal](/embedded-components/components/journal) for available options. Controls whether template accounts can be edited. We recommend this only be true for advanced users. Controls visibility of reversal entries. Controls visibility of the add account button. # Mileage Tracking Source: https://docs.layerfi.com/embedded-components/pages/mileage-tracking Mileage tracking page with trip management and deduction calculations. The Mileage Tracking view provides an interface for tracking business mileage, categorizing trips, and calculating tax deductions. Mileage Tracking ```tsx theme={null} import { MileageTracking } from '@layerfi/components' ``` ## Features * **Mileage Summary Statistics**: Overview of total deduction, miles, and trips * **Category Breakdown**: Business, personal, and uncategorized trips * **Monthly Deduction Chart**: Visual representation of mileage deductions by month * **Trip Management**: Detailed list of tracked trips with categorization * **Year Selection**: Filter trips and statistics by tax year * **Tax Deduction Calculation**: Automatic calculation using IRS standard mileage rate ## Usage Examples **Basic usage:** ```tsx theme={null} ``` **Without title header:** ```tsx theme={null} ``` ## Properties Whether to display the page title header "Mileage Tracking". ## Component Structure ### MileageTrackingStats Summary statistics and chart: * **Total Deduction**: Estimated tax deduction based on business miles * **Total Miles**: Business, personal, and uncategorized miles * **Total Trips**: Count of trips by category * **Monthly Chart**: Bar chart showing monthly mileage deductions ### Trips Detailed trip list: * Trip date, time, and locations * Distance traveled * Trip category (Business, Personal, Uncategorized) * Categorization and editing capabilities ## Deduction Calculation Deductions are calculated using the IRS standard mileage rate: * Only business-categorized miles contribute to deductions * Example (2024 rate of \$0.67/mile): 1,000 business miles = \$670 deduction * Personal and uncategorized miles do not contribute to deductions ## Trip Categorization * **Business**: Miles for business purposes (tax deductible) * **Personal**: Personal travel (not deductible) * **Uncategorized**: Trips awaiting categorization # Reports (Deprecated) Source: https://docs.layerfi.com/embedded-components/pages/reports Combined reports view. This layout is deprecated. Use the new [Reports](/embedded-components/pages/unified-reports) layout instead. The reports view combines the three most common reports into a single page, including the P\&L, Balance Sheet, and Cash Flow Statement. These are the tabular forms of these reports rather than interactive charts. ![Reports View](https://github.com/user-attachments/assets/a49308a5-0c08-4cc3-936a-be5f652d8690) ```tsx theme={null} import { Reports } from '@layerfi/components' ``` ### Properties Controls whether the page title/header is displayed. Array of reports to enable. Defaults to all three reports. Available values: `['profitAndLoss', 'balanceSheet', 'statementOfCashFlow']`. If more than one report is enabled, view will include a tabbed interface to switch between reports. Custom function for rendering in-app navigation links. See the [In-App Linking](/embedded-components/linking) guide for details. Controls the granularity of date selection for the P\&L report. Money format for CSV export. `'CENTS'` formats as an integer of cents. `'DOLLAR_STRING'` formats as a dollar string. Controls the granularity of date selection for the cash flow statement. Money format for CSV export. Page title to place in the header. Button text on download/export button. Defaults to "Download". Button text on download/export button, only shows upon download failure. Defaults to "Retry". Table column header for the category column. Defaults to "Category". Table column header for the account type column, e.g. Revenue, Expense. Defaults to "Type". Value column header showing dollar amounts. Defaults to "Value". Label for the "Gross Profit" row. Defaults to "Gross Profit". Label for the "Profit before taxes" row. Defaults to "Profit before taxes". Label for the "Net Profit" row. Defaults to "Net Profit". Label for the "Type" column, indicating type of account on the balance sheet, e.g. `Liability`. Defaults to "Type". Label for the "Total" column, indicating the total value of the account. Defaults to "Total". Label for the "Type" column, indicating type of income line statement. Defaults to "Type". Label for the "Total" column, indicating the total value of the line item. Defaults to "Total". # Solopreneur Overview Source: https://docs.layerfi.com/embedded-components/pages/solopreneur-overview Solopreneur Overview Page. This view provides an out of the box overview dashboard tailored to solopreneurs. It leads with cash flow: the summary tiles at the top default to the cashflow reporting variant (money in, money out, and net cash flow), each with a categorized vs. uncategorized breakdown. The page consists of an onboarding banner (prompting the user to link bank accounts and set up their tax profile), the cashflow summary tiles, and a grid of summary cards for profit & loss, expenses, tax estimates, and mileage tracking. Solopreneur Overview ```tsx theme={null} import { SolopreneurOverview } from '@layerfi/components' navigate('../tax-profile'), }, cashflowSummaries: { onTransactionsToReviewClick: () => navigate('../bank-transactions'), }, }} /> ``` ### Properties List of colors to use for the expenses breakdown chart. Specified in hex strings, i.e. `['#FF0000', '#00FF00', '#0000FF']`. Customize text and labels throughout the page. Override the page title. Defaults to `'Overview'`. Labels for the summary tiles at the top of the page. Label for the revenue summary tile. Label for the expenses summary tile. Label for the net profit summary tile. Label for the money in summary tile when using the cashflow reporting variant. Defaults to `'Money in'`. Label for the money out summary tile when using the cashflow reporting variant. Defaults to `'Money out'`. Label for the net cash flow summary tile when using the cashflow reporting variant. Defaults to `'Net cash flow'`. Titles for the summary cards in the grid below the summary tiles. Override the title of the profit & loss summary card. Override the title of the expenses summary card. Override the title of the tax estimates summary card. Override the title of the mileage tracking summary card. Callbacks invoked when the user interacts with elements of the page. A function which navigates to the tax profile setup page of your app. This will be triggered when clicking the "Set up your tax profile" button on the onboarding banner. If omitted, the button is not shown. A function which navigates to the bank transactions to review page of your app. This will be triggered when clicking on the transactions-to-review CTA in the summary tiles. Interaction callbacks for the summary cards in the grid. Each card accepts the same shape. Called when the user clicks the expand button on the profit & loss summary card. The expand button is only rendered when this callback is provided. Called when the user clicks the expand button on the expenses summary card. The expand button is only rendered when this callback is provided. Called when the user clicks the expand button on the tax estimates summary card. The expand button is only rendered when this callback is provided. Called when the user clicks the expand button on the mileage tracking summary card. The expand button is only rendered when this callback is provided. Configuration passed through to components within the page layout. Configuration for the summary tiles at the top of the page. Optional styling overrides for the mini donut charts and swatch colors on the summary tiles. Takes precedence over `chartColorsList` where both are supplied. Ordered palette for the revenue tile's mini chart and swatch. Cycles with reduced opacity once exhausted. Ordered palette for the expenses tile's mini chart and swatch. Cycles with reduced opacity once exhausted. Color for the uncategorized portion of each tile's mini chart and swatch. Omit to keep the default neutral color. Controls which reporting mode the summary tiles display. On this page, defaults to cashflow. With `'cashflow'` (the default on this page), the tiles show money in, money out, and net cash flow. With `'profitAndLoss'`, the tiles show revenue, expenses, and net profit. Only applies when `type` is `'cashflow'`. Controls whether the money in and money out tiles include a categorized vs. uncategorized breakdown footer. Configuration for the summary cards in the grid below the summary tiles. Optional styling overrides for the trend chart on the profit & loss summary card. Width of the bars, in pixels. Width of the bars when the chart renders in its compact layout (below 620px wide). Defaults to half of `barWidth`. Optional styling overrides for the donut chart on the expenses summary card. Takes precedence over the page-level `chartColorsList` where both are supplied. Ordered palette for the chart. Categories are assigned colors in alphabetical order by name; if the list is shorter than the number of categories, colors repeat with reduced opacity. Color for the uncategorized slice and its legend swatch. Omit to keep the default dot-pattern donut fill and neutral swatch color. Inner radius of the donut chart. Outer radius of the donut chart. Configuration for using Plaid Hosted Link instead of the embedded Plaid modal when linking bank accounts from the onboarding banner. When provided, account linking opens a Plaid-owned page in the browser rather than displaying an embedded modal. Set to `true` when the user will open the hosted link in an `ASWebAuthenticationSession` (iOS) or Android Custom Tab. This tells Plaid to use the correct redirect handling for mobile contexts. Universal Link (iOS) or App Link (Android) that opens your app. Used when Plaid redirects from a third-party OAuth app (e.g., a bank's app) back to your app during app-to-app authentication. URI to redirect to after the user completes the Plaid hosted link flow (e.g., `myapp://plaid-complete`). Recommended for mobile apps to automatically close the hosted link session and return to your app. If not provided, the user sees a "Return to app" message and must navigate back manually. Callback function that navigates the user to the Plaid Hosted Link URL. This function receives the Plaid-owned URL and should open it in the device's browser or an in-app browser. Required for all hosted link configurations. # Tax Estimates Source: https://docs.layerfi.com/embedded-components/pages/tax-estimates Tax estimates page with quarterly payment tracking and tax profile management. The Tax Estimates view provides a comprehensive interface for managing business income tax estimates, including quarterly tax calculations and payment tracking. Tax Estimates ```tsx theme={null} import { TaxEstimatesView } from '@layerfi/components' ``` ## Features * **Tax Profile Onboarding**: Guided setup for filing status, state, dependents, and deduction preferences * **Quarterly Estimates**: Detailed breakdown of estimated federal and state taxes by quarter * **Tax Calculations**: Automatic calculation of taxable business income, adjusted gross income, and tax liabilities * **Payment Tracking**: Record and track quarterly tax payments with due dates * **Year Selection**: Navigate between tax years to view historical estimates and payments * **Expandable Details**: Drill down into tax calculations including taxable income, federal taxes, and state taxes ## Properties The TaxEstimatesView component does not accept any props. All configuration and state management is handled internally. ## User Flow ### First-Time Users (Not Onboarded) New users see the Tax Profile form, grouped into three sections: **Federal Tax Information** * Filing status (Single, Married Filing Jointly, Married Filing Separately, Head of Household) * Annual W-2 income, tip income, and overtime income * Custom withholding **State Tax Information** * US state * State filing status * Custom withholding **Deductions** * Simplified home office deduction * Standard mileage deduction The form cannot be submitted until the user acknowledges the disclaimer at the bottom. Tax Profile ### Onboarded Users Once onboarded, users see a tabbed interface: **Estimates Tab** - Summary card with total estimated taxes and expandable sections for: * Taxable Business Income (revenue, expenses, deductions) * Estimated Federal Taxes (income tax, self-employment tax, quarterly estimates) * Estimated State Taxes (state tax and quarterly estimates, if applicable) **Payments Tab** - Quarterly tax payment schedule showing: * Payment quarter (Q1, Q2, Q3, Q4) * Due dates * Estimated amounts * Federal and state breakdowns Tax Payments ### Profile Management Users can update their tax profile at any time through the menu in the header. # Time Tracking Source: https://docs.layerfi.com/embedded-components/pages/time-tracking Time tracking page with a live timer, manual time entries, and a service catalog. The Time Tracking view gives your customers a place to record billable time — either with a running timer or by entering hours after the fact — and to break down where that time went by service. Time Tracking ```tsx theme={null} import { TimeTracking } from '@layerfi/components' ``` ## Features * **Live Timer**: Start a timer, let it run across page loads, then complete it into a time entry * **Manual Entries**: Record time after the fact with a date, duration, service, and optional customer * **Service Catalog**: Define the services time is tracked against, each with an optional hourly rate * **Period Summary**: Total time for the selected period, broken down by service * **Filtering**: Narrow the entry list by service and customer, on top of the selected date range * **Invoice Awareness**: Entries already billed to an invoice are locked against edits and deletion ## Properties Whether to display the page title header. The header also carries the actions menu, so hiding it hides the entry point to the service catalog. Called when the user selects **Reports** from the header menu. The menu item only appears when this callback is provided — omit it if your application has nowhere to send the user. Overrides for default strings in the component. Override for the view title. Defaults to "Time Tracking". ## Usage Examples **Basic usage:** ```tsx theme={null} ``` **Embedded in a page that supplies its own heading:** ```tsx theme={null} ``` **With a link out to your own reporting:** ```tsx theme={null} navigate('../reports')} /> ``` ## Timer Lifecycle **Start Timer** asks for a service and, optionally, a customer and memo, then the timer becomes a banner at the top of the view counting up. Both the service and the customer stay editable while it runs. The timer belongs to the business, not to the browser tab: closing the tab or reloading doesn't lose it, and it comes back showing the right elapsed time. Only one runs at a time — resolve it with **Complete**, which turns it into an entry, or **Cancel**, which discards it. A running timer ## Time Entries Entries can also be created directly through the **Add Entry** form rather than timed. Time entry details ### Invoiced entries Once an entry has been billed to an invoice it is locked. The drawer marks it with an **Invoiced** badge, the form is read-only, and the delete action is withheld. Correcting billed time means going through the invoice, not the entry. ## Services Time is tracked against services from the business's catalog, managed from the **Services** item in the header menu. Each service has a name and an optional hourly rate, which is what turns tracked minutes into billable amounts in the summary. The service catalog ## API The view is built on Layer's time tracking endpoints, which you can also call directly to sync time from an existing system: * [List time entries](/api-reference/v1/time-tracking/list-time-entries) * [Create a time entry](/api-reference/v1/time-tracking/create-time-entry) and [bulk create time entries](/api-reference/v1/time-tracking/bulk-create-time-entries) * [Update a time entry](/api-reference/v1/time-tracking/update-time-entry) * [Time entry summary](/api-reference/v1/time-tracking/get-time-entry-summary) — the figures behind the Overview card * [Invoice preview](/api-reference/v1/time-tracking/get-invoice-preview) — turn unbilled time into invoice line items # Reports Source: https://docs.layerfi.com/embedded-components/pages/unified-reports Unified reporting layout. The `UnifiedReports` layout renders the latest report experience from Layer's embedded components. It loads all reports enabled for the business and presents them in a unified interface with report navigation, expandable report tables, and Excel download support.
Reports desktop Reports mobile
```tsx theme={null} import { UnifiedReports } from '@layerfi/components' ``` ### Properties Controls how report navigation is presented on desktop. * `'sidebar'` (default): Available reports are listed in a left-hand navigation sidebar alongside the report content. * `'menu'`: The sidebar is hidden and report navigation is presented as a dropdown menu in the report header, giving the report content the full width of the layout. On smaller screens, report navigation is always available from the page header regardless of this setting. Controls the granularity of the date range picker used across reports. Opens a specific report on first load instead of the business default (e.g. `{ reportKey: "BALANCE_SHEET" }`). Applied once when the report configuration loads; unknown keys fall back to the default. ### Behavior The unified reporting layout combines all reports into a single standardized interface with shared controls and export formats. Reports are organized in a left-hand navigation so users can move between available reports without leaving the page. The `navigationVariant` prop can switch this to a dropdown menu in the report header instead, which lists every enabled report grouped by area: Report navigation as a menu On smaller screens, the report navigation is always available from the page header. Report tables support nested rows. Top-level rows are expanded by default, and users can expand or collapse all rows from the report header. The report header includes a download action for exporting the currently selected report to Excel. The export uses the same report selection shown in the interface, starts the file download when the export is ready, and changes to a retry action if the export request fails. ### Tag filters If a business has a user-visible tag dimension, `UnifiedReports` lists one extra report per dimension. A `location` dimension produces **Profit and Loss by Location**. That report appears once the dimension has at least one tag value. The report shows a multi-select above the table, labeled with the dimension's `display_name`. Each tag value you select becomes its own column. Across more than one period, each value becomes a column group with one sub-column per period. The Excel export follows the same selection. The business's tag configuration drives all of this, not component props. Send [Create tag dimension](/api-reference/v1/create-tag-dimension) with `user_visible` set to `true` and one entry in `values` per location. The dimension's `display_name` names both the report and the filter. Each value's `display_name` becomes a column header, so a value with no display name produces a header like `27`. ```bash theme={null} curl -X POST https://api.layerfi.com/v1/businesses/{businessId}/tags/dimensions \ -H 'Content-Type: application/json' \ -d '{ "key": "location", "display_name": "Location", "strictness": "NON_BALANCING", "user_visible": true, "values": [ { "value": "27", "display_name": "Downtown" }, { "value": "69", "display_name": "Airport" } ] }' ``` [List tag dimensions](/api-reference/v1/list-tag-dimensions) shows the dimensions a business already has. To add a value later, send [Create tag value](/api-reference/v1/create-tag-value). To make an existing dimension visible, send [Update tag dimension](/api-reference/v1/update-tag-dimension) with `user_visible` set to `true`. Apply tags with [Tag entities](/api-reference/v1/tag-entities), or send tags inline when you create invoices, payments, and payouts. Tag payments and payouts as well as invoices. If you tag invoices alone, revenue splits by location but expenses fall outside the location columns. `` picks up the new report. Define your tag values through the API. The tag pickers in Layer's other components let users choose from the values you define. Users cannot add a new value themselves. Each report filters on one tag dimension. A business with a `location` dimension and a `program` dimension gets two separate reports, not one report that crosses both. # Styling Source: https://docs.layerfi.com/embedded-components/styling You must explicitly import the Layer stylesheet into your application. We recommend importing it in the same file as your root component. ```ts theme={null} import '@layerfi/components/index.css' ``` ## Customization You can customize the styling of Layer's React components to match the appearance of your product. There are three ways to do this (ordered from simplest to most control): 1. Using the `theme` attribute of `LayerProvider`, 2. Setting CSS variables, 3. Overwriting CSS classes. ### `theme` attribute of `LayerProvider` The theme attribute allows you to set primary light and dark colors. The component will then use your primary colors to create a cohesive color palette across all components. We won't add any new colors, just different lightness of your brand colors for accents where helpful, e.g. hover states. ```ts theme={null} {...} ``` The `colors` can be defined in `HSL`, `RGB` or `HEX`: ```tsx theme={null} // HSL: colors: { dark: { h: '28', s: '26%', l: '11%' }, light: { h: '52', s: '100%', l: '55%' }, }, // RGB: colors: { dark: { r: '36', g: '28', b: '21' }, light: { r: '255', g: '224', b: '27' }, }, // HEX: colors: { dark: { hex: '#241C15' }, light: { hex: '#FFE01B' }, }, ``` ### CSS variables ```css theme={null} body .Layer__component { --color-dark-h: 167; --color-dark-s: 38%; --color-dark-l: 15%; --text-color-primary: #333; } ``` The full list of variables is listed in the [`variables.css`](https://github.com/Layer-Fi/layer-react/blob/main/src/styles/variables.scss) file and contains: ```scss theme={null} // 1. BASE VARIABLES: --color-black: #1a1a1a; --color-white: white; --color-info-success: hsl(145, 45%, 42%); --color-info-success-bg: hsl(145, 59%, 86%); --color-info-success-fg: hsl(145, 63%, 29%); --color-info-warning: hsl(43, 100%, 44%); --color-info-warning-bg: hsl(43, 100%, 84%); --color-info-warning-fg: hsl(43, 88%, 26%); --color-info-error: hsl(0 76% 50%); --color-info-error-bg: hsl(0 83% 86%); --color-info-error-fg: hsl(0 88% 32%); --color-dark-h: 0; --color-dark-s: 0%; --color-dark-l: 7%; --color-dark: hsl(var(--color-dark-h) var(--color-dark-s) var(--color-dark-l)); --color-light-h: 0; --color-light-s: 0%; --color-light-l: 90%; --color-light: hsl( var(--color-light-h) var(--color-light-s) var(--color-light-l) ); --color-base-0: #fff; --color-base-50: hsl(var(--color-dark-h) 1% 98%); --color-base-100: hsl(var(--color-dark-h) 1% 96%); --color-base-200: hsl(var(--color-dark-h) 1% 94%); --color-base-300: hsl(var(--color-dark-h) 2% 92%); --color-base-400: var(--color-light); --color-base-500: hsl(var(--color-dark-h) 2% 53%); --color-base-600: hsl(var(--color-dark-h) 7% 40%); --color-base-700: hsl(var(--color-dark-h) 9% 27%); --color-base-800: hsl(var(--color-dark-h) 12% 20%); --color-base-900: var(--color-dark); --color-base-1000: hsl(var(--color-dark-h) 20% 7%); --max-component-width: 1408px; --base-transparent-1: hsla(220, 43%, 11%, 0.01); --base-transparent-2: hsla(220, 43%, 11%, 0.02); --base-transparent-4: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.04 ); --base-transparent-5: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.05 ); --base-transparent-6: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.06 ); --base-transparent-8: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.08 ); --base-transparent-10: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.1 ); --base-transparent-12: hsla( var(--color-dark-h), var(--color-dark-s), var(--color-dark-l), 0.12 ); // 2. BASE CUSTOMIZATION --color-primary: var(--color-dark); --color-accent: var(--color-light); --color-secondary: var(--color-base); --color-success: var(--color-info-success); --color-danger: var(--color-info-error); --color-danger-dark: hsl(349, 30%, 30%); --color-danger-light: hsla( var(--color-info-error-h), var(--color-info-error-s), var(--color-info-error-l), 0.4 ); --text-color-primary: var(--color-dark); --text-color-secondary: var(--color-base-600); --bg-element-focus: var(--color-base-50); // 3. EXTENDED CUSTOMIZATION --font-family: 'InterVariable', 'Inter', sans-serif; --font-family-numeric: 'InterVariable', 'Inter', sans-serif; --text-xs: 11px; --text-sm: 12px; --text-md: 14px; --text-lg: 16px; --text-heading: 24px; --text-heading-sm: 16px; --font-weight-normal: 460; --font-weight-bold: 540; --spacing-4xs: 2px; --spacing-3xs: 4px; --spacing-2xs: 6px; --spacing-xs: 8px; --spacing-sm: 12px; --spacing-md: 16px; --spacing-lm: 20px; --spacing-lg: 24px; --spacing-xl: 32px; --spacing-2xl: 36px; --spacing-3xl: 40px; --spacing-5xl: 52px; --bg-color: var(--color-white); --border-color: var(--color-base-200); --border-radius-4xs: 2px; --border-radius-3xs: 4px; --border-radius-2xs: 6px; --border-radius-xs: 8px; --border-radius-sm: 12px; --border-radius: 16px; --border-radius-5xl: 52px; --text-color-transaction-credit: var(--color-info-success); --text-color-varying-amount: var(--color-base-700); --input-border-radius: var(--border-radius-2xs); --input-font-size: var(--text-md); --input-border-color: var(--color-base-300); --input-placeholder-color: var(--color-base-500); --label-color: var(--color-base-700); --btn-font-size: var(--text-md); --btn-border-radius: var(--border-radius-2xs); --btn-color: var(--color-black); --btn-bg-color: var(--color-white); --btn-color-primary: var(--color-white); --btn-bg-color-primary: var(--color-black); --btn-color-hover: var(--color-white); --btn-bg-color-hover: var(--color-primary); --btn-color-icon: var(--color-black); --btn-bg-color-icon: var(--color-base-50); --btn-color-icon-hover: var(--color-primary); --btn-bg-color-icon-hover: var(--color-accent); --btn-secondary-color: var(--color-black); --btn-secondary-bg-color: var(--color-white); --badge-color: var(--color-base-900); --badge-fg-color: var(--color-base-900); --badge-bg-color: var(--color-base-400); --badge-color-success: var(--color-info-success); --badge-fg-color-success: var(--color-info-success-fg); --badge-bg-color-success: var(--color-info-success-bg); --badge-color-warning: var(--color-info-warning); --badge-fg-color-warning: var(--color-info-warning-fg); --badge-bg-color-warning: var(--color-info-warning-bg); --badge-color-error: var(--color-info-error); --badge-fg-color-error: var(--color-info-error-fg); --badge-bg-color-error: var(--color-info-error-bg); --badge-border-radius: var(--border-radius-sm); --table-bg: var(--color-white); --tooltip-color: var(--color-white); --tooltip-bg-color: var(--color-base-800); --bar-color-income: var(--color-base-400); --bar-color-expenses: var(--color-base-900); --chart-indicator-color: var(--color-base-700); ``` ### CSS classes For fine grained control, you can override specific classes. We recommend using your browser dev tools to find the component you want restyle and overriding that specific class with a higher priority CSS rule. ```css theme={null} body .Layer__table-cell-content { background: white; } body .Layer__bank-transaction-row .Layer__table-cell-content { background: gray; } ``` # UI Events Source: https://docs.layerfi.com/embedded-components/ui-events Layer's React components emit UI events when users interact with them. Subscribe to these events through the `onEvent` callback on ``'s `eventCallbacks` prop to power analytics, custom logging, or to react to user activity in your own application. ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; { console.log('Layer event:', event.type, event.payload) }, }} > {...} ``` The `onEvent` callback fires when users interact with embedded Layer components. Each event includes a type, version, event-specific payload, and metadata. ## Event Structure ```tsx theme={null} interface LayerEventEnvelope { source: 'layer' type: LayerEventType version: 1 payload: TPayload metadata: { component: LayerEventComponent timestamp: string packageVersion?: string } } ``` The `LayerEventType` value, `LayerEventComponent` value, and `LayerEvent` type are exported from `@layerfi/components` for TypeScript users. `LayerEvent` is a discriminated union, so checking `event.type` narrows `event.payload` to the payload for that event. ## Supported Events All events listed below currently use `version: 1`. Fired when a user selects a month in the Tasks component. The selected year (e.g., `2024`). The selected month (1-12). Fired when a user selects a year in the Tasks component. The selected year (e.g., `2024`). Fired when a user clicks on a task to expand or collapse it. The ID of the clicked task. Fired when a user clicks the button to schedule a call with a bookkeeper. Empty object. Fired when a user selects a month on the Profit and Loss chart. The selected year (e.g., `2024`). The selected month (1-12). Fired when a user submits a search query in the Bank Transactions component. The search query entered by the user. Fired when a user clicks to download transactions. Empty object. Fired when a user saves a memo or description for a transaction. The ID of the transaction. Fired when a user initiates a receipt upload for a transaction. The ID of the transaction. Fired when a user navigates to a different page in the Bank Transactions list. The page number the user navigated to. Fired when a user navigates to a different report in the Unified Reports view. The key identifying the selected report. Fired when a user clicks to download a report. The key identifying the report being downloaded. Fired when a user expands or collapses a section in a report table. The key identifying the report section. Whether the section is now expanded (`true`) or collapsed (`false`). Fired when a user clicks to add a new linked account. Empty object. Fired when a user confirms unlinking a bank account. The ID of the account being unlinked. ## Example Usage ```tsx theme={null} import { LayerProvider, type LayerEvent, LayerEventType } from "@layerfi/components"; function App() { const handleLayerEvent = (event: LayerEvent) => { switch (event.type) { case LayerEventType.TransactionsSearchSubmitted: analytics.track('user_searched_transactions', { query: event.payload.query, }) break case LayerEventType.TaskClicked: console.log('User clicked task:', event.payload.taskId) break } } return ( {...} ) } ``` # Generating async reports Source: https://docs.layerfi.com/guides/async-reports Submit an export request, poll for status or use webhooks, then download the file Some Layer reports are too large or expensive to generate in a single synchronous request. For those, Layer uses an async export workflow: 1. Submit a report generation request 2. Poll the export status (or wait for a webhook) 3. Download the completed file [Billing report exports](/api-reference/v1/create-billing-report-export) and [bookkeeping status report exports](/api-reference/v1/create-bookkeeping-status-report-export) both use the same [Exports](/api-reference/v1/list-exports) polling endpoints. ## Prerequisites * An active Layer account and API credentials * A valid access token (see [Initial Setup](/guides/initial-setup)) * Optional: a webhook endpoint configured to receive `export.completed` and `export.failed` (see [Webhooks](/api-details/webhooks)) ## Workflow Call the report-specific creation endpoint. For billing reports: ```bash theme={null} curl -X POST https://sandbox.layerfi.com/v1/billing/reports \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "end_month": 6, "end_year": 2026 }' ``` For a client-wide bookkeeping status XLSX instead, send a JSON body to [Create bookkeeping status report export](/api-reference/v1/create-bookkeeping-status-report-export). An empty object uses the default report options: ```bash theme={null} curl -X POST https://sandbox.layerfi.com/v1/reports/bookkeeping/exports \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{}' ``` Layer responds with `202 Accepted` and an Export resource (billing example below; the bookkeeping report uses `export_type: bookkeeping_status_report`): ```json theme={null} { "data": { "type": "Export", "id": "00000000-0000-0000-0000-000000000006", "business_id": null, "export_type": "billing_report", "status": "pending", "params": { "end_month": 6, "end_year": 2026 }, "download_url": null, "file_name": null, "error": null, "created_at": "2026-08-04T14:00:00-04:00", "started_at": null, "completed_at": null, "failed_at": null } } ``` Save the export `id`. You will use it to poll for completion. Call [Fetch export](/api-reference/v1/fetch-export) until `status` is `completed` or `failed`: ```bash theme={null} curl https://sandbox.layerfi.com/v1/exports/{export_id} \ -H "Authorization: Bearer " ``` Status values: | Status | Meaning | | - | - | | `pending` | Request accepted; generation has not started | | `processing` | Generation is in progress | | `completed` | File is ready; `download_url` is populated | | `failed` | Generation failed; see `error` | You can also list recent exports with [List exports](/api-reference/v1/list-exports), filtering by `export_type` (for example, `bookkeeping_status_report`). When `status` is `completed`, download the artifact from `download_url`. The URL is a short-lived presigned link. ```bash theme={null} curl -L -o billing-report.xlsx "" ``` Use `file_name` from the export response when saving the file locally. ## Prefer webhooks instead of polling If you do not want to poll, subscribe to export lifecycle webhooks in the Layer developer portal: * `export.completed` — the export finished successfully * `export.failed` — the export failed These events are **client-scoped**: the payload includes `id`, `type`, and `data`, and does **not** include top-level `business_id` / `business_external_id` fields used by business-scoped webhooks. Example `export.completed` payload: ```json theme={null} { "id": "export_completed_00000000-0000-0000-0000-000000000006", "type": "export.completed", "data": { "export_id": "00000000-0000-0000-0000-000000000006", "business_id": null, "export_type": "billing_report", "status": "completed", "error": null } } ``` After receiving `export.completed`, call [Fetch export](/api-reference/v1/fetch-export) to retrieve the `download_url`. See [Webhooks](/api-details/webhooks) for endpoint setup and signature verification, and the [Event Catalog](/api-details/webhooks-event-catalog) for the full list of event types. ## Related endpoints * [Create billing report export](/api-reference/v1/create-billing-report-export) * [Create bookkeeping status report export](/api-reference/v1/create-bookkeeping-status-report-export) * [List exports](/api-reference/v1/list-exports) * [Fetch export](/api-reference/v1/fetch-export) # Build custom UIs Source: https://docs.layerfi.com/guides/build-custom-uis Instead of embedding [Layer's React components](/guides/embedded-components), you can build your own interface directly on top of the [Layer API](/api-reference/business/business). This gives you full control over the look, feel, and behavior of every accounting experience in your product. The [API Reference](/api-reference/business/business) is the complete resource for building custom UIs. At a high level: * **Authenticate.** Follow [Authentication](/api-details/authentication) to obtain an access token. For client-side apps, mint [business-scoped access tokens](/api-details/authentication#business-scoped-access-tokens) on your backend so the browser never holds your `client_secret`. * **Read and write data.** Use the API to fetch reports, list and [categorize transactions](/api-reference/bank-transaction/categorize), and manage invoices, bills, and more. * **Stay in sync.** Subscribe to [webhooks](/api-details/webhooks) so your UI updates as data changes in Layer. Launch Plaid Link from your own interface while Layer manages the connection and imports account activity. Reach out to your Layer contact if you'd like guidance on building a specific custom experience. # Onboard a business Source: https://docs.layerfi.com/guides/business-onboarding Onboard one of your business customers to Layer ## Prerequisites Before onboarding a business, you will need: * An active Layer account and API credentials * A valid access token (see [Quickstart](/guides/quickstart)) * Your customer's basic business information (legal name, entity type, state) ## Overview The first step is to onboard your customer to Layer using the [Create a Business](/api-reference/v1/create-business) endpoint. This creates a record for your customer in Layer's systems and provisions their general ledger. Gather the information about your customer's business. We recommend providing as much information as possible to help Layer accurately classify transactions and provide a better experience for your customer: * `legal_name` - The business's legal name * `entity_type` - One of: `SOLE_PROP`, `C_CORP`, `LLC`, `S_CORP`, `PARTNERSHIP` * `us_state` - Two letter state code * `external_id` - Your internal ID for this business, useful for linking records * `phone_number` - Used for SMS-based transaction categorization * `unit_accounts` - Array of Unit account IDs to link * `plaid_items` - Array of Plaid items to connect (requires Plaid configuration) The `external_id` field allows you to link the Layer business record to your own internal customer ID, making it easier to associate data between systems. Make a POST request to the [Create a Business](/api-reference/v1/create-business) endpoint with the business information. See the full endpoint documentation for request examples and all available parameters. If you've configured Plaid credentials (see [Plaid Configuration](/api-reference/plaid/plaid)), you can link Plaid accounts during business creation by including the `plaid_items` field. The API responds with the created [Business](/api-reference/business/business) object. Save the `id` field - you'll use this to make API calls on behalf of this business. ## Next Steps After onboarding a business, you can: * [Import bank data](/guides/importing-bank-data) - Connect bank accounts and pass transactions to Layer * [Import sales / AR data](/guides/importing-sales-ar-data) - Pass invoices, payments, and payouts to Layer * [Set up transaction categorization](/guides/transaction-categorization) - Enable your customers to categorize transactions * [Display accounting reports](/guides/reporting) - Show profit & loss, balance sheet, and other reports * [Embed accounting components](/guides/embedded-components) - Add Layer's pre-built UI components to your platform # Build custom Plaid account linking Source: https://docs.layerfi.com/guides/custom-plaid-account-linking Connect customers' bank accounts from your own interface while Layer manages the Plaid connection. You can launch Plaid Link from your own interface without embedding a Layer React component. Your application controls the button, loading states, and account-selection experience, while Layer creates the Plaid Link token, securely stores the resulting access token, and imports account activity. This guide uses Plaid's React SDK in its examples. You can follow the same API flow with another [Plaid Link SDK](https://plaid.com/docs/link/). ## Prerequisites Before starting, you will need: * Plaid enabled for your Layer account * The ID of the Layer business connecting an account * A [business-scoped access token](/api-details/authentication#business-scoped-access-tokens) Install Plaid's React SDK: ```bash theme={null} npm install react-plaid-link ``` ## Link an account Follow [Authentication](/api-details/authentication#business-scoped-access-tokens) to generate an access token for the Layer business. When the customer chooses to connect an account, request a short-lived Link token from Layer. ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/link \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{}' ``` ```typescript TypeScript theme={null} const response = await fetch( `https://sandbox.layerfi.com/v1/businesses/${businessId}/plaid/link`, { method: "POST", headers: { Authorization: `Bearer ${businessAccessToken}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }, ); if (!response.ok) { throw new Error("Unable to start account linking"); } const { data } = await response.json(); const linkToken = data.link_token; ``` Layer returns the token that your frontend will pass to Plaid: ```json theme={null} { "data": { "type": "Link_Token", "link_token": "link-sandbox-...", "hosted_link": null } } ``` Request a new Link token each time the customer starts a new linking session. Do not persist or reuse it. For an implementation example, see the [`layer-react` Link-token request](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/api/businesses/%5Bbusiness-id%5D/plaid/link/index.ts#L11-L26). Initialize Plaid Link with the token returned by Layer. Open the modal only after the SDK reports that it is ready: ```tsx theme={null} import { useEffect } from "react"; import { usePlaidLink } from "react-plaid-link"; const { open, ready } = usePlaidLink({ token: linkToken, onSuccess: (publicToken, metadata) => { void exchangePublicToken(publicToken, metadata.institution); }, onExit: () => { setLinkToken(null); }, }); useEffect(() => { if (ready) { open(); } }, [open, ready]); ``` Plaid owns the credential-entry modal. Your application owns the interface that launches it and the experience shown before and after it. For an implementation example, see how [`layer-react` initializes and opens Plaid Link](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/features/linkedAccounts/usePlaidLinkModal.ts#L82-L113). Plaid calls `onSuccess` with a short-lived public token and institution metadata. Send both to Layer: ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/link/exchange \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{ "public_token": "public-sandbox-...", "institution": { "institution_id": "ins_123", "name": "Example Bank" } }' ``` ```typescript TypeScript theme={null} type PlaidInstitution = { institution_id: string; name: string; }; async function exchangePublicToken( publicToken: string, institution: PlaidInstitution | null, ) { const response = await fetch( `https://sandbox.layerfi.com/v1/businesses/${businessId}/plaid/link/exchange`, { method: "POST", headers: { Authorization: `Bearer ${businessAccessToken}`, "Content-Type": "application/json", }, body: JSON.stringify({ public_token: publicToken, institution, }), }, ); if (!response.ok) { throw new Error("Unable to connect the account"); } } ``` The `institution` value may be `null`. After a successful exchange, Layer securely stores the Plaid access token and begins importing account data. Do not exchange the public token directly with Plaid. Layer must perform the exchange so it can manage the Plaid Item and synchronize its accounts. For implementation examples, see the [`layer-react` exchange request](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/api/businesses/%5Bbusiness-id%5D/plaid/link/exchange.ts#L5-L16) and [success handler](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/features/linkedAccounts/usePlaidLinkModal.ts#L52-L79). After the exchange succeeds, call [List bank accounts](/api-reference/v1/list-bank-accounts): ```bash cURL theme={null} curl https://sandbox.layerfi.com/v1/businesses/{businessId}/bank-accounts \ --header "Authorization: Bearer " ``` A newly connected account may still be synchronizing. Poll the endpoint while any entry in `external_accounts` has `is_syncing` set to `true`. As a reference, `layer-react` polls every five seconds and stops after 15 minutes. For implementation examples, see the [`layer-react` bank-account request](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/api/businesses/%5Bbusiness-id%5D/bank-accounts/useListBankAccounts.ts#L9-L24) and [polling configuration](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/contexts/BankAccountsContext/BankAccountsContext.tsx#L23-L62). Layer withholds an external account's transactions from users until its relevance is confirmed. An external account requires relevance confirmation when its `notifications` array contains: ```json theme={null} { "type": "CONFIRM_RELEVANT" } ``` If the customer uses the account for their business, call [Confirm external account](/api-reference/v1/confirm-external-account): ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/external-accounts/{externalAccountId}/confirm \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{"is_relevant": true}' ``` If the account is not used for the business, call [Exclude external account](/api-reference/v1/exclude-external-account): ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/external-accounts/{externalAccountId}/exclude \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{"is_irrelevant": true}' ``` Use the external account's `id`, not the containing bank account's `id`. Refetch the bank accounts after processing every selection. Confirming an account marks it as relevant and lifts Layer's hold on its transactions. Layer ingests the account's data on its periodic background sync cadence rather than triggering a sync on confirmation, so transactions from a newly confirmed account may not appear immediately. For implementation examples, see how [`layer-react` identifies accounts requiring confirmation](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/utils/bankAccount.ts#L4-L10) and [submits confirmations and exclusions](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/features/bankAccounts/useConfirmAndExcludeMultiple.ts#L27-L41). ## Repair a Plaid connection When an external account has a non-null `connection_needs_repair_as_of` value, request an update-mode Link token. Pass that external account's `connection_external_id` as `plaid_item_id`: ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/update-mode-link \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ --data '{ "plaid_item_id": "" }' ``` Open Plaid Link with the returned `link_token` using the same process described above. After Plaid calls `onSuccess`, do not exchange the public token. Instead, ask Layer to refresh the connection status: ```bash cURL theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/external-accounts/update-connection-status \ --header "Authorization: Bearer " ``` Then refetch the business's bank accounts. For implementation examples, see the [`layer-react` update-mode token request](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/api/businesses/%5Bbusiness-id%5D/plaid/update-mode-link.ts#L6-L23) and [update-mode success handling](https://github.com/Layer-Fi/layer-react/blob/v0.1.141/src/hooks/features/linkedAccounts/usePlaidLinkModal.ts#L85-L104). ## Handle failures Your interface should let the customer retry each network operation independently: * If Link-token creation fails, keep the customer on your connection screen and request a new token when they retry. * If the customer exits Plaid Link, discard the Link token. * If the public-token exchange fails, show an error and let the customer start a new linking session. * If account synchronization takes longer than expected, stop polling and provide a manual refresh action. # Embed Layer React components Source: https://docs.layerfi.com/guides/embedded-components Using Layer's prebuilt React UI components. Layer publishes pre-built UI components to npm that can be dropped into any existing React app. These components handle all integration with Layer’s API with the exception of authentication, which must be done on your backend to avoid exposing credentials in your client-side apps. See the [Embedded Components](/embedded-components/layerprovider-context) section for a full list of components and pre-built Layouts. ## React setup The first step of using Layer's embedded components is to install the `layerfi/components` package via npm and your preferred package manager. ```bash theme={null} npm install @layerfi/components --save ``` ```bash theme={null} yarn install @layerfi/components ``` Next, set up the `LayerProvider` context, which serves as the configuration for fetching data for an individual business. All individual UX components must be rendered within this context. **For local testing**, you can use your Layer sandbox credentials (`APP_ID` and `APP_SECRET`). ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; {...} ``` **In production**, you should use access tokens scoped to a specific business. See the backend configuration section below for steps to retrieve scoped tokens: ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; '} > {...} ``` You must explicitly import the Layer stylesheet into your application. We recommend importing it in the same file as your root component. ```ts theme={null} import '@layerfi/components/index.css' ``` **Option 1: Set primary colors in theme configuration** You can set a dark and light theme color for all components. We recommend starting with simple customization like this using rgb, hsl or hex colors. ```tsx theme={null} {...} ``` **Option 2: Customize CSS variables** For more flexible customization, CSS variables are exposed to allow you to set colors and styles for the embedded components. We recommend setting these variables within a scoped container to isolate the scope to Layer components. In this example, we've set variables within the `.layer-container` class. ```css theme={null} body .layer-container { --color-black: #1a1a1a; --color-white: white; --color-neutral: #666666; --color-neutral-50: #fafcfc; --color-neutral-200: #eef0ef; --color-neutral-700: #636665; --color-red: #e46362; --color-info-green: #29bc9b; --color-primary: var(--color-black); --color-accent: var(--color-white); --color-secondary: var(--color-neutral); --color-success: var(--color-info-green); --color-danger: var(--color-red); --text-color-primary: var(--color-black); --text-color-secondary: var(--color-neutral-700); --bg-element-focus: var(--color-neutral-50); --font-family: "InterVariable", "Inter", sans-serif; --font-family-numeric: "InterVariable", "Inter", sans-serif; --text-sm: 12px; --text-md: 14px; --text-heading: 24px; --font-weight-normal: 460; --font-weight-bold: 580; --spacing-sm: 12px; --spacing-md: 16px; --spacing-2xl: 36px; --border-color: var(--color-neutral-200); } ``` Finally, add components to your pages as you would any React component. ```tsx theme={null} ``` Some components have multiple sub components which can be optionally included for composition and layout customization. ```tsx theme={null}
``` Type definitions are available for all components to assist with discovering options & subcomponents.
## Backend setup To ensure an end user can only access their own data, the Layer component must be provided with a scoped access token which limits access to a specific business. This is a two step process. Use your Layer-provided `client_id` and `client_secret` to obtain a platform-wide access token. See [Authentication](/api-details/authentication) for more information on this process. This should be done server-side to avoid exposing your credentials in your client-side application. ```bash curl theme={null} curl -X POST https://auth.layerfi.com/oauth2/token \ -u : \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "scope=https://sandbox.layerfi.com/sandbox" \ --data-urlencode "client_id=" ``` ```tsx typescript theme={null} const clientId = ""; const clientSecret = ""; const url = "https://auth.layerfi.com/oauth2/token"; axios.post(url, null, { params: { grant_type: "client_credentials", scope: "https://sandbox.layerfi.com/sandbox", client_id: clientId, }, auth: { username: clientId, password: clientSecret, }, headers: { "Content-Type": "application/x-www-form-urlencoded", }, }); ``` Next, send a request to the Business Access Token endpoint, including the business ID in the `business_id` URL parameter. By default, the token's session duration is set to one hour, but you can customize this by specifying the `session_duration` parameter (in seconds) up to 24 hours. ```bash curl theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/auth-token \ -H "Authorization: Bearer " -d '{"session_duration": 3600}' ``` ```tsx typescript theme={null} const url = `https://sandbox.layerfi.com/v1/businesses/${businessId}/auth-token`; axios.post(url, { session_duration: 3600, }, { headers: { 'Authorization': `Bearer ${accessToken}` } }) ``` You'll receive a new access token that can only make requests for the selected business. ```bash theme={null} { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` Finally, send this access token to the frontend and populate it in the `businessAccessToken` field of the `LayerProvider`context: ```tsx theme={null} {...} ``` # Asset data Source: https://docs.layerfi.com/guides/importing-asset-data Layer tracks a business's fixed assets, such as vehicles, equipment, right-of-use assets, and goodwill, as first-class records. Each asset gets a dedicated ledger account, and you record changes to its carrying value over time, such as depreciation, improvements, impairments, and revaluations, as **value updates**. See the [Asset object](/api-reference/asset/asset) for the full data model and the [asset endpoints](/api-reference/v1/assets/create-asset) for the API. Assets purchased with financing are usually created as part of the loan rather than on their own, via an `ASSET` loan proceed. See [equipment financing](/guides/loans/equipment-financing) and [leases](/guides/loans/leases) in the loan guide. This guide covers assets you track directly. ## Create an asset Create an asset with a `name` and an `asset_type`. A dedicated ledger account is created for it under Fixed Assets. Set an `external_id` so you can reference the asset later without storing Layer's IDs; re-sending the same `external_id` upserts the existing asset rather than creating a duplicate. For depreciable assets, set `accumulated_depreciation_account` (along with `original_value` and `useful_life_months`) so you can record depreciation against it. `asset_type` can be `RIGHT_OF_USE_ASSET`, `VEHICLE`, `EQUIPMENT`, or `GOODWILL`. All monetary values are in cents. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/assets \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "name": "Forklift", "external_id": "forklift-001", "asset_type": "EQUIPMENT", "original_value": 4000000, "useful_life_months": 60, "accumulated_depreciation_account": "ACCUMULATED_DEPRECIATION" }' ``` ## Record value changes Record changes to an asset's carrying value as **value updates**. Each value update posts a journal entry between the asset (or its accumulated depreciation account) and a `counter_account`. Identify the asset with either `asset_id` or `asset_external_id`, and give each value update its own `external_id` for linking. Value updates only affect **accrual-basis** books. Under cash accounting, depreciation, impairments, and revaluations are not recognized; see [Assets under cash accounting](#assets-under-cash-accounting) instead. | `update_type` | Effect on carrying value | Typical counter account | | - | - | - | | `DEPRECIATION_AMORTIZATION` | Decrease | Depreciation expense (`DEPRECIATION`) | | `IMPAIRMENT` | Decrease | An impairment loss expense account | | `REVALUATION_DOWN` | Decrease | An equity or loss account | | `IMPROVEMENT` | Increase | The cash or payable account that funded it | | `REVALUATION_UP` | Increase | An equity or gain account | ### Depreciation Depreciation requires the asset to have an `accumulated_depreciation_account`. Record a `DEPRECIATION_AMORTIZATION` value update each period with `counter_account` set to a depreciation expense account (the `DEPRECIATION` stable name maps to the Depreciation Expense account). Layer debits the expense and credits accumulated depreciation. The example below records one month of straight-line depreciation for a \$40,000 asset over 60 months (\$666.67): ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/assets/value-updates \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "asset_external_id": "forklift-001", "external_id": "forklift-001-depreciation-2024-02", "amount": 66667, "update_type": "DEPRECIATION_AMORTIZATION", "counter_account": "DEPRECIATION", "date": "2024-02-29T00:00:00Z" }' ``` Repeat each period (for example, monthly) for the life of the asset. ### Improvements, impairments, and revaluations Use the other `update_type` values to record one-off changes. For an **improvement**, set `counter_account` to the account that funded the work (such as `CASH`); for an **impairment** or **downward revaluation**, use `IMPAIRMENT` or `REVALUATION_DOWN`; for an increase in fair value, use `REVALUATION_UP`. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/assets/value-updates \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "asset_external_id": "forklift-001", "external_id": "forklift-001-improvement-2024-06", "amount": 50000, "update_type": "IMPROVEMENT", "counter_account": "CASH", "date": "2024-06-15T00:00:00Z" }' ``` ## Assets under cash accounting Value updates only matter for **accrual-basis** accounting. For cash-basis businesses we recommend a simpler lifecycle: * **Create the asset whenever you need it.** Unless it was created from a [loan proceed](/guides/importing-loan-data), a new asset starts with a balance of zero. * **Let real cash activity build its balance** instead of recording value updates. Post to the asset's ledger account directly: reference the account in [bill](/guides/importing-bill-ap-data) line items, or [categorize bank transactions](/api-reference/v1/categorize-bank-transaction) to it. Use the asset's `ledger_account` (returned when you create the asset) as the target account. # Bank data Source: https://docs.layerfi.com/guides/importing-bank-data **Bank transactions**, activity within your customers' business bank accounts and credit cards, can be ingested by Layer in two ways: * **From external financial institutions**, using Layer's [Plaid integration](#import-with-plaid). * **From your platform's embedded bank accounts and credit cards**, by [importing them directly](#import-embedded-accounts-directly) (including Layer's integrations with Unit and Stripe Treasury). For a complete accounting picture, you will also need to import your customers' [sales / AR data](/guides/importing-sales-ar-data). ## Import with Plaid Layer uses [Plaid](https://plaid.com/) to connect with your customers' accounts at external financial institutions to ingest data such as transactions and balances and incorporate them into their accounting. ### Using Layer's Plaid connection If your platform does not already have a Plaid integration, you can use Layer's Plaid connection to import your customers' external bank accounts and credit card data. Layer will manage all aspects of the Plaid integration on your behalf. ### Using your own Plaid connection If your platform already has an integration with Plaid, you can grant Layer access to your existing Plaid data through Plaid's [processor token functionality](https://plaid.com/docs/api/processors/). To start importing customers' bank accounts and credit cards into Layer, you can either use Layer's [prebuilt React components](/guides/embedded-components) or [build a custom Plaid account-linking experience](/guides/custom-plaid-account-linking). Both options use Layer's Plaid connection and grant Layer read-only access to the customer's bank account and credit card activity. Bank Linking Component Once your customers have connected their accounts, Layer will automatically start importing their bank account and credit card transactions. ### Creating Processor Tokens First, [link](https://plaid.com/docs/link/#link-flow-overview) a customer's bank account with Plaid as normal, obtaining an `access_token`. Next, use the `access_token` and the `account_id` for an account to create a processor token via Plaid's [/processor/token/create](https://plaid.com/docs/api/processors/#processortokencreate) endpoint. ```bash Request theme={null} curl -X POST https://sandbox.plaid.com/processor/token/create \ -H 'Content-Type: application/json' \ -d '{ "client_id": "PLAID_CLIENT_ID", "secret": "PLAID_SECRET", "access_token": "ACCESS_TOKEN", "account_id": "ACCOUNT_ID", "processor": "layer" }' ``` ```json Response theme={null} { "processor_token": "processor-sandbox-0asd1-a92nc", "request_id": "xrQNYZ7Zoh6R7gV" } ``` ### Using Processor Tokens After creating a `processor_token` for each of the customer's accounts, [update the customer's business](/api-reference/business/update) with the processor tokens to begin ingesting data from the associated accounts. ```bash Request theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "plaid_processor_tokens": [ { "processor_token": "processor-sandbox-0asd1-a92nc" } ] }' ``` Note that you must include all processor tokens you would like associated with the business. Existing processor tokens not included in the request will be removed. You can remove all processor tokens from a business by updating it with an empty list. If there is no business associated with the customer yet, you can also include processor tokens when [creating a business](/api-reference/v1/create-business). ### Refreshing Processor Tokens If the access token for a Plaid account changes, all processor tokens associated with that account are invalidated. If this occurs, create a new processor token for the account, then [update the business](/api-reference/business/update) with the updated list of processor tokens. If you need to see the processor tokens already associated with the business, call the [List Plaid Accounts](/api-reference/plaid-account/list-plaid-accounts) endpoint. ## Import embedded accounts directly If your platform provides an embedded bank account or credit card to your customers, Layer can ingest data from these accounts. There are two ways to pass embedded banking activity to Layer: * **API** - Pass bank and credit card transactions to Layer's API directly. * **Layer integrations** - Layer has direct connections with top embedded banking platforms. You can grant Layer access to pull your customers' data from these platforms on your behalf. Layer currently supports: [Unit](https://www.unit.co/) and [Stripe Treasury](https://stripe.com/treasury). ### Importing transactions via API To import bank transactions to Layer, first call the [Create Custom Account](/api-reference/v1/create-custom-account) endpoint. This endpoint creates the record for this embedded account in Layer's systems. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/custom-accounts/ \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "external_id": "ww9wwLgkrbU3jkg3J4J7ckBR3zKQV6sLPQevK", "mask": "4321", "account_name": "My custom account", "institution_name": "My custom account institution", "account_type": "DEPOSITORY", "account_subtype": "checking" }' ``` The API will respond with the created Custom Account. Next, pass the transactions that have occured in your embedded account to Layer by calling the [Import Transactions](/api-reference/v1/import-transactions) endpoint. When making this call, be sure to populate the `customAccountId` parameter in the URL with the `id` of the Custom Account you just created. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/custom-accounts/{customAccountId}/transactions \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "transactions": [ { "external_id": "custom-transaction-id-1234", "amount": 123, "direction": "CREDIT", "date": "2023-11-07T05:31:56Z", "merchant_name": "My example merchant", "merchant_category_code": "4072", "description": "Original description", "display_description": "Current description to display with details", "currency_code": "USD", "balance": 123 } ] }' ``` The API will respond with a `200` if transactions were successfully imported. Your embedded bank account and its associated transactions will now be accessible across Layer's accounting workflows, such as [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting). ### Using Layer's integrations To use Layer's embedded banking integrations with [Unit](https://www.unit.co/) and [Stripe Treasury](https://stripe.com/treasury), reach out to your Layer contact. # Bill / AP data Source: https://docs.layerfi.com/guides/importing-bill-ap-data Bills represent your customers' **accounts payable**: amounts they owe to vendors for goods or services received. Importing bills lets Layer track outstanding payables, recognize expenses, and reconcile the bank transactions that pay those bills. A typical accounts payable flow has three steps: 1. [Create a vendor](#create-a-vendor), the party the bill is owed to. 2. [Create a bill](#create-a-bill) with its line items, terms, and due date. 3. [Record a bill payment](#record-a-bill-payment) against one or more bills. Bill / AP support may need to be enabled for your platform. Reach out to your Layer contact for access. ## Create a vendor A bill must be associated with a vendor. Create one with the [Create Vendor](/api-reference/v1/create-vendor) endpoint, supplying your own `external_id` so you can reference it later without storing Layer's IDs. ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{businessId}/vendors \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "vendor-1", "company_name": "Acme Supplies Inc.", "email": "billing@acmesupplies.com", "office_phone": "555-123-4567", "address_string": "123 Vendor St, Supply City, CA 90210" }' ``` The API responds with a [Vendor](/api-reference/vendor/vendor) object. You can later look up vendors with [List Vendors](/api-reference/v1/list-vendors). ## Create a bill Create a bill with the [Create Bill](/api-reference/v1/create-bill) endpoint. Each bill references a vendor (by `vendor_id` or `vendor_external_id`), one or more `line_items`, and either a `due_at` date or `bill_terms` (one of `DUE_ON_RECEIPT`, `NET_10`, `NET_15`, `NET_30`, `NET_60`). Each line item requires a `product_name` and `unit_price` (in cents) and may include a `quantity`, `description`, discounts, sales taxes, and an `account_identifier` to control which expense account the line posts to. ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{businessId}/bills \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "vendor-bill-123", "vendor_external_id": "vendor-1", "received_at": "2024-06-01T10:11:57Z", "bill_terms": "NET_30", "reference_number": "VB-123", "memo": "Monthly office supplies", "line_items": [ { "external_id": "bill-line-item-1", "product_name": "Paper reams", "description": "Monthly office supplies", "unit_price": 1500, "quantity": 10, "discount_amount": 1000, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CA_SALES_TAX" }, "amount": 1120 } ] } ] }' ``` The API responds with a [Bill](/api-reference/bill/bill) object. The bill's `status` reflects how much has been paid (`RECEIVED`, `PARTIALLY_PAID`, `PAID`, or `VOIDED`), and `outstanding_balance` tracks what remains owed. `external_id` is your idempotency key. Re-posting a bill with the same `external_id` updates the existing bill rather than creating a duplicate. To create many bills at once, use [Batch Create Bills](/api-reference/v1/batch-create-bills). ## Record a bill payment When a customer pays a bill, record the payment so Layer can mark the bill paid and reconcile it against bank activity. For a payment made at the same time the bill is created, include a `payments` array directly in the [Create Bill](/api-reference/v1/create-bill) request. To record a payment against an existing bill, or a single payment that covers several bills, use the [Create Bill Payment](/api-reference/v1/create-bill-payment) endpoint and allocate the amount across bills with `bill_payment_allocations`. ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{businessId}/bills/bill-payments \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "bill-payment-1", "paid_at": "2024-06-15T00:00:00Z", "method": "ACH", "amount": 10000, "bill_payment_allocations": [ { "bill_external_id": "vendor-bill-123", "amount": 10000 } ] }' ``` The `method` is one of `CASH`, `CHECK`, `CREDIT_CARD`, `ACH`, `CREDIT_BALANCE`, or `OTHER`. All amounts are in cents. ## Vendor credits and refunds Layer also supports reducing payables through [vendor credits](/api-reference/vendor-credits/vendor-credit) (credits a vendor issues that can be applied to future bills) and [vendor refunds](/api-reference/vendor-refunds/vendor-refund) (money a vendor returns). See the API reference for details. ## Expenses An expense is a type of bill for a purchase paid immediately. Use [Create expense](/api-reference/v1/create-expense) when you want to record the purchase and payment together. See the [Expense object](/api-reference/bill/expense) for details. # Overview Source: https://docs.layerfi.com/guides/importing-financial-data-overview Once you have onboarded one of your customers to Layer by creating a [Business](/api-reference/business/business), you can start importing their financial data. The more complete the data you send, the more accurate your customers' books, reports, and reconciliations will be. Layer supports several types of financial data: | Data type | What it covers | How it's imported | | - | - | - | | [Bank data](/guides/importing-bank-data) | Bank account and credit card activity | Plaid, or directly from your platform's embedded accounts | | [Sales / AR data](/guides/importing-sales-ar-data) | Invoices, payments, and payouts (accounts receivable) | Invoice & Payout APIs | | [Bill / AP data](/guides/importing-bill-ap-data) | Vendor bills and the payments made against them (accounts payable) | Bill API | | [Payroll data](/guides/importing-payroll-data) | Wages, taxes, and related payroll activity | Check Payroll integration | | [Loan data](/guides/importing-loan-data) | Loans, lines of credit, and their repayments | Custom accounts & categorization | For a complete accounting picture, most platforms import **bank data** and **sales / AR data** at a minimum. **Bill / AP**, **payroll**, and **loan** data add further detail depending on your customers' needs. Bill / AP, payroll, and loan support may need to be enabled for your platform. Reach out to your Layer contact for access. # Loan data Source: https://docs.layerfi.com/guides/importing-loan-data Layer models loans as first-class financial events. Each loan has a dedicated ledger account, one or more **proceeds** (the funds or assets received when the loan is drawn), and **payments** split into principal, interest, and fee portions. See the [Loan object](/api-reference/loan/loan) for the full data model and the [loan endpoints](/api-reference/v1/loans/create-loan) for the API. Every loan has a `loan_type`. Follow the guide for the type you're importing: | Loan type | `loan_type` | | - | - | | [Term loans](/guides/loans/term-loans) | `TERM_LOAN` | | [Merchant cash advances](/guides/loans/merchant-cash-advances) | `MCA` | | [Flex loans](/guides/loans/flex-loans) | `FLEX_LOAN` | | [Lines of credit](/guides/loans/lines-of-credit) | `LINE_OF_CREDIT` | | [Leases](/guides/loans/leases) | `LEASE` | | [Equipment financing](/guides/loans/equipment-financing) | `EQUIPMENT_FINANCING` | Importing a loan that is already partially repaid, without the full history of proceeds and payments? See [Backfilling existing loans](/guides/loans/backfilling-existing-loans). Loan support may need to be enabled for your platform. Reach out to your Layer contact for access. # Payroll data Source: https://docs.layerfi.com/guides/importing-payroll-data Payroll data covers the wages, employer taxes, and related liabilities your customers incur when paying their employees. Importing it lets Layer reflect payroll expense and the associated cash movement in your customers' books and reports. Payroll support may need to be enabled for your platform. Reach out to your Layer contact for access. ## How payroll data gets into Layer Layer ingests payroll through an integration with a payroll provider rather than a manual import. Once connected, payroll runs flow into Layer automatically and post to the appropriate payroll expense and liability accounts. Layer integrates with the following payroll providers: Sync payroll from Check embedded payroll. Sync payroll from Salsa embedded payroll. Sync payroll from Gusto Embedded. Establishing a connection links a Layer business to its company in the payroll provider and authorizes the integration. Visit the integration page of your chosen provider above for guidance on the setup process. If you use a payroll provider that isn't listed here, reach out to your Layer contact to discuss options. # Sales / AR data Source: https://docs.layerfi.com/guides/importing-sales-ar-data Layer ingests revenue through **Invoices & Payments** and **Payouts**. This includes in-person sales made through a point of sale system, invoices sent through your software, ecommerce sales, and any other type of accounts receivable activity. For a complete accounting picture, you will also need to import your customers' [bank data](/guides/importing-bank-data). After a historical sync, follow [Validate a sales data backfill](/guides/validating-sales-data-backfills) to compare invoice and payment totals between your system and Layer. ## Invoices and payments Invoices and payments represent revenue collected by your business customers. This can be in-person sales made through a point of sale system, invoices sent through your software, ecommerce sales, or any other type of accounts receivable activity. To import invoices, make a call to the [Create Invoice](/api-reference/invoice/create) endpoint. This endpoint takes in the data on the sale your customer made, what was sold, any associated taxes, and how the sale was paid for. ### Invoices without payments Invoices can be created without any payments associated with them. Payments towards the invoice can then be recorded later on using the [Record an Invoice Payment](/api-reference/v1/record-a-payment) endpoint. ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/{business_id}/invoices \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "019234", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "invoice_number": "1", "customer_external_id": "customer-john-doe", "line_items": [ { "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": 2, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ] }, { "product": "Full drain cleaning service", "unit_price": 25000, "quantity": 1 } ], "additional_discount": 250 }' ``` The API will respond with an [Invoice](/api-reference/invoice/invoice) object. ```json Response theme={null} { "data": { "type": "Invoice", "id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "external_id": "019234", "status": "SENT", "sent_at": "2024-04-02T09:02:00Z", "due_at": "2023-04-02T09:02:00Z", "paid_at": null, "voided_at": null, "invoice_number": "1", "customer": { "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "customer-john-doe", "individual_name": null, "company_name": null, "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE" }, "line_items": [ { "id": "e6a491dd-9c22-4403-a54f-32d741a7ec67", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": "2.00", "subtotal": 2598, "discount_amount": 0, "sales_taxes_total": 218, "sales_taxes": [ { "tax_account": { "type": "Tax_Name", "name": "CALIFORNIA_VAT" }, "amount": 218 } ], "total_amount": 2816 }, { "id": "44f06385-3ef5-4517-8095-eeedaf2054ab", "invoice_id": "6d0c298f-3e4e-4538-9a71-1d5359c22f71", "account_identifier": null, "description": null, "product": "Full drain cleaning service", "unit_price": 25000, "quantity": "1.00", "subtotal": 25000, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 25000 } ], "subtotal": 27598, "additional_discount": 250, "additional_sales_taxes_total": 0, "tips": 0, "tips_account": { "type": "StableName", "stable_name": "TIPS_REVENUE" }, "total_amount": 27566, "outstanding_balance": 27566, "payment_allocations": [], "imported_at": "2024-04-19T02:23:59.902537Z", "updated_at": null, "transaction_tags": [] } } ``` ### Invoices with payments For instances where invoices are immediately paid, such as when using a point of sale device for in-person sales or online merchandise sales, you can also include payment information directly in the creation of the invoice. This looks very similar to the above example with the addition of payment information. ```bash Request theme={null} curl -X POST https://sandbox.layerfi.com/v1/businesses/863ed926-e30d-40f4-8e7e-b0d5387ce4fb/invoices \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "external_id": "234988", "sent_at": "2024-05-12T14:13:07Z", "due_at": "2024-06-12T14:13:07Z", "invoice_number": "2", "customer_external_id": "customer-john-doe", "line_items": [ { "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": 1, "sales_taxes": [ { "amount": 114 } ] }, { "product": "Cleanout snake", "unit_price": 18000, "quantity": 1 } ], "additional_sales_taxes": [ { "amount": 1291 } ], "payments": [ { "external_id": "239872", "method": "CREDIT_CARD", "amount": 20704, "processor": "MY_PROCESSOR" } ] }' ``` In this case, the API will respond with the same created invoice, but with the invoice marked as fully or partially paid and the payment information included. ```json Response theme={null} { "data": { "type": "Invoice", "id": "d01c9839-0378-4d44-b409-a0ae1e5dbb59", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "external_id": "234988", "status": "PAID", "sent_at": "2024-05-12T14:13:07Z", "due_at": "2024-06-12T14:13:07Z", "paid_at": "2024-04-19T02:24:00.009658Z", "voided_at": null, "invoice_number": "2", "customer": { "id": "a4c38874-8c01-4986-b8d0-4f159a52dd39", "external_id": "customer-john-doe", "individual_name": null, "company_name": null, "email": null, "mobile_phone": null, "office_phone": null, "address_string": null, "notes": null, "status": "ACTIVE" }, "line_items": [ { "id": "fd60aa16-a0a6-40de-a814-b01836acfd36", "invoice_id": "d01c9839-0378-4d44-b409-a0ae1e5dbb59", "account_identifier": null, "description": null, "product": "Cleaner Solution Pro", "unit_price": 1299, "quantity": "1.00", "subtotal": 1299, "discount_amount": 0, "sales_taxes_total": 114, "sales_taxes": [ { "tax_account": { "type": "AccountId", "id": "ba1a5e91-d04a-4c67-919e-f09a20d6e151" }, "amount": 114 } ], "total_amount": 1413 }, { "id": "4dd7708a-cad4-46e6-b5ff-34248a0b141e", "invoice_id": "d01c9839-0378-4d44-b409-a0ae1e5dbb59", "account_identifier": null, "description": null, "product": "Cleanout snake", "unit_price": 18000, "quantity": "1.00", "subtotal": 18000, "discount_amount": 0, "sales_taxes_total": 0, "total_amount": 18000 } ], "subtotal": 19299, "additional_discount": 0, "additional_sales_taxes_total": 1291, "additional_sales_taxes": [ { "tax_account": { "type": "AccountId", "id": "ba1a5e91-d04a-4c67-919e-f09a20d6e151" }, "amount": 1291 } ], "tips": 0, "total_amount": 20704, "outstanding_balance": 0, "payment_allocations": [ { "invoice_id": "d01c9839-0378-4d44-b409-a0ae1e5dbb59", "payment_id": "4d769e05-a101-4a16-8de5-6c37fbcec088", "amount": 20704, "transaction_tags": [] } ], "imported_at": "2024-04-19T02:24:00.009658Z", "updated_at": null, "transaction_tags": [] } } ``` ## Payouts A [Payout](/api-reference/customer-payouts/payout) represents a processor deposit that moves funds from a payment processor, such as Stripe, to one of your business customers' bank accounts. Payouts are used to reconcile bank transactions that represent processor deposits with the underlying processor activity they contain, such as [invoice payments](/api-reference/invoice/payments) and [refunds](/api-reference/refunds/refund). Matching bank transactions to payouts prevents revenue from being double-counted: first from the invoice payment, and second from categorizing the bank transaction as revenue. ### Importing payouts Create payouts with the [Create Payout](/api-reference/v1/create-payout) endpoint, or use [Bulk Create Payouts](/api-reference/v1/bulk-create-payouts) to create or update multiple payouts in a single request. If `processor` is set (e.g. `STRIPE`), every linked payment and refund must also use this `processor` value. Use the [Update Payout](/api-reference/v1/update-payout) endpoint to modify a payout after it has been created. `external_id` is your idempotency key. Re-posting the same `external_id` returns the existing payout unchanged. The bulk endpoint uses upsert semantics: if a payout with the same `external_id` already exists, it will be updated; otherwise, a new payout is created. ### Linking payments and refunds Attach existing invoice payments and refunds by Layer ID or your external ID: ```json theme={null} { "payments": [ { "invoice_payment_id": "" } ], "refunds": [ { "refund_payment_id": "" } ] } ``` ### Other transactions Use `other_transactions` for line items that are not represented as invoice payments or refunds (e.g. Merchant Cash Advance fees, tax withholding, or other fees). ### Stripe Instant Payouts Instant payouts from Stripe should be imported as two [Payout](/api-reference/customer-payouts/payout) objects in Layer: one payout for the instant cash movement, and one following payout that reconciles the itemized payment activity when Stripe includes it in a later payout. Normal Stripe payouts are itemized around the specific transactions included in the payout. Instant payouts are amount-based, so Layer represents the instant transfer separately from the later itemized payout that contains the payment. #### Process Steps The expected process steps are: 1. Import the invoice and payment. 2. Create the instant payout with no payments or refunds, plus one `CREDIT` transaction to `STRIPE_CLEARING`. 3. Create the following payout with the original payment attached, plus one `DEBIT` transaction from `STRIPE_CLEARING`. After both payout objects are imported, the `STRIPE_CLEARING` entries will offset each other. #### 1. Import the payment First, import the sale and its Stripe payment. In the example payout below, there is an invoice for `12500` cents, with one credit card payment for the same amount and no fee. ```json theme={null} { "external_id": "invoice-instant-payout", "sent_at": "2023-12-05T00:00:00Z", "due_at": "2023-12-05T00:00:00Z", "customer_external_id": "customer-instant-payout", "line_items": [ { "description": "Test Service", "quantity": 1, "unit_price": 12500, "product": "Test Product" } ], "payments": [ { "external_id": "payment-instant-payout", "amount": 12500, "fee": 0, "processor": "STRIPE", "method": "CREDIT_CARD" } ] } ``` #### 2. Create the instant payout Create a payout for the instant transfer itself. Note the example payout below has the amount that Stripe deposited, but does not yet attach the invoice payment. ```json theme={null} { "external_id": "payout-instant", "paid_out_amount": 12500, "fee": 0, "processor": "STRIPE", "completed_at": "2023-12-05T00:00:00Z", "payments": [], "refunds": [], "other_transactions": [ { "amount": 12500, "direction": "CREDIT", "account": { "type": "StableName", "stable_name": "STRIPE_CLEARING" }, "description": "Stripe payout payout-instant", "external_id": "pbt-payout-instant-funding" } ] } ``` #### 3. Create the following payout When Stripe later reports the itemized payout that includes the payment, create a second payout. In the example payout below, the `paid_out_amount` of `0`, references the invoice payment created earlier and includes the opposite `STRIPE_CLEARING` transaction. ```json theme={null} { "external_id": "payout-following", "paid_out_amount": 0, "fee": 0, "processor": "STRIPE", "completed_at": "2023-12-06T00:00:00Z", "payments": [ { "invoice_payment_id": "" } ], "refunds": [], "other_transactions": [ { "amount": 12500, "direction": "DEBIT", "account": { "type": "StableName", "stable_name": "STRIPE_CLEARING" }, "description": "Stripe payout payout-instant", "external_id": "pbt-payout-instant-reconciliation" } ] } ``` The example now has both payouts present, with the following payout including the original payment. The `STRIPE_CLEARING` account will net to zero after the `CREDIT` and `DEBIT` transactions are applied. # Key concepts Source: https://docs.layerfi.com/guides/key-concepts The core model behind Layer: platforms, businesses, and the general ledger. This page covers the concepts you'll encounter throughout Layer's documentation. If you'd rather start building, head to the [Quickstart](/guides/quickstart). ## Platforms and businesses Layer uses two key terms to describe who's who in an integration: * **Platforms** are Layer's direct customers, software companies that integrate Layer to offer accounting features. You are a Platform. * **Businesses** are your end users, the SMBs that use your product and the embedded accounting capabilities Layer powers. A single Platform serves many Businesses, each with its own isolated accounting data. ## The general ledger When you onboard a Business, Layer provisions an associated **General Ledger**, the double-entry system of record where all of that Business's accounting data lives. Every transaction, invoice, bill, and journal entry flows into the general ledger, which is what makes real-time financial reporting possible without manual bookkeeping. ## Ways to integrate There are two ways to surface accounting features in your product. Either can deliver any capability, and most platforms use a mix. * **Embedded Components**: Layer's suite of pre-built, white-labeled React UI components you drop into your frontend for the fastest path to launch. See [Embedding UI components](/guides/embedded-components). * **API**: build your own accounting UIs directly on top of the Layer API for full control of the experience. See the [API Reference](/api-reference/business/business). ## Accounting packages Layer supports everything from a simple cashflow visualization to a complete monthly bookkeeping service. The right set of features depends on your product and your SMBs; your Layer contact can help you choose. Common packages: * **Core Accounting**: cash-based accounting to track profitability and prepare for taxes. SMBs import revenue and bank data, categorize and reconcile transactions, upload receipts, and view easy-to-understand profitability reports. * **Advanced Accounting**: a fuller experience supporting both cash and accrual basis, plus richer reports like the Balance Sheet and Cash Flow Statement. SMBs can manage the general ledger directly. * **Full-Service Bookkeeping**: Layer's bookkeeping team organizes transactions and closes the books each month. SMBs only answer questions about their activity; Layer handles the rest. ## Next steps Authenticate, onboard a business, and surface accounting in your product. Create your first business and connect its data. # Backfilling existing loans Source: https://docs.layerfi.com/guides/loans/backfilling-existing-loans Sometimes a loan enters Layer mid-life: the business took the financing before joining your platform, or your integration discovers the loan only when a repayment appears. Layer handles this with a loan **opening balance**: the portion of the loan's outstanding principal that its recorded history does not explain. It is journaled against Opening Balance Equity, so it puts the debt on the books without fabricating a cash disbursement, and repayments recorded from then on walk the balance down to zero. You do not compute it. Layer derives it, anchored on the date the business activated on Layer, because that is when its books begin. ## Send the loan's whole history If you can send every proceed and payment back to the loan's origination, do that and send no balance at all. * If none of that history predates the business's activation date, the recorded events explain the loan on their own and there is no opening balance. * If some of it does, Layer rolls that part up into an opening balance dated at the activation date. Events on or after activation post normally on top of it. Either way you send the same thing: everything you have, in whatever order it arrives. For long payment histories, use the [bulk payments endpoint](/api-reference/v1/loans/bulk-create-loan-payments) to send them in batches rather than one request per payment. ## When you cannot reach the start of the loan If your data begins partway through the loan's life, pass `reported_balance` when you [create](/api-reference/v1/loans/create-loan) or [update](/api-reference/v1/loans/update-loan) the loan, and send every event from that point on. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "MCA", "external_id": "mca-001", "display_name": "Working capital advance", "origination_date": "2024-03-01", "original_principal": 2000000, "fee_percentage": "15", "reported_balance": { "balance": 1200000, "at": "2024-06-01T00:00:00-04:00" } }' ``` Set `at` to the earliest date you can state the balance for, not the most recent. It marks where your knowledge of the loan begins, and events dated before it are rejected, so an `at` that is later than necessary shuts out history you could otherwise record. * If `at` is on or before the business's activation date, Layer rolls the balance forward through any events between the two and dates the opening balance at activation. * If `at` is after activation, the opening balance is dated at `at`. * `at` cannot precede the loan's `origination_date`, and it cannot postdate history already recorded on the loan. ## Recording earlier history later If you later obtain records from before your current `at`, re-send `reported_balance` with the earlier date and the balance as of that date, then send the events. The assertion is the boundary, so the boundary has to move before the earlier events will be accepted. Once your history reaches the loan's origination, retract the assertion by sending `reported_balance` as `null` on an update, and let the recorded events speak for themselves. Simply omitting `reported_balance` does not retract it, and neither does re-sending the loan through `POST /loans`. After a retraction, Layer re-derives the opening balance from the loan's recorded history alone: if the history predating the activation date leaves principal outstanding, an opening balance remains, now dated at activation; if the loan was already repaid by then, none does. Loan responses include the active `opening_balance`, so you can always read back what Layer currently derives. # Equipment financing Source: https://docs.layerfi.com/guides/loans/equipment-financing Equipment financing funds the purchase of equipment. Create the loan with at least one `ASSET` [proceed](/api-reference/loan/loan#loan-proceed-object) that creates (or links) the financed [asset](/api-reference/asset/asset); the API does not require it, but in practice there should be one. If the financing covers more than the equipment's cost, add a cash `DISBURSEMENT` proceed for the remainder. ## Step 1: Create the loan Create a loan with `loan_type` set to `EQUIPMENT_FINANCING`, `original_principal`, and `loan_term_months`. In the example below, a \$42,000 loan funds a \$40,000 forklift (an `ASSET` proceed that creates the asset) with the remaining \$2,000 disbursed as cash. Giving the new asset an `external_id` lets you record its depreciation later without storing Layer's IDs. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "EQUIPMENT_FINANCING", "external_id": "equip-001", "display_name": "Forklift financing", "origination_date": "2024-01-15", "original_principal": 4200000, "loan_term_months": 48, "proceeds": [ { "loan_proceed_type": "ASSET", "amount": 4000000, "date": "2024-01-15", "asset": { "new_asset": { "name": "Forklift", "external_id": "equip-001-forklift", "asset_type": "EQUIPMENT", "original_value": 4000000, "useful_life_months": 60, "accumulated_depreciation_account": "ACCUMULATED_DEPRECIATION" } } }, { "loan_proceed_type": "DISBURSEMENT", "amount": 200000, "date": "2024-01-15", "method": "ACH" } ] }' ``` Track the financed asset's depreciation over time with [asset value updates](/api-reference/asset/asset#asset-value-update-object), referencing the asset by its `asset_external_id` (for example, `equip-001-forklift`). ## Step 2: Record repayments Equipment financing repayments work exactly like [term loan repayments](/guides/loans/term-loans#step-2-record-repayments): each is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `INTEREST`, and if you have an amortization schedule we recommend pre-creating the installments with `defer_posting` set to `true`. # Flex loans Source: https://docs.layerfi.com/guides/loans/flex-loans A flex loan is a business term loan: the business borrows a fixed amount and repays it, plus a fixed fee, over a set period. Repayment is collected automatically as a percentage of the business's sales (the *repayment rate*), and each period has a *minimum payment*. If the amount withheld from sales doesn't meet the minimum by the end of a period, the remainder is debited from the business's bank account. The sales-withheld portion of a flex loan repayment works the same way as a [merchant cash advance](/guides/loans/merchant-cash-advances). The difference is that a flex loan is a loan with a repayment term and a minimum payment, so it can also be repaid by direct bank debits. ## Step 1: Create the loan Create a loan with `loan_type` set to `FLEX_LOAN`, `original_principal` set to the financed amount, and `fee_percentage` set to the fixed fee. Disburse the full amount up front with a single `DISBURSEMENT` [proceed](/api-reference/loan/loan#loan-proceed-object). Set an `external_id` so you can reference the loan later without storing Layer's IDs. The `fee_percentage` is the fixed fee expressed as a percentage (for example, `"15"` for a 15% fee on a \$20,000 loan). Do not add the fee to `original_principal` or to the disbursement proceed. Both should be the amount actually financed (\$20,000.00 here), not the \$23,000.00 the business will repay. Layer adds the fee to each repayment from `fee_percentage`, so bundling it in overstates the loan balance and the fee never reaches an expense account. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "FLEX_LOAN", "external_id": "flex-001", "display_name": "Flex loan", "origination_date": "2024-03-01", "original_principal": 2000000, "fee_percentage": "15", "proceeds": [ { "loan_proceed_type": "DISBURSEMENT", "amount": 2000000, "date": "2024-03-01", "method": "ACH" } ] }' ``` ## Step 2: Record repayments Each repayment is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `FEE`. As with MCAs, you can omit `splits` and Layer derives them from the loan's `fee_percentage` (`principal = amount / (1 + fee_percentage / 100)`, fee = remainder); provide explicit `splits` to override. ### Repayments withheld from sales When a repayment is withheld from the business's sales, record it exactly as you would for a merchant cash advance: attach it to the [payout](/api-reference/customer-payouts/payout) it was deducted from, or record it as a `LOAN_REPAYMENT` fee on the [invoice payment](/api-reference/v1/record-a-payment) it was withheld from. See [Record repayments](/guides/loans/merchant-cash-advances#step-2-record-repayments) in the MCA guide for both flows. ### Minimum payments debited from the bank When a period's sales don't meet the minimum payment and the difference is debited directly from the business's bank account, record that as a standalone [loan payment](/api-reference/v1/loans/create-loan-payment): ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans/payments \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_external_id": "flex-001", "external_id": "flex-001-minimum-2024-03-31", "amount": 115000, "date": "2024-03-31", "method": "ACH" }' ``` # Leases Source: https://docs.layerfi.com/guides/loans/leases A lease is recorded over a fixed term and, in practice, recognizes a **right-of-use asset**. Create the loan with at least one `ASSET` [proceed](/api-reference/loan/loan#loan-proceed-object) that creates (or links) the right-of-use [asset](/api-reference/asset/asset); the API does not require it, but a lease should have one. If the financing exceeds the asset's value, add a cash `DISBURSEMENT` proceed for the remainder. ## Step 1: Create the lease Create a loan with `loan_type` set to `LEASE`, `original_principal`, and `loan_term_months`. Include an `ASSET` proceed whose `new_asset` has `asset_type` `RIGHT_OF_USE_ASSET`. To attach an **existing** asset instead, set the proceed's `asset` to `{ "id": "" }` or `{ "external_id": "" }`. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "LEASE", "external_id": "lease-001", "display_name": "Office equipment lease", "origination_date": "2024-01-15", "original_principal": 3000000, "loan_term_months": 36, "proceeds": [ { "loan_proceed_type": "ASSET", "amount": 3000000, "date": "2024-01-15", "asset": { "new_asset": { "name": "Office equipment (right-of-use)", "external_id": "lease-001-rou", "asset_type": "RIGHT_OF_USE_ASSET", "original_value": 3000000, "useful_life_months": 36 } } } ] }' ``` ## Step 2: Record repayments Lease payments work exactly like [term loan repayments](/guides/loans/term-loans#step-2-record-repayments): each is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `INTEREST`, and if you have an amortization schedule we recommend pre-creating the installments with `defer_posting` set to `true`. # Lines of credit Source: https://docs.layerfi.com/guides/loans/lines-of-credit A line of credit is **revolving**: the business can draw funds up to a `credit_limit`, repay, and draw again. Model it as a single long-lived loan, record each draw as a [proceed](/api-reference/loan/loan#loan-proceed-object), and record repayments as loan payments. ## Step 1: Create the line of credit Create a loan with `loan_type` set to `LINE_OF_CREDIT` and a `credit_limit`. Set an `external_id` so you can reference it later. You can include the first draw in `proceeds` now, or add draws later (next step). ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "LINE_OF_CREDIT", "external_id": "loc-001", "display_name": "Revolving credit line", "origination_date": "2024-01-15", "credit_limit": 10000000 }' ``` ## Step 2: Record draws Each time the business draws on the line, add a `DISBURSEMENT` proceed with the [Create a loan proceed](/api-reference/v1/loans/create-loan-proceed) endpoint, using the loan's `id` from the create response. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans/{loanId}/proceeds \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_proceed_type": "DISBURSEMENT", "external_id": "loc-001-draw-1", "amount": 2500000, "date": "2024-02-01", "method": "ACH" }' ``` ## Step 3: Record repayments Each repayment is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `INTEREST` (explicit `splits` are required). Because draws and repayments on a line of credit are irregular, record each payment as it happens rather than pre-creating them. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans/payments \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_external_id": "loc-001", "external_id": "loc-001-payment-2024-03-01", "amount": 500000, "date": "2024-03-01", "splits": [ { "split_type": "PRINCIPAL", "amount": 450000 }, { "split_type": "INTEREST", "amount": 50000 } ] }' ``` # Merchant cash advances (MCAs) Source: https://docs.layerfi.com/guides/loans/merchant-cash-advances A merchant cash advance is an up-front lump sum that the business repays out of its incoming sales, plus a fixed fee. In Layer you model an MCA in two parts: **create the loan** (fully disbursed up front), then **record repayments** as they are withheld from sales. Creating an advance that is already partially repaid, without the full repayment history? Pass `reported_balance` instead of `proceeds` when creating the loan. See [Backfilling existing loans](/guides/loans/backfilling-existing-loans). ## Step 1: Create the loan Create a loan with `loan_type` set to `MCA`, and disburse the full advance immediately by including a single `DISBURSEMENT` [proceed](/api-reference/loan/loan#loan-proceed-object) for the whole amount. Set an `external_id` so you can reference the loan later without storing Layer's IDs. The `fee_percentage` is the fixed fee expressed as a percentage (for example, `"15"` for a 15% fee on a \$20,000 advance). Do not add the fee to `original_principal` or to the disbursement proceed. Both should be the amount actually advanced (\$20,000.00 here), not the \$23,000.00 the business will repay. Layer adds the fee to each repayment from `fee_percentage`, so bundling it in overstates the loan balance and the fee never reaches an expense account. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "MCA", "external_id": "mca-001", "display_name": "Working capital advance", "origination_date": "2024-03-01", "original_principal": 2000000, "fee_percentage": "15", "proceeds": [ { "loan_proceed_type": "DISBURSEMENT", "amount": 2000000, "date": "2024-03-01", "method": "ACH" } ] }' ``` ### If the advance is disbursed through a payout Some providers deposit the advance in a payout rather than as a separate transfer, sometimes bundled with that period's sales. In that case omit `proceeds` when creating the loan and record the disbursement separately with [Create a loan proceed](/api-reference/v1/loans/create-loan-proceed), giving it an `external_id` you can reference. Then include it in the payout via `loan_proceeds`. The proceed is money in, so it increases `paid_out_amount`. Here \$20,000.00 of advance was deposited alongside \$1,000.00 of sales: ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/payouts \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "external_id": "payout-2024-03-01", "paid_out_amount": 2100000, "fee": 0, "completed_at": "2024-03-01T23:00:00Z", "payments": [ { "invoice_payment_external_id": "card-sales-2024-03-01", "amount": 100000 } ], "loan_proceeds": [ { "loan_proceed_external_id": "mca-001-disbursement" } ] }' ``` Only `DISBURSEMENT` proceeds can be paid out; asset proceeds finance property rather than cash and are rejected. Reference each proceed at most once per payout. ## Step 2: Record repayments MCA repayments are typically withheld from the business's incoming sales, so each repayment reduces the outstanding principal and includes a portion of the fee. Each repayment is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `FEE`. For MCAs you can omit the payment's `splits` and Layer derives them from the loan's `fee_percentage` (`principal = amount / (1 + fee_percentage / 100)`, fee = remainder); provide explicit `splits` to override. How you create those loan payments depends on the granularity of your data. ### If you have payment-level granularity If you know how much was withheld for each individual sale, attach the repayment to that [invoice payment](/api-reference/invoice/payments) as a `LOAN_REPAYMENT` additional fee when you [record the payment](/api-reference/v1/record-a-payment). Layer creates the linked loan payment and ties the two together. In the example below, a customer pays a \$1,150.00 invoice and the MCA provider withholds \$150.00 of it to repay the advance, so the business nets \$1,000.00. Because the loan is an MCA, `splits` are omitted and Layer derives the principal and fee from the loan's `fee_percentage`. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/invoices/payments \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "paid_at": "2024-03-15T12:00:00Z", "method": "ACH", "amount": 115000, "invoice_payments": [ { "invoice_external_id": "invoice-789", "amount": 115000 } ], "additional_fees": [ { "type": "LOAN_REPAYMENT", "loan_payment": { "loan_external_id": "mca-001", "amount": 15000, "date": "2024-03-15" } } ] }' ``` ### If you have payout-level granularity If you only know repayment totals at the payout level, create the loan payment(s) directly with [Create a loan payment](/api-reference/v1/loans/create-loan-payment), then reference them when you [create the payout](/api-reference/v1/create-payout) they were deducted from. First, create the loan payment with an `external_id` you can reference. As above, `splits` are omitted so Layer derives the principal and fee from the loan's `fee_percentage`: ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans/payments \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_external_id": "mca-001", "external_id": "mca-001-payment-2024-03-15", "amount": 115000, "date": "2024-03-15" }' ``` Then reference the loan payment(s) in the [payout](/api-reference/customer-payouts/payout) they were deducted from via `loan_payments`. The MCA repayment reduces the amount deposited: here \$5,000.00 of sales were collected and \$1,150.00 was withheld for the advance, so `paid_out_amount` is \$3,850.00. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/payouts \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "external_id": "payout-2024-03-15", "paid_out_amount": 385000, "fee": 0, "completed_at": "2024-03-15T23:00:00Z", "payments": [ { "invoice_payment_external_id": "card-sales-2024-03-15", "amount": 500000 } ], "loan_payments": [ { "loan_payment_external_id": "mca-001-payment-2024-03-15" } ] }' ``` # Term loans Source: https://docs.layerfi.com/guides/loans/term-loans A term loan is a fixed amount borrowed up front and repaid over a set term in scheduled installments of principal and interest. Term loans have no transaction feed, so you provide the loan and every repayment through the API. ## Step 1: Create the loan Create a loan with `loan_type` set to `TERM_LOAN` and disburse the full amount up front with a single `DISBURSEMENT` [proceed](/api-reference/loan/loan#loan-proceed-object). Set `loan_term_months` and an `external_id` so you can reference the loan later without storing Layer's IDs. ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_type": "TERM_LOAN", "external_id": "term-001", "display_name": "Equipment term loan", "origination_date": "2024-01-15", "original_principal": 5000000, "loan_term_months": 36, "proceeds": [ { "loan_proceed_type": "DISBURSEMENT", "amount": 5000000, "date": "2024-01-15", "method": "ACH" } ] }' ``` ## Step 2: Record repayments Each repayment is a [loan payment](/api-reference/loan/loan#loan-payment-object) split into `PRINCIPAL` and `INTEREST`. Unlike MCAs and flex loans, term loans have no `fee_percentage` to derive from, so every loan payment must include explicit `splits`. The interest portion posts to `INTEREST_EXPENSE` by default; override it with the split's `account_identifier`. ### Pre-create scheduled payments (recommended) If you have an amortization schedule, we recommend creating the future payments up front with `defer_posting` set to `true`. A deferred payment is recorded immediately but is not posted to the ledger until its `date` arrives (or it is paid out), so the books stay accurate as each installment comes due without you having to call back every month. Create one loan payment per scheduled installment: ```bash Request theme={null} curl --request POST \ --url https://sandbox.layerfi.com/v1/businesses/{businessId}/loans/payments \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "loan_external_id": "term-001", "external_id": "term-001-2024-02-15", "amount": 150000, "date": "2024-02-15", "defer_posting": true, "splits": [ { "split_type": "PRINCIPAL", "amount": 135000 }, { "split_type": "INTEREST", "amount": 15000 } ] }' ``` ### Record payments as they happen If you don't have a schedule, create each loan payment when the repayment occurs using the same call with `defer_posting` omitted (it defaults to `false`), so the payment posts to the ledger immediately. # Quickstart Source: https://docs.layerfi.com/guides/quickstart Authenticate, onboard a business, and surface accounting in your product. This guide walks you through the core path to offering accounting in your product with Layer: authenticate, onboard a business, pass in financial data, and surface it back to your users. For the concepts behind these steps, see [Key concepts](/guides/key-concepts). ## Prerequisites Before getting started with Layer's API, you will need: * A Layer account. Reach out to your Layer contact or [contact our team](https://www.layerfi.com/contact). * Client credentials (`client_id` and `client_secret`) provided by Layer. ## Environments Layer provides two environments for development and production use: | Environment | Base URL | OAuth Scope | | - | - | - | | **Sandbox** | `https://sandbox.layerfi.com` | `https://sandbox.layerfi.com/sandbox` | | **Production** | `https://api.layerfi.com` | `https://api.layerfi.com/production` | Use sandbox for development and testing. All examples in this guide use the sandbox environment. Layer uses OAuth2's client credentials flow to authenticate API clients. Calls to the Layer API require a bearer access token. To receive one, provide your `client_id` and `client_secret` in the body of a POST request to Layer's authorization server. ```bash cURL theme={null} curl -X POST https://auth.layerfi.com/oauth2/token \ -u : \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "scope=https://sandbox.layerfi.com/sandbox" \ --data-urlencode "client_id=" ``` ```python Python theme={null} import requests from requests.auth import HTTPBasicAuth response = requests.post( "https://auth.layerfi.com/oauth2/token", auth=HTTPBasicAuth("", ""), headers={"Content-Type": "application/x-www-form-urlencoded"}, data={ "grant_type": "client_credentials", "scope": "https://sandbox.layerfi.com/sandbox", "client_id": "" } ) token_data = response.json() access_token = token_data["access_token"] ``` ```javascript Node.js theme={null} const axios = require('axios'); const getAccessToken = async () => { const response = await axios.post( 'https://auth.layerfi.com/oauth2/token', new URLSearchParams({ grant_type: 'client_credentials', scope: 'https://sandbox.layerfi.com/sandbox', client_id: '' }), { auth: { username: '', password: '' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); return response.data.access_token; }; ``` The authorization server will respond with your granted access token: ```json theme={null} { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` Extract the `access_token` value from the response. You'll use this in the `Authorization` header for all API requests. Use the access token to make a request to the API by including it as a Bearer token in the authorization header. ```bash cURL theme={null} curl https://sandbox.layerfi.com/whoami \ -H "Authorization: Bearer " ``` ```python Python theme={null} import requests response = requests.get( "https://sandbox.layerfi.com/whoami", headers={"Authorization": f"Bearer {access_token}"} ) print(response.json()) ``` ```javascript Node.js theme={null} const axios = require('axios'); const response = await axios.get( 'https://sandbox.layerfi.com/whoami', { headers: { 'Authorization': `Bearer ${accessToken}` } } ); console.log(response.data); ``` The API will respond with your client name and client id: ```json theme={null} { "data":{ "type":"whoami", "clientName":"Layer Example", "clientId":"018f1657-dc66-7482-917b-c0c0e532f52b" } } ``` Access tokens expire after 1 hour. To refresh your access token, make another call to Layer's authorization endpoint with your `client_id` and `client_secret`. We recommend refreshing tokens for new sets of requests rather than persisting access tokens. Each of your SMB customers is represented in Layer as a `Business`. Creating one also provisions its `General Ledger`, where all accounting data is stored. See [Onboarding a Business](/guides/business-onboarding) for the full flow, then [create a business](/api-reference/v1/create-business) via the API. Pass your customers' financial activity to Layer so it can be categorized, reconciled, and reported on. * [Connect bank accounts and import transactions](/guides/importing-bank-data) * [Import invoices and revenue data](/guides/importing-sales-ar-data) Choose how to display accounting features. Either method can deliver any capability, and you can mix them. * **Embedded Components**: drop in Layer's pre-built React UI. See [Embedding UI components](/guides/embedded-components). * **API**: build your own UX directly on the [Layer API](/api-reference/business/business). ## Next steps Understand platforms, businesses, and the general ledger. Add Layer's pre-built components to your frontend. Create your first business and connect its data. Give AI agents access to Layer via Model Context Protocol. # Accounting reports Source: https://docs.layerfi.com/guides/reporting Layer provides a full set of accounting charts and table reports that you can embed directly within your platform. You can use these reports to give your customers a clear picture of their business profitability, cash flows, and balance sheet. There are two ways to offer reporting within your platform: * **Embedded UI components** - Embed Layer's charts and report UI components within your experience. * **API** - Call Layer's API directly to build your own accounting reports. ## Embedded components Layer provides a variety of chart and table report UI components that you can download via npm and embed directly within your frontend. Below are some examples: **Profit & Loss chart** Profit & Loss chart **Profit & Loss table** Profit & Loss table More detail on using Layer's embedded UI components is available [here](/guides/embedded-components). Reach out to your Layer contact for a full list of embedded reporting components. ## API ### Retrieving a Profit & Loss report To build your own Profit & Loss report UI make a call to the [retrieve a Profit and Loss Report](/api-reference/pnl/get) endpoint. The start\_date query string parameter is required for all calls to the Retrieve a Profit and Loss Report endpoint. ```bash Request theme={null} curl -X GET https://sandbox.layerfi.com/v1/businesses/{business_id}/reports/profit-and-loss?start_date=2023-01-01T00:00:00-06:00&end_date=2023-12-01T00:00:00-06:00 -H "Authorization: Bearer " ``` The API will respond with the generated \[Profit and Loss Report]\(/api-reference/pnl/pnl. ```json Response theme={null} { "data":{ "type":"Profit_And_Loss", "business_id":"d2f6d97f-3345-4299-9ec2-468738c5d536", "start_date":"2023-01-01T06:00:00Z", "end_date":"2023-12-01T06:00:00Z", "income":{ "name":"REVENUE", "display_name":"Revenue", "value":49397, "line_items":[ { "name":"SERVICES_REVENUE", "display_name":"Service Revenue", "value":46897, "line_items":null }, { "name":"GOODS_REVENUE", "display_name":"Sale of Goods Revenue", "value":0, "line_items":null }, { "name":"DISCOUNTS", "display_name":"Discounts & Refunds", "value":2500, "line_items":null } ] }, "cost_of_goods_sold":{ "name":"COGS", "display_name":"Cost of Goods Sold", "value":8026, "line_items":[ { "name":"JOB_SUPPLIES", "display_name":"Job supplies", "value":8026, "line_items":null } ] }, "gross_profit":41371, "expenses":{ "name":"OPERATING_EXPENSES", "display_name":"Operating Expenses", "value":0, "line_items":[ { "name":"INSURANCE", "display_name":"Insurance", "value":0, "line_items":null }, { "name":"RENT_EXPENSE", "display_name":"Rent", "value":0, "line_items":null }, { "name":"UTILITIES", "display_name":"Utilities", "value":0, "line_items":null }, { "name":"EQUIPMENT", "display_name":"Equipment & Tools", "value":0, "line_items":null }, { "name":"ADVERTISING", "display_name":"Advertising", "value":0, "line_items":null }, { "name":"VEHICLE_EXPENSES", "display_name":"Vehicle Expenses", "value":0, "line_items":null } ] }, "profit_before_taxes":41371, "taxes":{ "name":"TAXES", "display_name":"Taxes", "value":0, "line_items":null }, "net_profit":41371, "other_outflows":null, "personal_expenses":null, "fully_categorized":true } } ``` You can use this data to build your own profit and loss report UI within your platform. ### Supported reports A full list of supported reports is available in the [API reference](/api-reference/pnl/pnl). ### Async report exports Some reports are generated asynchronously. Submit a request, poll (or wait for a webhook), then download the file. See [Generating async reports](/guides/async-reports). ### Bookkeeping status reporting For analytics and support visibility into books status across your platform, use the [bookkeeping status reporting](/api-reference/v1/list-bookkeeping-businesses) endpoints to list enrolled businesses, fetch a business status summary, and retrieve period history. # Overview Source: https://docs.layerfi.com/guides/surface-accounting-uis-overview Once Layer has your customers' [financial data](/guides/importing-financial-data-overview), you can surface their accounting (reports, transactions, categorization, and more) directly inside your product. There are two ways to do this, and you can mix them: Drop Layer's pre-built, white-labeled React components into your frontend for the fastest path to launch. Build your own interface directly on the Layer API for full control over look, feel, and behavior. ## Which option should I choose? | | Embed Layer React components | Build custom UIs | | - | - | - | | **Speed to launch** | Fastest. The pre-built UI handles data fetching and workflows | Slower. You build and maintain the UI | | **Customization** | Themeable via colors and CSS variables | Full control over every detail | | **What you build** | Configure and style components | Your own components on top of the [Layer API](/api-reference/business/business) | Either method can deliver any of Layer's accounting capabilities, and many platforms combine them, embedding components where speed matters and building custom UIs where they need full control. # Validate a sales data backfill Source: https://docs.layerfi.com/guides/validating-sales-data-backfills Compare source-system sales totals with Layer after a sync or backfill. After backfilling invoices and payments, compare your source system with Layer to confirm two things: Every record in the intended date range was sent, without missing or duplicate invoices, refunds, or payments. The financial totals calculated from those records agree across your system and Layer's accounting representations. Layer's [data sync validation endpoint](/api-reference/v1/fetch-data-sync-validation-totals) returns a compact set of totals for this comparison. Amounts returned by Layer are integer cents. Calculate your source-system totals in the same unit and use the exact same date boundaries for both sides of every comparison. ## Validation workflow Import the full set of invoices, refunds, payments, and related sales data for the period you want to validate. Record the exact `start_date` and `end_date` boundaries used for the backfill. See [Sales / AR data](/guides/importing-sales-ar-data) for the available invoice, payment, refund, and payout workflows. For large imports, use [Bulk create invoices](/api-reference/v1/bulk-create-invoices) and [Bulk create invoice payments](/api-reference/v1/bulk-create-invoice-payments) where appropriate. Pull every invoice or sales receipt in the synced period, regardless of payment status. Calculate the following totals: * **`TOTAL_SALES`** — Sum all invoice totals. * **`CUSTOMER_REFUNDS`** — Sum refunds issued against invoices. Do not include refunded payments that left the invoice open. * **`TIPS`** — Sum tips included on invoices. * **`DISCOUNTS`** — Sum invoice-level and line-item discounts. * **`SALES_TAXES`** — Sum sales taxes reported on invoices. * **`NET_REVENUE`** — Calculate `TOTAL_SALES - CUSTOMER_REFUNDS - DISCOUNTS - TIPS - SALES_TAXES`. These fields use **accrual accounting** in Layer. They reflect invoiced activity during the period and do not depend on whether an invoice has been paid. Pull the payments collected in the synced period and sum the processing fees reported on those payments. Compare this result with **`PAYMENT_PROCESSOR_FEES`**. This field uses the **cash basis** because it reflects fees on collected payments. It does not include hypothetical fees on invoices for which no payment was collected. Call the validation endpoint with the same boundaries used for your source-system calculations: ```bash Request theme={null} curl --request GET \ --url 'https://sandbox.layerfi.com/v1/businesses/{businessId}/reports/data-sync-validation?start_date=2026-01-01T00:00:00Z&end_date=2026-07-01T00:00:00Z' \ --header 'Authorization: Bearer ' ``` The response identifies the report and accounting basis used for each total: ```json Response theme={null} { "data": { "type": "Data_Sync_Validation_Report", "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f", "start_date": "2026-01-01T00:00:00Z", "end_date": "2026-07-01T00:00:00Z", "totals": [ { "field": "TOTAL_SALES", "description": "Total sales should match the sum of all invoice totals sent over the period. This statistic does not consider payments, only the invoiced amounts.", "value": 1250000, "generated_by": { "report": "PROFIT_AND_LOSS", "reporting_basis": "ACCRUAL" } }, { "field": "CUSTOMER_REFUNDS", "description": "Customer refunds should reflect the total of refunds issued against invoices. Refunded payments that left invoices open are not included.", "value": 25000, "generated_by": { "report": "PROFIT_AND_LOSS", "reporting_basis": "ACCRUAL" } }, { "field": "TIPS", "description": "Tips should match the sum of all tips included on all invoices over the period. Ignore invoice payment status.", "value": 10000, "generated_by": { "report": "BALANCE_SHEET", "reporting_basis": "ACCRUAL" } }, { "field": "DISCOUNTS", "description": "Discounts should reflect the total of invoice and individual line item discounts on all invoices sent over the period. Invoice payment status is not considered.", "value": 15000, "generated_by": { "report": "PROFIT_AND_LOSS", "reporting_basis": "ACCRUAL" } }, { "field": "SALES_TAXES", "description": "Total sales taxes reported on invoices across the period. Invoice payment status is not considered.", "value": 100000, "generated_by": { "report": "BALANCE_SHEET", "reporting_basis": "ACCRUAL" } }, { "field": "PAYMENT_PROCESSOR_FEES", "description": "Payment processor fees should match the total reported fees on payments. Fees on invoices with no payment collected are not included.", "value": 30000, "generated_by": { "report": "PROFIT_AND_LOSS", "reporting_basis": "CASH" } }, { "field": "NET_REVENUE", "description": "Topline sales less customer refunds, discounts, tips, and sales taxes.", "value": 1100000, "generated_by": { "report": "PROFIT_AND_LOSS", "reporting_basis": "ACCRUAL" } } ] } } ``` Compare each field independently. Matching only `NET_REVENUE` can hide offsetting differences between sales, refunds, discounts, tips, or taxes. ## Investigate a difference by bisecting the period If a total differs, narrow the problem by repeatedly splitting the date range: 1. Divide the mismatched period into two non-overlapping date ranges. 2. Recalculate the source-system total and call the validation endpoint for each half. 3. Keep the half containing the difference and split it again. 4. Repeat until the range is small enough to inspect individual records. This is well suited to an automated agent: give it the original boundaries, the mismatched field, and access to both totals, then have it bisect until it finds a small set of example records. Use identical boundaries on both systems at every iteration. Check records exactly on each boundary, timezone conversion, duplicate or missing external IDs, refunds that leave invoices open, and payment `fee` values before treating a difference as an accounting issue. ## Related documentation Review request parameters and the complete response schema. Review how invoices, payments, refunds, and payouts flow into Layer. # Categorizing Bank Transactions Source: https://docs.layerfi.com/insights/business-use-cases/basic-smb-transaction-categorization Use Layer MCP tools to help an SMB review, categorize, and match bank transactions. An AI assistant can help an SMB owner turn raw bank activity into categorized accounting data. This is useful for routine bookkeeping workflows where the owner wants to review unresolved transactions, understand what needs attention, and approve reasonable categorizations. ## Questions And Uncertainties Business owners and bookkeepers often want help answering: * Which bank transactions still need review? * Which transactions have obvious categories? * Which transactions might be personal, duplicated, or excluded from the books? * Which transactions should be matched to existing business activity instead of categorized as standalone income or expense? * Which proposed categorizations are safe to apply in bulk? ## Prompts And Tools Users can ask prompts like: * "Show me the transactions that still need review." This typically triggers `get_bank_transactions`. * "Suggest categories for these uncategorized transactions." This typically triggers `get_bank_transactions` and `get_chart_of_accounts`. * "Categorize this hardware store transaction as supplies." This typically triggers `get_chart_of_accounts` and `categorize_bank_transaction`. * "Apply these approved categories in bulk." This typically triggers `bulk_match_or_categorize_bank_transactions`. * "Match these deposits to their suggested matches." This typically triggers `get_bank_transactions` and `match_bank_transaction` or `bulk_match_or_categorize_bank_transactions`. Matching confirms a suggested match; it is not the same as categorizing. * "Undo that last category." This typically triggers `uncategorize_bank_transaction`. ## Expected Interactions The agent should first gather the relevant transactions and accounting context, then present a proposed set of actions for review. For ambiguous transactions, the agent can ask follow-up questions before changing the books. Once the user approves the plan, the agent can submit single or bulk categorization and matching requests through the MCP tools. ## Details And Variations Splits are useful when one bank transaction belongs to multiple accounting categories. The agent can propose split entries, but amounts must sum to the transaction amount before the categorization can be submitted. See [Split Categorizations](/api-reference/v1/categorize-bank-transaction#split-categorizations) for the API request shape. Bank transaction matches are useful when the transaction should be reconciled to existing activity instead of categorized directly. The agent can inspect suggested matches returned with transaction data and confirm the right match after user approval. See [Match Bank Transaction](/api-reference/v1/match-bank-transaction) for the API behavior. Bulk operations are useful after the user reviews a batch of proposed actions. Internally, the MCP server triggers the same Layer API workflows documented in the bank transaction API reference, including [Bulk Match or Categorize Bank Transactions](/api-reference/v1/bulk-match-or-categorize). # Seasonality Analysis by Quarter Source: https://docs.layerfi.com/insights/business-use-cases/seasonality-analysis-by-quarter Use Layer MCP report tools to compare quarterly trends and seasonal business patterns. An AI assistant can compare quarterly financial patterns to help a business owner understand seasonality. This is useful for businesses with recurring busy seasons, slower periods, or expense cycles that change throughout the year. ## Questions And Uncertainties Business owners often want to understand: * Which quarters are usually strongest or weakest. * Whether a slow quarter is expected seasonality or a new problem. * Whether expenses rise before or during busy seasons. * Whether profit changes are driven by revenue, cost of goods sold, or operating expenses. * Whether the current quarter is tracking better or worse than prior quarters. ## Prompts And Tools Users can ask prompts like: * "Which quarter is usually strongest for revenue?" This typically triggers `get_profit_and_loss_summaries` (month-range trends). Use `get_financial_report` when a full P\&L statement is needed. * "Do my expenses rise before my busy season?" This typically triggers `get_profit_and_loss_summaries`. * "Compare this quarter to the same quarter last year." This typically triggers `get_profit_and_loss_summaries` or `compare_profit_and_loss`. * "Are seasonal changes coming from revenue or expenses?" This typically triggers `get_profit_and_loss_summaries` or `get_financial_report`. ## Expected Interactions The agent should retrieve a month range wide enough to compare quarters, group monthly results into quarters, and explain the seasonal pattern. If the data is sparse or uncategorized activity may distort the results, the agent should say so and suggest reviewing the underlying transactions. ## Details And Variations Seasonality analysis can compare consecutive quarters, the same quarter across years, or busy-season months against off-season months. The assistant can focus on top-level metrics such as revenue and net profit, or drill into cost of goods sold and operating expenses when the user wants to understand what changed. This type of analysis works best when the business has enough categorized historical data for quarter-over-quarter comparisons. # Trailing 3 Months P&L Source: https://docs.layerfi.com/insights/business-use-cases/trailing-three-month-pnl Use Layer MCP tools to explain recent profit and loss trends. An AI assistant can use Layer's financial report tools to explain how a business performed over the trailing three months. This gives SMB owners a lightweight way to understand recent revenue, expenses, gross profit, and net profit without reading a full accounting report line by line. ## Questions And Uncertainties Business owners often want to understand: * Whether revenue is growing or shrinking. * Whether expenses are rising faster than income. * Which month had the strongest or weakest profit. * Whether the recent trend is healthy enough to support hiring, spending, or owner distributions. * Whether uncategorized transactions may be affecting the report. ## Prompts And Tools Users can ask prompts like: * "How did my business perform over the last three months?" Start with `get_financial_report` (`report_type: profit_and_loss`) or `get_profit_and_loss_summaries` for month-range trends. * "Did expenses grow faster than revenue?" This typically triggers `get_profit_and_loss_summaries`. * "Which month had the strongest net profit?" This typically triggers `get_profit_and_loss_summaries`. * "Are uncategorized transactions affecting my P\&L?" This may trigger `get_financial_report` or `get_profit_and_loss_summaries` and `get_bank_transactions`. ## Expected Interactions The agent should retrieve the trailing three-month P\&L (prefer `get_financial_report` for a full statement, `get_profit_and_loss_summaries` for month-by-month trends), compare the months, and explain the results in plain language. If the report shows unusual changes or uncategorized activity, the agent can ask whether the user wants to inspect the underlying transactions. ## Details And Variations The same pattern can be used for cash or accrual reporting when the report tool supports the requested basis. The agent can also compare the trailing three months to the previous three months, focus only on expense categories, or call out specific line items that changed meaningfully. Because report values are returned in cents, agents should convert amounts before presenting them to users. # Overview Source: https://docs.layerfi.com/insights/mcp-server How Layer's MCP server gives AI agents access to accounting data and bookkeeping actions. Layer's MCP server exposes Layer accounting data and bookkeeping workflows as Model Context Protocol tools. AI clients and platform agents can inspect financial data, answer business questions, and take supported bookkeeping actions through Layer's API. The catalog is workflow-oriented, not a generic REST executor. Clients discover the long tail of tools with MCP tool search against names and descriptions. Monetary amounts are **integer cents** (`123456` means `$1,234.56`); convert to dollars when presenting answers. The server currently registers on the order of **190 tools**. Most clients should not load the full catalog into context. Use tool search, and rely on the always-load tools below for the common path. ## Modes, URLs, and capability groups JWTs prove authentication. **Mode** is which URL you hit. **Capability groups** filter which tools are registered. Tool annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`) are UX hints, not authorization. | URL | Mode | Business context | Default groups | | - | - | - | - | | `POST` / `GET` / `DELETE` `…/mcp` | **platform** | Agent calls `set_active_business` with a Layer business UUID | `core` + `reporting` | | `…/mcp/:businessToken` | **business** | Fixed at provisioning (`layerBusinessId` in the MCP server client config) | `core` + `reporting` + `accounting` | | `…/mcp/b/:businessId` | **business** (passthrough) | Path business + bearer Layer API token | All business groups unless `LAYER_MCP_GROUPS` is set | All business groups: `core`, `reporting`, `accounting`, `banking_imports`, `ar_imports`, `ap_imports`, `loans_assets`, `qbo`. Provisioned clients can add groups with `capabilityGroups` on the client entry, or with the comma-separated `LAYER_MCP_GROUPS` environment variable. See [Authentication](/insights/mcp-server/business-scoped-access) for hosts, tokens, and the two business URLs. **Platform mode does not get accounting mutations** (no categorize, imports, voids, or journal entries). Exceptions: `create_business` and `update_business` (platform lifecycle). Platform **does** get many **read** tools that also appear on business (reports, list invoices, get bank transactions, and similar) when those tools list both modes. **Business mode does not get** `set_active_business`, `get_all_businesses`, `get_profitability_report`, platform billing/activity export tools, or platform-secret / auth-token issuance tools. ## Always-load tools These stay in client context even when tool search is used (`anthropic/alwaysLoad`): **Platform:** `set_active_business`, `get_all_businesses`, `get_financial_report`, `get_profitability_report` **Business:** `get_bank_transactions`, `get_financial_report`, `get_chart_of_accounts`, `categorize_bank_transaction` ## Integration patterns * **Business-level insights:** Tools operate within one business. Use this when an end business owner or business-scoped assistant needs that business's transactions, reports, and chart of accounts. * **Platform-level insights:** The agent calls `set_active_business` before business-scoped reads. Use this for platform support, operations, demos, and internal agents that already know which Layer business to inspect. Platforms can incorporate Layer MCP tools into their own AI agents, or connect an MCP client such as Claude Desktop or Claude on the web. ## Product conventions * Identify the underlying HTTP contract by **method and path**, not OpenAPI `operationId`. Workflow pages in this tab link to the existing REST guides for payload shape. * Destructive actions are separately named (`void_*`, `delete_*`, `reverse_*`, `unlink_*`, `archive_*`, `merge_*`, `uncategorize_*`). * Tag filters are only accepted where Layer filters **before aggregation**: P\&L, P\&L summaries, balance sheet, AP aging, and bank transactions. Do not invent tag filters for cash flow, AR aging, trial balance, tax, or Schedule C. * Receipts are **prepare → PUT file bytes to S3 → complete**. Never send file bytes or large base64 through the model. * Prefer JSON custom transaction import over CSV. * AR uses **customer credit**, not “credit note”. AP uses **vendor credit**, not “credit note”. * Plaid tools return a **hosted Link URL** for a human to open. ## Where to start | Goal | Start here | | - | - | | Connect a client | [Authentication](/insights/mcp-server/business-scoped-access) | | Reports, P\&L, cash flow, aging | [Financial reports](/insights/mcp-server/financial-reports) | | Categorize vs match vs uncategorize | [Transaction categorization](/insights/mcp-server/transaction-categorization) | | Platform onboarding and analytics | [Platform session](/insights/mcp-server/platform-session) | # Bank connections and custom imports Source: https://docs.layerfi.com/insights/mcp-server/bank-connections Hosted Plaid Link, repair, confirm accounts, and JSON custom bank imports. Banking import tools are in the `banking_imports` group (not in default provisioned groups). Bank account **reads** (`list_bank_accounts`, `get_bank_account`) are also in `core`. Prefer **JSON** custom transaction import over CSV. `start_plaid_link` returns a **hosted Link URL** for a human to open. REST guides: [Importing bank data](/guides/importing-bank-data), [Plaid](/integrations/banking/plaid), [Custom Plaid account linking](/guides/custom-plaid-account-linking). ## Plaid (hosted Link) Call `start_plaid_link`. Optional `hosted_link_params` in the body. Open the returned hosted URL in a browser. After the human finishes Link, `list_external_accounts`. Confirm with `confirm_external_account` or drop with `exclude_external_account` (destructive). `get_bank_connection_status` refreshes Plaid/external-account status after Link. `start_plaid_repair` starts update-mode Link. Body must include `plaid_item_id`. Returns a hosted URL. Search phrases: hosted Link URL, repair, reconnect, confirm account, exclude account. ## Custom bank accounts CRUD plus: * `set_custom_bank_account_opening_balance` * `import_custom_bank_transactions` — **JSON, preferred** * `import_custom_bank_transactions_csv` * `list_transaction_imports`, `archive_transaction_import` (destructive) * `archive_custom_bank_account` (destructive), `reactivate_custom_bank_account` Search phrases: custom bank, JSON import preferred, CSV upload. # Bills and AP import Source: https://docs.layerfi.com/insights/mcp-server/bills-and-ap Vendors, bills, bill payments, vendor credits, refunds, payouts, and expenses. AP import tools are in the `ap_imports` group. Vendor **reads** are also in `core`. Writes are business mode. Use **vendor credit**, not “credit note”. Prefer `external_id` on imports. REST guide: [Importing bills / AP data](/guides/importing-bill-ap-data). ## Sequence Reads: `list_vendors`, `get_vendor`. Writes: `create_vendor`, `update_vendor`, `archive_vendor` (destructive), `unarchive_vendor`, `merge_vendors` (destructive). `list_bills`, `get_bill`, `import_bills` (`POST …/bills/bulk`), `update_bill`. Destructive: `void_bill`, `delete_bill`. Bill payments: list/get/`import_bill_payments`/update/`delete_bill_payment`. Vendor credits: list/get/create/update/`delete_vendor_credit`. Vendor refunds and vendor payouts similarly, including `record_vendor_refund_payment`. ## Expenses `create_expense` (`POST …/expenses`) creates a paid-on-receipt expense (bill + payment). Prefer `external_id` as the idempotency key. See [Create expense](/api-reference/v1/create-expense). Search phrases: bills, bill payments, vendor credit, vendor refunds, expenses, vendor payouts. # Authentication Source: https://docs.layerfi.com/insights/mcp-server/business-scoped-access Connect an MCP client in platform mode, provisioned business mode, or Layer-token passthrough. Layer's MCP server supports three Streamable HTTP URLs. The JWT proves who the caller is. **Which URL you hit** selects platform vs business mode and which capability groups are registered by default. Hosts: | Environment | MCP host | Layer API scope | | - | - | - | | Sandbox | `https://mcp-sandbox.layerfi.com` | `https://sandbox.layerfi.com/sandbox` | | Production | `https://mcp.layerfi.com` | `https://api.layerfi.com/production` | The environment is inferred from the token's `scope` claim, so the token and the MCP host must be from the same environment. Layer remains the authorization boundary. ## Platform: `/mcp` ``` POST https://mcp.layerfi.com/mcp GET https://mcp.layerfi.com/mcp DELETE https://mcp.layerfi.com/mcp Authorization: Bearer ``` Platform mode is for operators who move between businesses. The agent must call `set_active_business` with a Layer business UUID before business-scoped tools. Default groups are `core` and `reporting`. Extra groups can be set on the provisioned client (`capabilityGroups`) or with `LAYER_MCP_GROUPS`. Platform mode does not register accounting mutations. See [Platform session](/insights/mcp-server/platform-session). ## Provisioned business: `/mcp/:businessToken` ``` POST https://mcp.layerfi.com/mcp/{businessToken} GET https://mcp.layerfi.com/mcp/{businessToken} DELETE https://mcp.layerfi.com/mcp/{businessToken} Authorization: Bearer ``` The business is fixed at provisioning (`layerBusinessId` on the MCP server client entry). There is no `set_active_business` tool. Default groups are `core`, `reporting`, and `accounting`. Additional groups (`banking_imports`, `ar_imports`, `ap_imports`, `loans_assets`, `qbo`) are opt-in via `capabilityGroups` or `LAYER_MCP_GROUPS`. Use this when Layer (or the platform) has already issued a per-business MCP URL token for an interactive client. ## Passthrough business: `/mcp/b/{businessId}` Point an MCP client at a single Layer business using a [Layer API access token](/api-details/authentication). The MCP server validates that token the same way the Layer API does and forwards it verbatim to Layer. ``` POST https://mcp.layerfi.com/mcp/b/{businessId} GET https://mcp.layerfi.com/mcp/b/{businessId} DELETE https://mcp.layerfi.com/mcp/b/{businessId} Authorization: Bearer ``` `{businessId}` is the Layer business UUID. It must be a business owned by the token's client. Passthrough registers **all** business capability groups (`core`, `reporting`, `accounting`, `banking_imports`, `ar_imports`, `ap_imports`, `loans_assets`, `qbo`) unless `LAYER_MCP_GROUPS` is set on the MCP server. This is the right fit when platform engineers already mint Layer API tokens and want to expose Layer MCP tools inside their own agents. ### Authenticate for a given business (passthrough) This is the same client credentials flow used for the Layer REST API. See [Authentication](/api-details/authentication) for full details. ```bash theme={null} curl -X POST https://auth.layerfi.com/oauth2/token \ -u "$LAYER_CLIENT_ID:$LAYER_CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials&client_id=$LAYER_CLIENT_ID&scope=https://sandbox.layerfi.com/sandbox" ``` The authorization server responds with a short-lived access token: ```json theme={null} { "access_token": "...", "expires_in": 3600 } ``` Use `…/mcp/b/` as the server URL and send the token as `Authorization: Bearer `. Claude Desktop runs OAuth discovery on remote servers, so pass the static bearer through the `mcp-remote` proxy in `~/Library/Application Support/Claude/claude_desktop_config.json`: ```json theme={null} { "mcpServers": { "layer-sandbox": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp-sandbox.layerfi.com/mcp/b/", "--header", "Authorization:${AUTH_HEADER}" ], "env": { "AUTH_HEADER": "Bearer " } } } } ``` After making this change, restart Claude Desktop. The `${AUTH_HEADER}` env indirection avoids a Claude Desktop bug that splits `--header "Authorization: Bearer ..."` on the space. ## Errors | Status | Meaning | | - | - | | `401` | Missing or malformed bearer, or JWT invalid/expired/wrong issuer | | `403 insufficient_scope` | Token's scope is not a recognized Layer environment scope (passthrough) or required MCP scope (provisioned) | | `404` | Provisioned business token not found, or (from Layer) business not found / not owned by the token's client | ## Token lifetime Platform customers building an MCP integration typically wrap passthrough in a refresher that re-mints via `client_credentials`, or run a local MCP process that manages token refresh. For a human's Claude Desktop config, a pasted token stops working at expiry and must be re-pasted. ## When to use which URL | Need | URL | | - | - | | One agent across many businesses | `/mcp` (platform) | | Interactive client, business fixed at provisioning | `/mcp/:businessToken` | | Existing Layer API token, one business in the path | `/mcp/b/{businessId}` | # Financial reports Source: https://docs.layerfi.com/insights/mcp-server/financial-reports Start with get_financial_report, then use specialized P&L, ledger, export, and tax tools. Agents should start with **`get_financial_report`**. It is always-load in both platform and business mode. Specialized tools exist when the response shape differs (trends, comparisons, line items, general ledger, data-sync validation). Amounts are integer cents. Convert before presenting. For HTTP payload shapes and embedded reporting, see [Accounting reports](/guides/reporting). ## Sequence In platform mode, call `set_active_business` first. See [Platform session](/insights/mcp-server/platform-session). Call `get_financial_report` with `report_type`. Use `start_date` and `end_date` for P\&L and cash flow. Use `effective_date` for balance sheet. Month-range trends use `get_profit_and_loss_summaries` (this is **not** renamed to “trends”). Side-by-side periods use `compare_profit_and_loss`. File downloads use `export_financial_report`. ## `get_financial_report` Always-load. Group: `reporting`. Modes: platform and business. `report_type` values: `profit_and_loss`, `balance_sheet`, `cash_flow`, `trial_balance`, `ap_aging`, `ar_aging`. The tool returns a shared envelope: `report_type`, `fetched_at`, `amounts_unit: cents`, and `report` (the Layer payload). | `report_type` | Dates | HTTP | Tag filter | | - | - | - | - | | `profit_and_loss` | `start_date` + `end_date` required | `GET …/reports/profit-and-loss` | Yes | | `balance_sheet` | `effective_date` required | `GET …/reports/balance-sheet` | Yes | | `cash_flow` | `start_date` + `end_date` required | `GET …/reports/cashflow-statement` | No | | `trial_balance` | dates optional | `GET …/ledger/balances` | No | | `ap_aging` | — | `GET …/reports/unified/ap-aging` | Yes | | `ar_aging` | — | `GET …/invoices/ar-aging` | No | Tag filters are only sent when Layer applies them **before aggregation** (P\&L, balance sheet, AP aging). Do not invent tag filters for cash flow, AR aging, trial balance, tax, or Schedule C. Optional `reporting_basis`: `ACCRUAL` or `CASH`. P\&L also accepts `structure`. ## Specialized report tools Keep these when you need their distinct shapes: * `get_profit_and_loss_summaries` — month-range P\&L summaries for trends, charts, and performance comparisons (`GET …/profit-and-loss-summaries`). Search phrases: reports, P\&L, profit and loss, trends. * `compare_profit_and_loss` — `POST …/profit-and-loss-comparison` * `get_profit_and_loss_details` — `GET …/profit-and-loss-details` * `get_profit_and_loss_line_items` — `GET …/profit-and-loss/lines` * `get_balance_sheet` — same resource as unified `report_type: balance_sheet` * `get_general_ledger` — `GET …/ledger/entries` * `get_data_sync_validation` — backfill / data-sync checks * `get_chart_of_accounts` — nested chart; always-load on business (`GET …/ledger/chart`) ## Exports `export_financial_report` returns a presigned download URL for `csv` or `xlsx`. | Report | Formats | | - | - | | P\&L, balance sheet | `csv` or `xlsx` | | cash flow, trial balance | **csv only** | | AP aging | **xlsx only** | | AR aging | **no file export** | Async billing jobs are platform-only: `create_billing_report_export` then `list_exports` / `get_export`. See [Platform session](/insights/mcp-server/platform-session). ## Tax (reporting group) Tax tools live in `reporting`. Prefer [Tax](/insights/mcp-server/tax) for the full sequence. * `get_tax_estimate` — `view`: `overview` | `summary` | `details` | `payments`. No tag filter. * `get_tax_checklist`, `get_tax_profile`, `update_tax_profile` (business write) * `get_schedule_c_report` — `GET …/reports/tax/schedule-c` * `create_tax_packet`, `list_tax_packets` * `export_tax_documents` — `TAX_PACKET` | `SCHEDULE_C` | `PAYMENT_HISTORY` # Invoices and AR import Source: https://docs.layerfi.com/insights/mcp-server/invoices-and-ar Customers, invoices, payments, refunds, payouts, and customer credits. Use external_id for idempotent imports. AR import tools are in the `ar_imports` group. Customer and invoice **reads** are also available in `core` (platform and business). Writes are business mode. Prefer `external_id` as the idempotency key on imports. Use **customer credit**, not “credit note”. REST guide: [Importing sales / AR data](/guides/importing-sales-ar-data). ## Sequence Reads: `list_customers`, `get_customer`. Writes: `create_customer`, `update_customer`, `archive_customer` (destructive), `unarchive_customer`, `merge_customers` (destructive), `bulk_create_customers`. `list_invoices`, `get_invoice`, `import_invoices` (`POST …/invoices/batch`), `update_invoice`. Destructive: `void_invoice`, `delete_invoice`. Also `get_invoice_pdf`, `write_off_invoice`, `delete_invoice_write_off` (destructive). List/get plus import-or-create/update/delete for invoice payments, invoice refunds, payouts, and customer credits. `record_invoice_refund_payment` / `delete_invoice_refund_payment` (destructive) for refund payments. ## Tool groups (search) | Area | Search terms | | - | - | | Invoices | `import_invoices`, void, delete, write-off, PDF | | Payments | `import_invoice_payments` | | Refunds | `import_invoice_refunds`, `record_invoice_refund_payment` | | Payouts | `import_payouts` | | Customer credits | `create_customer_credit` (not credit note) | List tools accept `cursor` / `limit`. Writes typically take a loose `body` object. # Loans and assets Source: https://docs.layerfi.com/insights/mcp-server/loans-and-assets Loan, proceed, payment, and asset tools for MCP agents. These tools are in the `loans_assets` group (opt-in; not in default provisioned groups). Archives are destructive. Prefer `external_id` on creates. Product guides: [Importing loan data](/guides/importing-loan-data), [Importing asset data](/guides/importing-asset-data). API reference: [Loan](/api-reference/loan/loan), [List loans](/api-reference/v1/loans/list-loans), [List assets](/api-reference/v1/assets/list-assets). ## Loans * `list_loans`, `get_loan`, `create_loan`, `update_loan`, `archive_loan` (destructive) * Proceeds: `list_loan_proceeds`, `get_loan_proceed`, `create_loan_proceed`, `update_loan_proceed`, `archive_loan_proceed` * Payments: `list_loan_payments`, `get_loan_payment`, `create_loan_payment`, `bulk_create_loan_payments`, `update_loan_payment`, `archive_loan_payment` ## Assets * `list_assets`, `get_asset`, `create_asset`, `update_asset`, `archive_asset` (destructive) * Value updates: `list_asset_value_updates`, `get_asset_value_update`, `create_asset_value_update`, `update_asset_value_update`, `archive_asset_value_update` Reads are available in platform and business mode. Writes are business mode. # Platform session Source: https://docs.layerfi.com/insights/mcp-server/platform-session Set the active business, onboard businesses, and run platform analytics and billing exports. Platform mode uses `POST`/`GET`/`DELETE …/mcp`. Default groups are `core` and `reporting`. The agent **must** call `set_active_business` with a Layer business UUID before business-scoped tools. Platform cannot mutate business accounting data (no categorize, imports, voids, or journal entries). It can create and update businesses, read many shared resources, and run platform analytics. Always-load on platform: `set_active_business`, `get_all_businesses`, `get_financial_report`, `get_profitability_report`. See [Authentication](/insights/mcp-server/business-scoped-access) for the `/mcp` URL. ## Sequence: inspect a customer `get_all_businesses`, or `get_business` when you already have the UUID. `set_active_business` (always-load). `get_financial_report` for P\&L, balance sheet, cash flow, trial balance, and aging. `get_profitability_report` buckets businesses by net income (platform analytics only). ## Onboarding * `create_business` — `POST /v1/businesses`. `external_id` is the idempotency key. Does not mutate an existing ledger. * `update_business` — `PUT /v1/businesses/{businessId}` * `get_business` — platform and business * `get_all_businesses` — always-load composite REST: [Business onboarding](/guides/business-onboarding). ## Analytics and bookkeeping status * `get_profitability_report` — always-load. Platform analytics; amounts in cents. Search: profitability. * `get_platform_activity_summary` — `GET /v2/activity` * `list_bookkeeping_businesses` — `GET /v1/reports/bookkeeping` ## Billing exports `create_billing_report_export` — `POST /v1/billing/reports` `list_exports` / `get_export` — `GET /v1/exports` Search phrases: set active business, profitability, activity summary, billing export. # QuickBooks Source: https://docs.layerfi.com/insights/mcp-server/quickbooks Authorize QuickBooks Online, poll connection status, sync, map accounts, and unlink. QuickBooks tools are in the `qbo` group (opt-in; not in default provisioned groups). ## Sequence `start_quickbooks_connection` (`POST …/quickbooks/authorize`) returns a URL a human must open. `get_quickbooks_connection_status` after authorize and after sync. `sync_from_quickbooks` (`POST …/quickbooks/sync-from`). Poll status again. `list_quickbooks_accounts`, `get_quickbooks_account`, `map_quickbooks_account`. `unlink_quickbooks` is destructive. Search phrases: authorize, connection status, sync from QuickBooks, map accounts, unlink. REST: [Authorize QuickBooks](/api-reference/v1/authorize-quickbooks-oauth-flow), [Sync from QuickBooks](/api-reference/v1/sync-from-quickbooks), [List QuickBooks accounts](/api-reference/v1/list-quickbooks-accounts). # Receipts Source: https://docs.layerfi.com/insights/mcp-server/receipts Prepare a receipt upload, PUT bytes to S3, then complete. Never send base64 through the model. Receipts use Layer's multipart document upload. The MCP tools never accept file bytes. The **client** (not the model) PUTs the file to S3. Full HTTP contract: [Multipart upload guide](/api-reference/v1/multipart-upload-guide). ## Sequence Call `prepare_receipt_upload` (`POST …/documents`) with filename, content type, size, and document type such as `RECEIPT`. The result includes the document id, upload id, part size, and presigned part URLs. The HTTP client PUTs each part to the returned URLs. Do not pass file bytes or large base64 through the model. Call `complete_receipt_upload` with the upload id and part ETags from S3 (`POST …/documents/{documentId}/complete`). ## Reads and archive * `list_transaction_receipts` — documents on a bank transaction (`GET …/bank-transactions/{transactionId}/documents`), including presigned URLs. * `get_transaction_receipt` — `GET …/s3_doc/{documentId}`. * `archive_transaction_receipt` — destructive. Search phrases: prepare upload, S3 PUT, complete upload, receipts (not base64). These tools are in the `accounting` group. Writes are business mode. List/get are available in platform and business as reads. # Tags and journal entries Source: https://docs.layerfi.com/insights/mcp-server/tags-and-journals Tag dimensions and values, apply or merge tags, and post custom journal entries. Tags and custom journal entries are business bookkeeping tools. List reads for tags are in `core` and `accounting` (platform and business). Writes and journal mutations are business `accounting`. Amounts on journal lines are integer cents. ## Tags ### Sequence `list_tag_dimensions`, `list_tag_values`. `create_tag_dimension`, `update_tag_dimension`, `create_tag_value`, `update_tag_value`. `apply_tags`, `remove_tags` (destructive). `merge_tag_values` (destructive). Tag filters on reports are **not** universal. Layer applies them before aggregation only for P\&L, P\&L summaries, balance sheet, AP aging, and bank transactions. Do not send tag filters on cash flow, AR aging, trial balance, tax, or Schedule C. ## Custom journal entries | Tool | Notes | | - | - | | `list_custom_journal_entries` / `get_custom_journal_entry` | Reads | | `create_custom_journal_entry` / `bulk_create_custom_journal_entries` | Writes | | `update_custom_journal_entry` | Write | | `reverse_custom_journal_entry` | Destructive reverse | Search phrases: custom journal entry, reverse. REST shapes: [Custom journal entries](/api-reference/custom-journal-entries/custom-journal-entry). # Tax Source: https://docs.layerfi.com/insights/mcp-server/tax Tax estimates, checklist, profile, Schedule C, packets, and document export. Tax tools are in the `reporting` group. `get_tax_estimate` is a composite: pick a `view` instead of calling four separate REST paths. Tag filtering is **not** supported on tax or Schedule C. REST: [Tax estimates overview](/api-reference/v1/tax-estimates/overview), [Get tax profile](/api-reference/v1/tax-estimates/get-tax-profile), [Create tax packet](/api-reference/v1/create-tax-packet). ## Sequence `get_tax_estimate` with `year` and `view`: `overview` | `summary` | `details` | `payments`. Optional `project` for full-year projection on the current year. `get_tax_checklist`, `get_tax_profile`. Business write: `update_tax_profile`. `get_schedule_c_report` (`GET …/reports/tax/schedule-c`). `create_tax_packet` (business), `list_tax_packets`. `export_tax_documents` (`POST …/tax-estimates/export`) with `type`: `TAX_PACKET` | `SCHEDULE_C` | `PAYMENT_HISTORY`. See also [Financial reports](/insights/mcp-server/financial-reports) for P\&L and balance sheet context that tax estimates depend on. # Transaction categorization Source: https://docs.layerfi.com/insights/mcp-server/transaction-categorization Categorize, match, uncategorize, and manage rules for bank transactions. Layer MCP can retrieve and act on bank transactions for the configured business. Matching and categorizing are different actions: **match** confirms a suggested invoice/bill (or other) match; **categorize** assigns a ledger account, split, or exclusion. Amounts are integer cents. For REST request shapes, see [Transaction categorization](/guides/transaction-categorization), [Categorize Bank Transaction](/api-reference/v1/categorize-bank-transaction), [Match Bank Transaction](/api-reference/v1/match-bank-transaction), and [Bulk Match or Categorize](/api-reference/v1/bulk-match-or-categorize). ## Sequence Call always-load `get_bank_transactions` with filters (date range, direction, amount, categorization status, description, merchant, customer, vendor, external account, tags, search). Use `cursor` / `limit` on lists. Fetch one row with `get_bank_transaction`. Call always-load `get_chart_of_accounts` before categorizing so account IDs and stable names are valid. Use `match_bank_transaction` when the transaction already has a suggested match to confirm. Use `categorize_bank_transaction` to assign a single account, split across accounts, or exclude. Use `bulk_match_or_categorize_bank_transactions` for a map of transaction id → match or categorize. `uncategorize_bank_transaction` and `bulk_uncategorize_bank_transactions` are destructive. `update_bank_transaction_metadata` updates memo-style fields without changing categorization. ## Reads (core + accounting) Always-load on business: `get_bank_transactions`. Also: `get_bank_transaction`, `get_chart_of_accounts` (always-load). `get_bank_transactions` is available in platform and business mode. Categorize/match/uncategorize writes are **business** only (`core` + `accounting`, except bulk categorize which is `accounting`). ## Categorize vs match vs uncategorize | Tool | What it does | | - | - | | `categorize_bank_transaction` | Always-load on business. Single account, split, or exclude. Distinct from match. | | `match_bank_transaction` | Confirms a **suggested match**. Does not assign a P\&L category. | | `bulk_match_or_categorize_bank_transactions` | Map of transaction id → `match` or `categorize`. | | `uncategorize_bank_transaction` / `bulk_uncategorize_bank_transactions` | Destructive. Clears categorization. | | `update_bank_transaction_metadata` | Metadata only. | Splits must sum to the transaction amount. See [Split Categorizations](/api-reference/v1/categorize-bank-transaction#split-categorizations). Search phrases: match vs categorize, confirm suggested match, assign ledger account, exclude. ## Rules and suggestions Business writes in `accounting`: * `list_categorization_rules`, `get_categorization_rule` * `create_categorization_rule`, `update_categorization_rule` * `archive_categorization_rule` (destructive) * `list_categorization_rule_suggestions` * `accept_categorization_rule_suggestion` * `reject_categorization_rule_suggestion` (destructive) See [Categorization rule suggestions](/guides/transaction-categorization/rules-suggestion). ## Related workflows * Attach receipts with [Receipts](/insights/mcp-server/receipts) (prepare → S3 PUT → complete; never base64 through the model). * Dimension tags with [Tags and journal entries](/insights/mcp-server/tags-and-journals). Tag filters on bank transaction list are supported; report tag filters are limited (see [Financial reports](/insights/mcp-server/financial-reports)). # Platform MCP Source: https://docs.layerfi.com/insights/platform-use-cases How platform owners can use Layer MCP tools to draw insights across customer businesses. Platform owners can use Layer's MCP server to power internal agents, support workflows, demos, and operational analysis across the businesses they serve. In platform mode, an agent sets the active business for a session, queries Layer financial data, and uses those results to explain customer trends or identify follow-up actions. Tool sequences for onboarding, profitability, activity, and billing exports are in [Platform session](/insights/mcp-server/platform-session). ## Customer support and operations A platform-owned agent uses `set_active_business` to inspect the right customer business during a support workflow. From there it can retrieve bank transactions, `get_financial_report`, specialized P\&L tools, or the chart of accounts. Examples include: * Investigating why a customer's report looks incomplete (`get_financial_report`, `get_data_sync_validation`). * Checking whether uncategorized transactions are affecting financial statements (`get_bank_transactions`). * Finding recent transactions that match a support question. * Explaining the current state of a customer's bookkeeping setup (`list_bookkeeping_businesses`). ## Portfolio-level insights The agent iterates across selected businesses, gathers consistent report or transaction signals, and summarizes patterns for internal teams. Examples include: * Identifying customers with persistent uncategorized transaction volume. * Comparing customer profitability with `get_profitability_report`. * Reviewing platform activity with `get_platform_activity_summary` (`GET /v2/activity`). * Exporting billing reports with `create_billing_report_export` then `list_exports` / `get_export`. * Finding businesses that may need bookkeeping attention before month end. * Preparing account-management summaries before customer check-ins. Platform agents should validate authorization before calling `set_active_business` with customer business IDs. ## Onboarding from an agent Platform mode can `create_business` and `update_business` (lifecycle only; not ledger mutations). After create, `set_active_business` then `get_financial_report` or `get_business` to confirm the record. # Mixpanel Source: https://docs.layerfi.com/integrations/analytics/mixpanel Send usage events from Layer's embedded components to Mixpanel. Track how your customers use Layer's embedded accounting features in [Mixpanel](https://mixpanel.com/), alongside the rest of your product analytics. Layer's React components emit [UI events](/embedded-components/ui-events) as users interact with them, and you can forward those events to Mixpanel from a single callback. ## Setup Subscribe to component events through the `onEvent` callback on `` and pass them to Mixpanel's `track` method: ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; import mixpanel from "mixpanel-browser"; { mixpanel.track(`layer.${event.type}`, { ...event.payload, component: event.metadata.component, }); }, }} > {...} ``` Every event includes a `type`, a typed `payload`, and metadata identifying the component it came from. Prefixing the event name (for example `layer.tasks.month_selected`) keeps Layer activity easy to filter in Mixpanel. See the [UI events reference](/embedded-components/ui-events) for the full catalog of events and their payloads. ## What to measure * **Adoption** - which businesses open accounting features, and which components they use * **Engagement** - how often customers review transactions, run reports, or complete tasks * **Funnels** - where customers drop off in flows like account linking or transaction categorization # Pendo Source: https://docs.layerfi.com/integrations/analytics/pendo Send usage events from Layer's embedded components to Pendo. Track how your customers use Layer's embedded accounting features in [Pendo](https://www.pendo.io/), alongside the rest of your product analytics. Layer's React components emit [UI events](/embedded-components/ui-events) as users interact with them, and you can forward those events to Pendo from a single callback. ## Setup Subscribe to component events through the `onEvent` callback on `` and pass them to Pendo's `track` method: ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; { window.pendo?.track(`layer.${event.type}`, { ...event.payload, component: event.metadata.component, }); }, }} > {...} ``` Every event includes a `type`, a typed `payload`, and metadata identifying the component it came from. Prefixing the event name (for example `layer.tasks.month_selected`) keeps Layer activity easy to filter in Pendo. See the [UI events reference](/embedded-components/ui-events) for the full catalog of events and their payloads. ## What to measure * **Adoption** - which businesses open accounting features, and which components they use * **Engagement** - how often customers review transactions, run reports, or complete tasks * **Guides** - target Pendo in-app guides at customers who haven't tried accounting features yet # PostHog Source: https://docs.layerfi.com/integrations/analytics/posthog Send usage events from Layer's embedded components to PostHog. Track how your customers use Layer's embedded accounting features in [PostHog](https://posthog.com/), alongside the rest of your product analytics. Layer's React components emit [UI events](/embedded-components/ui-events) as users interact with them, and you can forward those events to PostHog from a single callback. ## Setup Subscribe to component events through the `onEvent` callback on `` and pass them to PostHog's `capture` method: ```tsx theme={null} import { LayerProvider } from "@layerfi/components"; import posthog from "posthog-js"; { posthog.capture(`layer.${event.type}`, { ...event.payload, component: event.metadata.component, }); }, }} > {...} ``` Every event includes a `type`, a typed `payload`, and metadata identifying the component it came from. Prefixing the event name (for example `layer.tasks.month_selected`) keeps Layer activity easy to filter in PostHog. See the [UI events reference](/embedded-components/ui-events) for the full catalog of events and their payloads. ## What to measure * **Adoption** - which businesses open accounting features, and which components they use * **Engagement** - how often customers review transactions, run reports, or complete tasks * **Funnels** - where customers drop off in flows like account linking or transaction categorization # CapitalOS Source: https://docs.layerfi.com/integrations/banking/capitalos Sync spend from CapitalOS-powered charge cards into your customers' books. Layer connects to [CapitalOS](https://www.capitalos.com/) to import spend from the business charge cards your platform issues. Purchases, payments, and balances all reach the customer's books automatically. ## Setup Grant Layer read access to your CapitalOS data. Your Layer contact will help you establish the connection and map card accounts to Layer businesses. Layer ingests transactions and balances from each customer's card accounts as new activity comes in. Card spend then flows through [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting), so expenses land in the right categories on the customer's profit and loss. This integration is enabled per platform. Reach out to your Layer contact to turn it on. # Finicity Source: https://docs.layerfi.com/integrations/banking/finicity Import bank account activity aggregated through Finicity into your customers' books. Platforms that aggregate bank data with [Finicity](https://www.finicity.com/) can grant Layer access to that connectivity. Layer ingests transactions and balances from your customers' Finicity-connected accounts and incorporates them into their books, with no second account-linking step for the customer. ## Setup Grant Layer access to your Finicity data and map each customer's connected accounts to their Layer business. Your Layer contact will help you establish the connection. Layer ingests transactions and balances as new activity comes in. Imported accounts behave like any other account in Layer, flowing through [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. Don't have an existing aggregator relationship? Layer's [Plaid integration](/integrations/banking/plaid) includes a fully managed connection, with prebuilt account linking UI. ## Importing directly instead To push aggregated account activity to Layer yourself, create a [Custom Account](/api-reference/v1/create-custom-account) for each account and pass its activity to the [Import Transactions](/api-reference/v1/import-transactions) endpoint. The [bank data guide](/guides/importing-bank-data) covers this in full. # MX Source: https://docs.layerfi.com/integrations/banking/mx Import bank account activity aggregated through MX into your customers' books. If your platform uses [MX](https://www.mx.com/) for bank connectivity, Layer can ingest the account data you already aggregate. Transactions and balances from your customers' MX-connected accounts flow into their books, so customers don't need to link their banks a second time. ## Setup Grant Layer access to your MX data and map each customer's connected accounts to their Layer business. Your Layer contact will help you establish the connection. Layer ingests transactions and balances as new activity comes in. Imported accounts behave like any other account in Layer, flowing through [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. Don't have an existing aggregator relationship? Layer's [Plaid integration](/integrations/banking/plaid) includes a fully managed connection, with prebuilt account linking UI. ## Importing directly instead To push aggregated account activity to Layer yourself, create a [Custom Account](/api-reference/v1/create-custom-account) for each account and pass its activity to the [Import Transactions](/api-reference/v1/import-transactions) endpoint. The [bank data guide](/guides/importing-bank-data) covers this in full. # Plaid Source: https://docs.layerfi.com/integrations/banking/plaid Import your customers' external bank account and credit card activity into Layer with Plaid. Layer uses [Plaid](https://plaid.com/) to connect to your customers' accounts at external financial institutions. Once an account is connected, Layer ingests its transactions and balances and incorporates them into the customer's books. There are two ways to connect Plaid accounts, depending on whether your platform already has a Plaid integration: * **Use Layer's Plaid connection** - Layer manages the Plaid relationship on your behalf. Best if you don't already integrate with Plaid. * **Use your own Plaid connection** - Keep your existing Plaid relationship and grant Layer access to the data. ## Use Layer's Plaid connection Your customers link their accounts through a Layer-powered flow, and Layer handles credential management, connection health, and data ingestion. You can present the linking flow in two ways: Drop Layer's prebuilt, white-labeled account linking component into your app. Build your own account linking experience on top of Plaid Link, powered by Layer's Plaid connection. Both options grant Layer read-only access to the customer's bank account and credit card activity. Once accounts are connected, transactions begin flowing into Layer automatically. ## Use your own Plaid connection If your platform already integrates with Plaid, you don't need to ask customers to link their accounts again. Grant Layer access to your existing Plaid data using processor tokens. [Link](https://plaid.com/docs/link/#link-flow-overview) a customer's bank account with Plaid as usual, obtaining an `access_token`. Then create a processor token for each account via Plaid's [/processor/token/create](https://plaid.com/docs/api/processors/#processortokencreate) endpoint, specifying `layer` as the processor. ```bash Request theme={null} curl -X POST https://sandbox.plaid.com/processor/token/create \ -H 'Content-Type: application/json' \ -d '{ "client_id": "PLAID_CLIENT_ID", "secret": "PLAID_SECRET", "access_token": "ACCESS_TOKEN", "account_id": "ACCOUNT_ID", "processor": "layer" }' ``` Pass the processor tokens when [creating a business](/api-reference/v1/create-business), or [update an existing business](/api-reference/v1/update-business) with them. Layer begins ingesting data from the associated accounts immediately. ```bash Request theme={null} curl -X PUT https://sandbox.layerfi.com/v1/businesses/{businessId} \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "plaid_processor_tokens": [ { "processor_token": "processor-sandbox-0asd1-a92nc" } ] }' ``` Updates replace the full list of processor tokens on the business. Include every token you want associated, since any existing tokens omitted from the request are removed. If a Plaid account's access token changes, its processor tokens are invalidated. Create a new processor token and update the business with the refreshed list. To see which processor tokens are currently associated with a business, call [List Plaid Accounts](/api-reference/plaid-account/list-plaid-accounts). ## Unlinking bank accounts When a customer disconnects a Plaid link, Layer removes the connection with Plaid and archives the linked item and all of its accounts. What happens to the account's transactions depends on whether they have been categorized onto the ledger: Transactions that have already been categorized, whether categorized, split, or matched to an existing invoice, bill, payout, transfer, or manual journal entry, are *not* affected. Their ledger entries remain intact, so they continue to appear in the customer's books and reports exactly as before. Transactions that have not yet been categorized, such as those pending, awaiting Layer review, or ready for input, are archived. Archived transactions are no longer visible to the customer and are excluded from balances and reports, but the underlying records are retained. The customer's opening balances and any bank-account-level mappings are also archived when the last active external account on that bank account is disconnected. Categorized transactions are preserved because once a transaction has been posted to the ledger, its source bank transaction must remain in-system: the ledger entry depends on it, and removing it would change the customer's financial reports. Unlinking therefore archives only uncategorized transactions. Users are not allowed to remove transactions from Plaid accounts. Users are only allowed to remove transactions from custom accounts, where transactions are either from an CSV upload or manually recorded expenses or income. Unlinking also calls Plaid's `/item/remove`, which invalidates the item's access token. The disconnected Plaid item cannot be reconnected. To resume syncing, the customer must complete a new Plaid Link flow, which creates a new item. Transactions that Plaid had already reported to Layer are retained in the archived state described above. For the full walkthrough, see the [bank data guide](/guides/importing-bank-data). # Stripe Treasury Source: https://docs.layerfi.com/integrations/banking/stripe Sync activity from Stripe Treasury financial accounts into your customers' books. Layer connects to [Stripe Treasury](https://stripe.com/treasury) to import activity from the embedded bank accounts your platform offers. Payments in, transfers out, and card spend all post to the customer's books without a separate import step. ## Setup Share Stripe API access with Layer using the [Stripe configuration](/api-reference/v1/update-stripe-configuration) endpoint, then map each Layer business to its Stripe entities, such as a connected account. Layer ingests transactions and balances from each customer's Treasury financial accounts as new activity comes in. Those accounts then behave like any other account in Layer, flowing through [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. Also processing payments with Stripe? See the [Stripe payments integration](/integrations/payments/stripe) to bring that revenue into the books as well. # Unit Source: https://docs.layerfi.com/integrations/banking/unit Sync activity from Unit-powered bank accounts and cards into your customers' books. Layer connects to [Unit](https://www.unit.co/) to import activity from the bank accounts and cards your platform issues. Deposits, card transactions, and transfers all reach the customer's books automatically. ## Setup Grant Layer read access to your Unit data, then link each customer's Unit accounts to their Layer business with the `unit_accounts` field, an array of Unit account IDs, when [creating a business](/api-reference/v1/create-business). Layer ingests transactions and balances from the linked accounts as new activity comes in. The accounts then behave like any other account in Layer, flowing through [transaction categorization](/guides/transaction-categorization) and [reporting](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. # Amazon S3 Source: https://docs.layerfi.com/integrations/data-warehouses/amazon-s3 Export your customers' accounting data from Layer to an Amazon S3 bucket. Layer can deliver your platform's accounting data as files to an [Amazon S3](https://aws.amazon.com/s3/) bucket you control. Unlike Layer's other integrations, this one flows outward: bank transactions, ledger activity, and report outputs from Layer arrive in your bucket on a schedule, ready to load into whatever stack sits downstream. ## Setup Work with your Layer contact to choose the datasets you need, the delivery schedule, and the destination bucket and prefix. Once configured, Layer keeps the exported files current, and each customer's records carry their business ID so you can join them to your own data. Typical uses include feeding a data lake, archiving accounting records, and staging data for downstream ETL into your warehouse of choice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Pulling data via API instead For one-off or lighter-weight needs, the API exposes the same data directly: list endpoints such as [List Bank Transactions](/api-reference/v1/list-bank-transactions) and [List Ledger Entries](/api-reference/v1/list-ledger-entries), and export endpoints such as [Export Ledger Entries as CSV](/api-reference/v1/export-ledger-entries-csv). # Google Cloud Storage Source: https://docs.layerfi.com/integrations/data-warehouses/google-cloud-storage Export your customers' accounting data from Layer to a Google Cloud Storage bucket. Layer can deliver your platform's accounting data as files to a [Google Cloud Storage](https://cloud.google.com/storage) bucket you control. Unlike Layer's other integrations, this one flows outward: bank transactions, ledger activity, and report outputs from Layer arrive in your bucket on a schedule, ready to load into BigQuery or whatever sits downstream. ## Setup Work with your Layer contact to choose the datasets you need, the delivery schedule, and the destination bucket and prefix. Once configured, Layer keeps the exported files current, and each customer's records carry their business ID so you can join them to your own data. Typical uses include feeding BigQuery for platform-wide financial analytics, archiving accounting records, and staging data for downstream ETL. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Pulling data via API instead For one-off or lighter-weight needs, the API exposes the same data directly: list endpoints such as [List Bank Transactions](/api-reference/v1/list-bank-transactions) and [List Ledger Entries](/api-reference/v1/list-ledger-entries), and export endpoints such as [Export Ledger Entries as CSV](/api-reference/v1/export-ledger-entries-csv). # Snowflake Source: https://docs.layerfi.com/integrations/data-warehouses/snowflake Export your customers' accounting data from Layer to your Snowflake warehouse. Layer can deliver your platform's accounting data to [Snowflake](https://www.snowflake.com/), where it sits alongside the rest of your product data. Unlike Layer's other integrations, this one flows outward: bank transactions, ledger activity, and report outputs from Layer land in your warehouse on a schedule, ready to query. ## Setup Work with your Layer contact to choose the datasets you need, the delivery schedule, and the Snowflake destination. Once configured, Layer keeps the exported data current, and each customer's records carry their business ID so you can join them to your own tables. Typical uses include platform-wide financial analytics, powering internal dashboards, and enriching your existing customer models with accounting activity. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Pulling data via API instead For one-off or lighter-weight needs, the API exposes the same data directly: list endpoints such as [List Bank Transactions](/api-reference/v1/list-bank-transactions) and [List Ledger Entries](/api-reference/v1/list-ledger-entries), and export endpoints such as [Export Ledger Entries as CSV](/api-reference/v1/export-ledger-entries-csv). # Fundbox Source: https://docs.layerfi.com/integrations/lending/fundbox Sync Fundbox working capital activity into your customers' books. Layer connects to [Fundbox](https://fundbox.com/) to import the working capital your platform offers through it. Draws, repayments, and fees post to each customer's books, and outstanding balances are carried as liabilities on their balance sheet. ## Setup Grant Layer access to your Fundbox data and map each Layer business to its Fundbox account. Your Layer contact will help you establish the connection. Layer records proceeds when a customer draws on their financing and tracks repayments and fees as they occur. When the customer's [bank data](/guides/importing-bank-data) is connected, the cash movement reconciles against their account activity, keeping balances and financing costs accurate in their [reports](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push financing activity to Layer yourself, use the [Loans API](/api-reference/loan/loan) to record loans, proceeds, and payments. The [loan data guide](/guides/importing-loan-data) covers Layer's loan model, including [lines of credit](/guides/loans/lines-of-credit) and other financing structures. # Parafin Source: https://docs.layerfi.com/integrations/lending/parafin Sync Parafin capital activity into your customers' books. If your platform offers business financing through [Parafin](https://www.parafin.com/), Layer can import that activity directly. Advances, repayments, and fees post to each customer's books, and outstanding balances are carried as liabilities on their balance sheet. ## Setup Grant Layer access to your Parafin data and map each Layer business to its Parafin recipient. Your Layer contact will help you establish the connection. Layer records proceeds when capital is deployed and tracks repayments as they occur, including repayments collected as a share of sales. When the customer's [bank data](/guides/importing-bank-data) is connected, the cash movement reconciles against their account activity, keeping balances and financing costs accurate in their [reports](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push financing activity to Layer yourself, use the [Loans API](/api-reference/loan/loan) to record loans, proceeds, and payments. The [loan data guide](/guides/importing-loan-data) covers Layer's loan model, including [merchant cash advances](/guides/loans/merchant-cash-advances) and other financing structures. # Pipe Source: https://docs.layerfi.com/integrations/lending/pipe Sync Pipe capital activity into your customers' books. If your platform offers embedded capital through [Pipe](https://pipe.com/), Layer can import that activity directly. Advances, repayments, and fees post to each customer's books, and outstanding balances are carried as liabilities on their balance sheet. ## Setup Grant Layer access to your Pipe data and map each Layer business to its Pipe recipient. Your Layer contact will help you establish the connection. Layer records proceeds when capital is deployed and tracks repayments as they occur, including repayments collected as a share of revenue. When the customer's [bank data](/guides/importing-bank-data) is connected, the cash movement reconciles against their account activity, keeping balances and financing costs accurate in their [reports](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push financing activity to Layer yourself, use the [Loans API](/api-reference/loan/loan) to record loans, proceeds, and payments. The [loan data guide](/guides/importing-loan-data) covers Layer's loan model, including [merchant cash advances](/guides/loans/merchant-cash-advances) and other financing structures. # Stripe Capital Source: https://docs.layerfi.com/integrations/lending/stripe-capital Sync Stripe Capital financing activity into your customers' books. Layer connects to [Stripe Capital](https://stripe.com/capital) to import the financing your platform offers through Stripe. When a customer accepts an offer, the proceeds, repayments, and fees post to their books, and the outstanding balance is carried as a liability on their balance sheet. ## Setup Grant Layer access to your Stripe Capital data and map each Layer business to its Stripe entities. Your Layer contact will help you establish the connection. Layer records financing proceeds when capital is deployed and tracks repayments as they occur, including repayments collected as a percentage of sales. When the customer's [bank data](/guides/importing-bank-data) is connected, the cash movement reconciles against their account activity, keeping loan balances and expenses accurate in their [reports](/guides/reporting). This integration is enabled per platform. Reach out to your Layer contact to turn it on. Using Stripe for payments or embedded bank accounts too? See the [Stripe payments](/integrations/payments/stripe) and [Stripe Treasury](/integrations/banking/stripe) integrations. ## Importing directly instead To push financing activity to Layer yourself, use the [Loans API](/api-reference/loan/loan) to record loans, proceeds, and payments. The [loan data guide](/guides/importing-loan-data) covers Layer's loan model, including [merchant cash advances](/guides/loans/merchant-cash-advances) and other financing structures. # Adyen Source: https://docs.layerfi.com/integrations/payments/adyen Import payments and payouts from Adyen into your customers' books. Layer connects to [Adyen](https://www.adyen.com/) to import the payments your customers process through it. Sales post as revenue on the customer's books, and payouts are tracked so settlement deposits reconcile against bank activity. ## Setup Grant Layer access to your Adyen data and map each Layer business to its Adyen account. Your Layer contact will help you establish the connection. Layer ingests payment and payout activity as it settles. Payments post as sales on the customer's books. When the customer's [bank data](/guides/importing-bank-data) is also connected, Layer matches payouts against the corresponding deposits, so the same revenue isn't counted twice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push sales activity to Layer yourself, use the [Invoices](/api-reference/invoice/invoice), [Invoice Payments](/api-reference/invoice/payments), and [Payouts](/api-reference/customer-payouts/payout) APIs. The [sales / AR data guide](/guides/importing-sales-ar-data) covers this in full. # Moov Source: https://docs.layerfi.com/integrations/payments/moov Import payments and transfers from Moov into your customers' books. If your platform moves money with [Moov](https://moov.io/), Layer can import that activity directly. Payments your customers collect post as revenue on their books, and transfers out to their bank accounts are tracked so deposits reconcile cleanly. ## Setup Grant Layer access to your Moov data and map each Layer business to its Moov account. Your Layer contact will help you establish the connection. Layer ingests payment and transfer activity as it occurs. Collected payments post as sales on the customer's books. When the customer's [bank data](/guides/importing-bank-data) is also connected, Layer matches transfers against the corresponding deposits, so the same revenue isn't counted twice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push sales activity to Layer yourself, use the [Invoices](/api-reference/invoice/invoice), [Invoice Payments](/api-reference/invoice/payments), and [Payouts](/api-reference/customer-payouts/payout) APIs. The [sales / AR data guide](/guides/importing-sales-ar-data) covers this in full. # PayPal Source: https://docs.layerfi.com/integrations/payments/paypal Import payments and payouts from PayPal into your customers' books. Layer connects to [PayPal](https://www.paypal.com/) to import the sales your customers collect through it. Payments post as revenue on the customer's books, and withdrawals to their bank account are tracked so deposits reconcile against bank activity. ## Setup Grant Layer access to your customers' PayPal activity and map each Layer business to its PayPal account. Your Layer contact will help you establish the connection. Layer ingests payment and payout activity as it occurs. Payments post as sales on the customer's books, net of refunds. When the customer's [bank data](/guides/importing-bank-data) is also connected, Layer matches PayPal withdrawals against the corresponding bank deposits, so the same revenue isn't counted twice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push sales activity to Layer yourself, use the [Invoices](/api-reference/invoice/invoice), [Invoice Payments](/api-reference/invoice/payments), and [Payouts](/api-reference/customer-payouts/payout) APIs. The [sales / AR data guide](/guides/importing-sales-ar-data) covers this in full. # Rainforest Source: https://docs.layerfi.com/integrations/payments/rainforest Import payments and payouts from Rainforest into your customers' books. Layer connects to [Rainforest](https://www.rainforestpay.com/) to import the payments your customers process through it. Sales post as revenue on the customer's books, and payouts are tracked so settlement deposits reconcile against bank activity. ## Setup Grant Layer access to your Rainforest data and map each Layer business to its Rainforest merchant account. Your Layer contact will help you establish the connection. Layer ingests payment and payout activity as it settles. Payments post as sales on the customer's books. When the customer's [bank data](/guides/importing-bank-data) is also connected, Layer matches payouts against the corresponding deposits, so the same revenue isn't counted twice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Importing directly instead To push sales activity to Layer yourself, use the [Invoices](/api-reference/invoice/invoice), [Invoice Payments](/api-reference/invoice/payments), and [Payouts](/api-reference/customer-payouts/payout) APIs. The [sales / AR data guide](/guides/importing-sales-ar-data) covers this in full. # Stripe Payments Source: https://docs.layerfi.com/integrations/payments/stripe Import payments and payouts from Stripe into your customers' books. Layer connects to [Stripe](https://stripe.com/) to import the payments your customers collect. Payments are recorded as revenue on the customer's books, and payouts are tracked so deposits reconcile against bank activity. ## Setup Share Stripe API access with Layer using the [Stripe configuration](/api-reference/v1/update-stripe-configuration) endpoint, then map each Layer business to its Stripe entities, such as a connected account. Layer ingests payment and payout activity as it occurs. Payments post as sales on the customer's books. When the customer's [bank data](/guides/importing-bank-data) is also connected, Layer matches payouts against the corresponding bank deposits, so the same revenue isn't counted twice. This integration is enabled per platform. Reach out to your Layer contact to turn it on. Once it's live, you can manage the connection with the [Stripe configuration endpoints](/api-reference/v1/fetch-stripe-configuration). Offering embedded bank accounts through Stripe Treasury? See the [Stripe Treasury integration](/integrations/banking/stripe) to bring that account activity into the books as well. ## Importing directly instead To push sales activity to Layer yourself, use the [Invoices](/api-reference/invoice/invoice), [Invoice Payments](/api-reference/invoice/payments), and [Payouts](/api-reference/customer-payouts/payout) APIs. The [sales / AR data guide](/guides/importing-sales-ar-data) covers this in full. # Check Source: https://docs.layerfi.com/integrations/payroll/check Integrate Check Payroll with Layer to sync payroll data into your customers' books. Layer connects to [Check](https://www.checkhq.com/) to import payroll runs from the embedded payroll your platform offers. Once a Layer business is linked to its Check company, wages, employer taxes, and the resulting liabilities post to the customer's books without manual journal entries. Payroll support may need to be enabled for your platform. Reach out to your Layer contact for access. ## Linking a Business Use the following steps to establish the connection between a Layer business and a Check company. This step establishes the mapping between a Layer business and a Check company. **Endpoint:** `PUT /v1/businesses/{businessId}/payroll/check/configs` See the [Layer documentation](/api-reference/v1/create-check-payroll-config) for full details on this endpoint. ```json theme={null} { "check_company_id": "" } ``` Once the mapping is established, the Layer system knows to anticipate an OAuth flow. Proceed to authorize the integration with Check Payroll. **Endpoint:** `PUT /integrations/partners/{integrationPartnerId}/authorize` See the [Check documentation](https://docs.checkhq.com/reference/integration-partners-copy) for full details on this endpoint. ```json theme={null} { "company": "", "integration_permission": "", "tos_timestamp": "", "product_purchase_timestamp": "" } ``` ## Check IDs The `integrationPartnerId` and `integrationPermissionId` values used in Step 2 differ between sandbox and production. Use these fixed values for sandbox testing: | Parameter | Value | | - | - | | Integration Partner ID | `int_Ccn63OpX6zKfIvssRdyB` | | Integration Permission ID | `ipe_S2LMi4ckzax5YdN8BokZ` | Production IDs must be fetched from the Check API using your own credentials. **Fetch the Integration Partner ID** Call `GET /integrations/partners` and find the entry where `name` is `"Layer"`. See the [Check documentation](https://docs.checkhq.com/reference/integration-partners) for full details. ```bash cURL theme={null} curl https://api.checkhq.com/integrations/partners \ -H "Authorization: Bearer " ``` ```json Response theme={null} { "results": [ { "id": "", "name": "Layer", "description": "Embedded accounting" } ] } ``` **Fetch the Integration Permission ID** Call `GET /integrations/permissions` and find the entry whose `integration_partner` matches the ID returned above and whose `access_type` is `"Active"`. ```bash cURL theme={null} curl https://api.checkhq.com/integrations/permissions \ -H "Authorization: Bearer " ``` ```json Response theme={null} { "results": [ { "id": "", "access_type": "Active", "integration_partner": "", "scope": [] } ] } ``` # Gusto Embedded Source: https://docs.layerfi.com/integrations/payroll/gusto-embedded Sync payroll from Gusto Embedded into your customers' books. Layer connects to [Gusto Embedded](https://gusto.com/embedded-payroll) to import payroll runs from the embedded payroll your platform offers. Wages, employer taxes, and the resulting liabilities all post to the customer's books without manual journal entries. Payroll support may need to be enabled for your platform. Reach out to your Layer contact for access. ## Setup Grant Layer access to your Gusto Embedded payroll data and map each Layer business to its Gusto company. Your Layer contact will help you establish the connection. Layer then ingests payroll runs as they're processed. Each run posts to the customer's general ledger, and the cash movement reconciles against their [bank activity](/guides/importing-bank-data) once that's connected. Payroll expense shows up in their [reports](/guides/reporting) from there. For more on how payroll data fits into your customers' books, see the [payroll data guide](/guides/importing-payroll-data). # Salsa Source: https://docs.layerfi.com/integrations/payroll/salsa Sync payroll from Salsa embedded payroll into your customers' books. Layer connects to [Salsa](https://www.salsa.dev/) to import payroll runs from the embedded payroll your platform offers. Wages, employer taxes, and the resulting liabilities all post to the customer's books without manual journal entries. Payroll support may need to be enabled for your platform. Reach out to your Layer contact for access. ## Setup Grant Layer access to your Salsa payroll data and map each Layer business to its Salsa employer. Your Layer contact will help you establish the connection. Layer then ingests payroll runs as they're processed. Each run posts to the customer's general ledger, and the cash movement reconciles against their [bank activity](/guides/importing-bank-data) once that's connected. Payroll expense shows up in their [reports](/guides/reporting) from there. For more on how payroll data fits into your customers' books, see the [payroll data guide](/guides/importing-payroll-data). # April Source: https://docs.layerfi.com/integrations/tax/april Power embedded tax filing with Layer-maintained, tax-ready financials. If your platform offers embedded tax filing through [April](https://www.getapril.com/), Layer can supply the financial data that filing depends on. Layer keeps each customer's books categorized and current throughout the year, so their income, expenses, and deductions are ready at filing time rather than reconstructed by hand. ## How it works Throughout the year, Layer ingests activity from your [banking](/integrations/banking/plaid), [payments](/integrations/payments/stripe), and [payroll](/integrations/payroll/check) integrations and keeps the books up to date. At filing time, Layer passes each customer's business financials to April, pre-filling the business income and expense portions of their return, including Schedule C data for sole proprietors. Your customers review and file through April's embedded experience without leaving your platform. This integration is enabled per platform. Reach out to your Layer contact to turn it on. ## Related resources * [Fetch Schedule C report](/api-reference/v1/fetch-schedule-c-report) - retrieve Schedule C data directly from the API * [Tax packets](/api-reference/v1/create-tax-packet) - generate a package of tax-ready financial statements * [Tax estimates](/api-reference/v1/tax-estimates/get-tax-summary) - surface quarterly tax estimates to your customers year-round # Overview Source: https://docs.layerfi.com/overview Explore our guides and documentation to integrate Layer. Layer enables you to easily add accounting software and bookkeeping services to your product. We provide UI components that you can embed directly in your app and a REST API to build custom functionality. If you're just getting started, check out or recommended guides below. ## Get Started Go from zero to your first embedded accounting experience, step by step. Understand Platforms, Businesses, the general ledger, and how data flows through Layer. Drop Layer's pre-built, white-labeled React components directly into your app. Give AI agents access to Layer accounting data and bookkeeping actions via Model Context Protocol. ## Getting access To get started with Layer, [reach out to our team](https://www.layerfi.com/contact). We'll provide sandbox access for development and guide you through the integration process.