# Abandon Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/abandon-bill-draft https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill-draft/{id}/abandon POST /bill-draft//abandon — hard-delete an unfinished UI upload draft. # Bill Stat Card Aggregates Source: https://docs.campfire.ai/api-reference/accounts-payable/bill-stat-card-aggregates https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill/stats Customer-scoped counts and outstanding amounts for the Bills page Needs Approval / Awaiting Payment / Overdue stat cards. # Bills Inbox open-item count Source: https://docs.campfire.ai/api-reference/accounts-payable/bills-inbox-open-item-count https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill-draft/inbox-count GET /bill-draft/inbox-count — count of open inbox drafts for the nav badge. # Bulk Search Bills by Number Source: https://docs.campfire.ai/api-reference/accounts-payable/bulk-search-bills-by-number https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/bulk-search Search for thousands of bills by exact bill number match in a single request. Optimized for performance. # Bulk Search Debit Memos by Number Source: https://docs.campfire.ai/api-reference/accounts-payable/bulk-search-debit-memos-by-number https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo/bulk-search Search for thousands of debit memos by exact debit memo number match in a single request. Optimized for performance. # Bulk Sync Bills to Ramp Source: https://docs.campfire.ai/api-reference/accounts-payable/bulk-sync-bills-to-ramp https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/bulk-sync-to-ramp Sync multiple bills without a source to Ramp using the enabled Ramp connection # Create Accounting Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/create-accounting-bill https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill Creates a new accounting bill with line items and automatic journal entry generation. This endpoint allows for complex bill creation with: - Multiple line items with different accounts, departments, and vendor assignments - Automatic accounts payable journal entry creation - Tax calculations and tax account handling - Exchange rate support for multi-currency transactions - Custom field support for additional bill metadata Requirements: - All referenced accounts must exist and be active - Vendor must exist - Entity must exist - Line items must have valid amounts and descriptions - Currency must be valid for the entity - Accounting date must be before closed book date # Create Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/create-bill-draft https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill-draft GET list (customer-scoped, AG Grid server-side: paginate / sort / filter) + POST UI upload. # Create Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/create-debit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo Creates a new accounting debit memo with line items and automatic journal entry generation. Debit memos are used to record amounts owed to vendors or to adjust vendor account balances. This endpoint handles multi-currency transactions, departmental allocations, and automatic double-entry bookkeeping. # Delete Accounting Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/delete-accounting-bill https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/bill/{id} Permanently deletes an accounting bill and its associated journal entry. This endpoint performs a complete deletion of the bill including: - Removal of all bill line items and associated data - Deletion of the corresponding accounts payable journal entry - Cleanup of any tax calculations and allocations - Removal of vendor payment allocations if applicable **Important Notes:** - This operation is irreversible and permanently removes the bill from the system - The associated journal entry will be automatically deleted to maintain accounting integrity - All double-entry bookkeeping records related to this bill will be removed - Any payments allocated to this bill should be handled separately before deletion - Deletion may affect financial reports and account balances **Restrictions:** - Bills with allocated payments may require payment reallocation first - Consider the impact on historical financial reporting - Bills cannot be deleted in a closed period # Delete Bill Payment Source: https://docs.campfire.ai/api-reference/accounts-payable/delete-bill-payment https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/bill/{bill_id}/payment/{payment_id}/void Delete a bill payment. This removes the payment record and updates the transaction to uncategorized. # Delete Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/delete-debit-memo https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/debit-memo/{id} # Delete Debit Memo Used Payment Source: https://docs.campfire.ai/api-reference/accounts-payable/delete-debit-memo-used-payment https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/debit-memo/{debit_memo_id}/payment/{payment_id}/void Remove a debit memo 'mark used' payment application. This recategorizes the transaction back to Uncategorized and deletes the payment record. # Discard Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/discard-bill-draft https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill-draft/{id}/discard POST /bill-draft//discard — terminal state with a required reason. # Generate Bill Amortization Schedule Source: https://docs.campfire.ai/api-reference/accounts-payable/generate-bill-amortization-schedule https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill/amortization/generate-schedule # Get Default Department and Tags for Empty Transaction Source: https://docs.campfire.ai/api-reference/accounts-payable/get-default-department-and-tags-for-empty-transaction https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill/{bill_id}/empty-transaction-default-department-tags Get the default department and tags from the bill line with the largest total amount. This endpoint is used to provide default values when creating empty transactions (marking as paid without a transaction). The total amount is calculated as: amount + tax. If multiple lines have the same total amount, the line with the lowest ID (first created) is selected. The department and tags are retrieved directly from the bill line. # Get Next Debit Memo Number Source: https://docs.campfire.ai/api-reference/accounts-payable/get-next-debit-memo-number https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/debit-memo/next-debit-memo-number # List Accounting Bills Source: https://docs.campfire.ai/api-reference/accounts-payable/list-accounting-bills https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill Retrieve a paginated list of accounting bills with comprehensive filtering, search, and sorting capabilities. This endpoint provides complete access to your bills data with: - Advanced filtering by date ranges, payment status, vendors, entities, and currency - Full-text search across bill numbers, vendor names, addresses, and bill messages - Flexible sorting by any field including calculated fields (totals, amounts due, etc.) - Comprehensive pagination with customizable page sizes - Aging calculations and payment status categorization - Automatic calculation of totals, amounts paid, and amounts due **Deleted Records Support:** - When include_deleted=true: Returns ONLY deleted bills with minimal data (id, is_deleted, deleted_at, last_modified_at) - When include_deleted=false or omitted: Returns ONLY active bills with full data - Timestamp filtering (last_modified_at__gte/lte) works with both active and deleted records # List Bill Drafts Source: https://docs.campfire.ai/api-reference/accounts-payable/list-bill-drafts https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill-draft GET list (customer-scoped, AG Grid server-side: paginate / sort / filter) + POST UI upload. # List Bill Payments Source: https://docs.campfire.ai/api-reference/accounts-payable/list-bill-payments https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill-payments Retrieve a paginated list of bill payments (payments applied against accounts payable bills), designed for syncing payment data into external systems. Results are ordered by (last_modified_at, id) ascending, so pages are stable and a sync can resume from where it left off. **Full sync (cursor pagination):** - Pass an empty cursor parameter (cursor=) on the first request - Follow the 'next' URL from each response until it is null **Incremental sync (time-based):** - Store the highest last_modified_at value you have processed - On the next run, pass it as last_modified_at__gte to fetch only new and updated payments **Voids:** - Voided payments are included by default with voided_date set, so integrators can detect payments that were reversed after a previous sync - Filter with voided=true or voided=false to fetch only one kind # List Debit Memos Source: https://docs.campfire.ai/api-reference/accounts-payable/list-debit-memos https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/debit-memo Retrieves a paginated list of accounting debit memos with filtering and sorting capabilities. Supports filtering by date ranges, status, vendors, entities, and full-text search. # Mark Bill as Paid Source: https://docs.campfire.ai/api-reference/accounts-payable/mark-bill-as-paid https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/{bill_id}/pay Mark a bill as paid, allowing partial payments. This endpoint supports multiple payment methods: - Apply existing transactions as payments - Apply debit memos to reduce the bill balance - Create manual payments without a transaction The request body should contain at least one of: - transactions: List of transaction payments to apply - debit_memos: List of debit memos to apply - empty_transactions: List of manual payments without transactions # Mark Debit Memo as Used Source: https://docs.campfire.ai/api-reference/accounts-payable/mark-debit-memo-as-used https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo/{debit_memo_id}/mark-used Mark a debit memo as used by linking to an existing credit-side transaction. The transaction's credit amount will be recategorized to A/P to clear the debit memo. The debit memo's status will be updated to "used" or "partially_used" based on the amount applied vs the total amount. # Partial Update Accounting Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/partial-update-accounting-bill https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v1/bill/{id} Performs a partial update of an existing accounting bill using PATCH semantics. This endpoint allows selective modification of bill fields without requiring a complete bill replacement. You can update specific aspects of the bill while leaving other fields unchanged. **Updatable Fields:** - Bill metadata (number, dates, descriptions, vendor, entity) - Line items (amounts, accounts, descriptions, departments) - Payment terms and due dates - Tax calculations and allocations - Custom fields and tags - Currency and exchange rates # Partial Update Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/partial-update-bill-draft https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v1/bill-draft/{id} GET detail + PATCH update on a single BillDraft. # Partial Update Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/partial-update-debit-memo https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v1/debit-memo/{id} Performs a partial update of an existing accounting debit memo using PATCH semantics. This endpoint allows selective modification of debit memo fields without requiring a complete replacement. # Promote Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/promote-bill-draft https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill-draft/{id}/promote POST /bill-draft//promote — routes through the promote service. # Reopen Voided Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/reopen-voided-bill https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/{bill_id}/reopen Reopen a voided bill. This removes the void date and void journal entry, and sets the bill status back to open. The voiding journal entry will be deleted to reverse the void operation. # Reopen Voided Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/reopen-voided-debit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo/{debit_memo_id}/reopen Reopen a voided debit memo. This removes the void date and void journal entry, and sets the debit memo status back to open. The voiding journal entry will be deleted to reverse the void operation. # Retrieve Accounting Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/retrieve-accounting-bill https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill/{id} Retrieve a single accounting bill by ID with complete detail including all line items, payments, and related data. This endpoint returns comprehensive bill information including: - Full bill details with vendor, entity, and customer information - All line items with account details, departments, tags, and amortization schedules - Complete payment history with journal entry references - Calculated fields including total amounts, amounts paid, amounts due, and payment status - Journal entry references for accounting integration - Exchange rate information for multi-currency bills # Retrieve Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/retrieve-bill-draft https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/bill-draft/{id} GET detail + PATCH update on a single BillDraft. # Retrieve Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/retrieve-debit-memo https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/debit-memo/{id} Retrieves a single accounting debit memo with complete details including line items, payments, and accounting relationships. # Save Bill Amortization Schedule Source: https://docs.campfire.ai/api-reference/accounts-payable/save-bill-amortization-schedule https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/bill/amortization/generate-schedule # Sync Bill to Ramp Source: https://docs.campfire.ai/api-reference/accounts-payable/sync-bill-to-ramp https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/{bill_id}/sync-to-ramp Sync a bill without a source to Ramp using the enabled Ramp connection # Update Accounting Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/update-accounting-bill https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/bill/{id} Update an existing accounting bill with complete replacement of all data including line items and metadata. This endpoint performs a full update (PUT) of an accounting bill with: - Complete replacement of all bill data including vendor, entity, dates, and terms - Full replacement of all line items with new account assignments, amounts, and descriptions - Automatic recalculation of journal entries and accounting transactions - Preservation of payment history while updating balances and amounts due - Validation of all referenced accounts, vendors, entities, and departments - Automatic exchange rate updates for multi-currency bills - Custom field updates and attachment management # Update Bill Draft Source: https://docs.campfire.ai/api-reference/accounts-payable/update-bill-draft https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/bill-draft/{id} GET detail + PATCH update on a single BillDraft. # Update Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/update-debit-memo https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/debit-memo/{id} Performs a complete update of an existing accounting debit memo using PUT semantics. This endpoint allows full replacement of debit memo data including line items and journal entry recalculation. # Void Bill Source: https://docs.campfire.ai/api-reference/accounts-payable/void-bill https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/{bill_id}/void Void an existing bill. This creates a reversing journal entry to void the bill by reversing all debit and credit amounts. The bill status will be updated to reflect the void. # Void Bill Payment Source: https://docs.campfire.ai/api-reference/accounts-payable/void-bill-payment https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/bill/{bill_id}/payment/{payment_id}/void Void an existing bill payment. This creates a reversing journal entry to void the payment and updates the bill status. Optionally accepts a void_date in the request body to specify when the payment should be voided. If not provided, defaults to today's date. # Void Debit Memo Source: https://docs.campfire.ai/api-reference/accounts-payable/void-debit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo/{debit_memo_id}/void Void an existing debit memo. This creates a reversing journal entry to void the debit memo by reversing all debit and credit amounts. The debit memo status will be updated to reflect the void. # Void Debit Memo Used Payment Source: https://docs.campfire.ai/api-reference/accounts-payable/void-debit-memo-used-payment https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/debit-memo/{debit_memo_id}/payment/{payment_id}/void Void a debit memo 'mark used' payment by creating a reversing journal entry. This creates a reversing JE that credits the A/P account and debits Uncategorized, then marks the payment as voided. # Bulk Apply Transaction Payment to Selected Invoices Source: https://docs.campfire.ai/api-reference/accounts-receivable/bulk-apply-transaction-payment-to-selected-invoices https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/bulk-apply-payment Apply a single transaction payment to multiple selected invoices. Supports two selection modes: - Explicit invoice IDs (``invoice_ids``) - Filter-based selection (``filters``) for "select all matching" behaviour Reuses :meth:`MarkInvoicePaidView.apply_transaction_payment` so that line-level payment splitting, FX gain/loss realisation, and transaction cleanup are all respected. A single ``DraftQueue`` is created when approval is required. # Bulk Create Invoices Source: https://docs.campfire.ai/api-reference/accounts-receivable/bulk-create-invoices https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/bulk-create Create multiple invoices atomically in a single transaction. All invoices are created within a single database transaction. If any invoice creation fails, all invoices are rolled back and no invoices are created. This endpoint validates all invoices before creating any of them, ensuring data integrity. # Bulk Search Credit Memos by Number Source: https://docs.campfire.ai/api-reference/accounts-receivable/bulk-search-credit-memos-by-number https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo/bulk-search Search for thousands of credit memos by exact credit memo number match in a single request. Optimized for performance. # Bulk Search Invoices by Number Source: https://docs.campfire.ai/api-reference/accounts-receivable/bulk-search-invoices-by-number https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/bulk-search Search for thousands of invoices by exact invoice number match in a single request. Optimized for performance. # Calculate Invoice Payment Source: https://docs.campfire.ai/api-reference/accounts-receivable/calculate-invoice-payment https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/calculate-payment Calculate the payment details for an invoice. This endpoint calculates: - Total amount due on the invoice - Applied payments (existing + proposed) - Applied credits (existing + proposed credit memos) - Payment term discounts (based on payment dates) - ALL OR NOTHING: discount only applies if paying full invoice - Remaining balance due Supports payment terms with early payment discounts (all-or-nothing). # Create Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/create-credit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo Creates a new accounting credit memo with line items and automatic journal entry generation. This endpoint allows for comprehensive credit memo creation with: - Multiple line items with different products, accounts, amounts, and departmental allocations - Automatic journal entry creation following double-entry bookkeeping principles - Multi-currency support with exchange rate handling - Client and entity relationship management - Contract associations for revenue recognition tracking - Product-based line item categorization with tax handling - Tag-based transaction categorization and reporting # Create Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/create-invoice https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice Creates a new accounting invoice with line items and automatic journal entry generation. This endpoint allows for comprehensive invoice creation with: - Multiple line items with different products, rates, quantities, and tax handling - Automatic accounts receivable journal entry creation - Tax calculations and tax account handling - Multi-currency support with exchange rate handling - Product-based taxation rules - Service date tracking for revenue recognition - Contract and purchase order integration - Stripe payment integration support Key features: - Credits revenue accounts for each line item amount - Debits accounts receivable for the total amount - Handles tax calculations with appropriate tax accounts - Supports entity-specific currency conversions - Creates proper double-entry accounting transactions - Validates client, entity, and product relationships - Integrates with Stripe for payment processing Requirements: - All referenced products, clients, and entities must exist and be active - Client must be of type 'customer' - Line items must have valid amounts, quantities, and rates - Currency must be valid for the entity - Tax calculations must comply with configured tax rules # Delete Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/delete-credit-memo https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/credit-memo/{id} Permanently deletes an accounting credit memo and all associated data from the system. This endpoint performs a complete removal of the credit memo including: - Complete credit memo record deletion with all line items - Automatic journal entry removal and accounting transaction cleanup **Accounting Impact:** - Associated journal entries are automatically deleted to maintain accounting integrity - Exchange rate records and multi-currency data are cleaned up **Restrictions:** - Credit memos that have been applied to invoices cannot be deleted - Credit memos in closed accounting periods may have deletion restrictions - Consider the impact on historical financial reporting # Delete Credit Memo Used Payment Source: https://docs.campfire.ai/api-reference/accounts-receivable/delete-credit-memo-used-payment https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/credit-memo/{credit_memo_id}/payment/{payment_id}/void Remove a credit memo 'mark used' payment application. This recategorizes the transaction back to Uncategorized and deletes the payment record. # Delete Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/delete-invoice https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/invoice/{id} Permanently deletes an accounting invoice and its associated journal entry and related data. This endpoint performs a complete deletion of the invoice including: - Removal of all invoice line items and associated product data - Deletion of the corresponding accounts receivable journal entry - Removal of payment records and journal entries **Important Notes:** - This operation is irreversible and permanently removes the invoice from the system - The associated journal entry will be automatically deleted to maintain accounting integrity **Restrictions:** - Invoices in closed accounting periods cannot be deleted - Consider the impact on historical financial reporting # Delete Invoice Payment Source: https://docs.campfire.ai/api-reference/accounts-receivable/delete-invoice-payment https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v1/invoice/{invoice_id}/payment/{payment_id}/void Delete an invoice payment. This removes the payment record and updates the transaction to uncategorized. For Stripe payments, this will also process a refund through Stripe. # Execute invoice report Source: https://docs.campfire.ai/api-reference/accounts-receivable/execute-invoice-report https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice/report/{id}/data Execute saved invoice report and return DataTable-compatible response. :param request: HTTP request with query params :param pk: Custom report ID :return: Paginated, sparse-formatted response # Get Client Invoice Statement PDF Source: https://docs.campfire.ai/api-reference/accounts-receivable/get-client-invoice-statement-pdf https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice/statement/client/{client_id}/pdf Generate a customer statement PDF for a specific client. This creates a professional, customer-facing statement showing: - All outstanding invoices as of the specified date - Running balance - Total balance due - Payment advice slip # Get Credit Memo PDF Source: https://docs.campfire.ai/api-reference/accounts-receivable/get-credit-memo-pdf https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/credit-memo/{id}/pdf # Get Default Payment Amount Source: https://docs.campfire.ai/api-reference/accounts-receivable/get-default-payment-amount https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/default-payment Get the default payment amount for an invoice based on when payment is posted. If the invoice has discount terms and the posted date is within the discount period, the discounted amount is returned. Otherwise, the full amount is returned. # Get Next Credit Memo Number Source: https://docs.campfire.ai/api-reference/accounts-receivable/get-next-credit-memo-number https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/credit-memo/next-credit-memo-number # Invoice Stat Card Aggregates Source: https://docs.campfire.ai/api-reference/accounts-receivable/invoice-stat-card-aggregates https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice/stats Customer-scoped counts and outstanding amounts for the Invoices page Open / Sent / Overdue stat cards. # List Credit Memos Source: https://docs.campfire.ai/api-reference/accounts-receivable/list-credit-memos https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/credit-memo Retrieves a paginated list of accounting credit memos with comprehensive filtering and sorting capabilities. This endpoint provides a powerful interface for browsing and searching credit memos with: - Advanced filtering by date ranges, status, clients, entities, and contracts - Full-text search across credit memo numbers, messages, and client names - Flexible sorting by multiple fields including amounts and relationships - Optimized performance with efficient database queries and pagination - Complete credit memo details including line items, payment status, and accounting relationships **Key Features:** - Date range filtering for credit memo creation and application dates - Status-based filtering (open, partially_used, used, voided) - Client and entity-based filtering with hierarchical client support - Contract association filtering for revenue recognition workflows - Full-text search capabilities across key fields **Query Parameters:** - `start_date`, `end_date`: Filter by credit memo date range - `status`: Filter by application status (open, partially_used, used, voided) - `q`: Full-text search across credit memo number, message, and client name - `client`: Filter by specific client IDs (supports multiple values) - `entity`: Filter by specific entity IDs (supports multiple values) - `contract`: Filter by specific contract IDs (supports multiple values) - `sort`: Sort by various fields (credit_memo_date, client_name, total_amount, etc.) - `limit`, `offset`: Pagination controls for large result sets # List Invoice Payments Source: https://docs.campfire.ai/api-reference/accounts-receivable/list-invoice-payments https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice-payments Retrieve a paginated list of invoice payments (payments applied against accounts receivable invoices), designed for syncing payment data into external systems. Results are ordered by (last_modified_at, id) ascending, so pages are stable and a sync can resume from where it left off. **Full sync (cursor pagination):** - Pass an empty cursor parameter (cursor=) on the first request - Follow the 'next' URL from each response until it is null **Incremental sync (time-based):** - Store the highest last_modified_at value you have processed - On the next run, pass it as last_modified_at__gte to fetch only new and updated payments **Voids:** - Voided payments are included by default with voided_date set, so integrators can detect payments that were reversed after a previous sync - Filter with voided=true or voided=false to fetch only one kind # List Invoices Source: https://docs.campfire.ai/api-reference/accounts-receivable/list-invoices https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice Retrieve a paginated list of invoices with comprehensive filtering, sorting, and download capabilities. This endpoint provides powerful invoice listing with: - Advanced filtering by date ranges, status, clients, and entities - Full-text search across multiple fields - Flexible sorting options including custom calculated fields - Async CSV export functionality via email - Optimized queries with prefetched relationships **Filtering Options:** - Date-based filtering (invoice_date, due_date ranges) - Status-based filtering (payment status, sent status, aging buckets) - Entity and client-based filtering (supports multiple selections) - Contract and currency filtering - Full-text search across invoice numbers, addresses, messages, and client names **Sorting Capabilities:** - Standard field sorting (invoice_date, total_amount, due_date, etc.) - Custom calculated field sorting (amount_due, client_name, contract_name) - Ascending/descending order with null handling **Performance Features:** - Efficient database queries with proper indexing - Prefetched related objects (lines, payments, clients, entities) - Pagination support for large datasets - Optimized for high-volume invoice management **Export Functionality:** - Async CSV generation and email delivery - Filtered export based on current query parameters - Background processing to handle large datasets # Mark Credit Memo as Used Source: https://docs.campfire.ai/api-reference/accounts-receivable/mark-credit-memo-as-used https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo/{credit_memo_id}/mark-used Mark a credit memo as used by linking to an existing transaction. The transaction's debit amount will be recategorized to A/R to clear the credit memo. The credit memo's status will be updated to "used" or "partially_used" based on the amount applied vs the total amount. # Mark Invoice as Paid Source: https://docs.campfire.ai/api-reference/accounts-receivable/mark-invoice-as-paid https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/pay Mark an invoice as paid, allowing partial payments. This endpoint supports multiple payment methods: - Apply existing transactions as payments - Apply credit memos to reduce the invoice balance - Create manual payments without a transaction The request body should contain at least one of: - transactions: List of transaction payments to apply - credit_memos: List of credit memos to apply - empty_transactions: List of manual payments without transactions # Partial Update Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/partial-update-credit-memo https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v1/credit-memo/{id} Performs a partial update of an existing accounting credit memo using PATCH semantics. This endpoint allows selective modification of credit memo fields without requiring a complete credit memo replacement. You can update specific aspects of the credit memo while leaving other fields unchanged. **Updatable Fields:** - Credit memo metadata (dates, messages, descriptions, client, entity, currency) - Line items (amounts, accounts, descriptions, departments, products) - Reference numbers and contract associations - Exchange rates and currency information - Custom fields and additional metadata - Application status and tracking information # Partial Update Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/partial-update-invoice https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v1/invoice/{id} Performs a partial update of an existing accounting invoice using PATCH semantics. This endpoint allows selective modification of invoice fields without requiring a complete invoice replacement. You can update specific aspects of the invoice while leaving other fields unchanged. **Updatable Fields:** - Invoice metadata (dates, terms, descriptions, client, entity, currency) - Line items (amounts, accounts, descriptions, departments, products) - Payment terms and due dates - Tax calculations and allocations - Custom fields and tags - Contract and purchase order associations - Exchange rates and currency information # Preview invoice report Source: https://docs.campfire.ai/api-reference/accounts-receivable/preview-invoice-report https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice/report/preview Execute invoice report preview from query params. :param request: HTTP request with report configuration :return: Paginated response or CSV stream # Reopen Voided Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/reopen-voided-credit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo/{credit_memo_id}/reopen Reopen a voided credit memo. This removes the void date and void journal entry, and sets the credit memo status back to open. The voiding journal entry will be deleted to reverse the void operation. # Reopen Voided Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/reopen-voided-invoice https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/reopen Reopen a voided invoice. This removes the void date and void journal entry, and sets the invoice status back to open. The voiding journal entry will be deleted to reverse the void operation. # Retrieve Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/retrieve-credit-memo https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/credit-memo/{id} Retrieves a single accounting credit memo with complete details including line items, payments, and accounting relationships. This endpoint provides comprehensive credit memo information with: - Complete credit memo metadata (dates, amounts, status, currency, terms) - All associated line items with product details, account information, and departmental allocations - Payment application history with journal entry references and transaction details - Client and entity information with relationship details - Contract associations for revenue recognition and reporting - File attachments and supporting documentation - Journal entry references for accounting audit trails and compliance # Retrieve Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/retrieve-invoice https://api.meetcampfire.com/api/schema?format=json get /coa/api/v1/invoice/{id} Retrieves a single accounting invoice with complete details including line items, payments, and accounting relationships. This endpoint provides comprehensive invoice information with: - Complete invoice metadata (dates, amounts, status, terms) - All associated line items with product details and tax information - Payment history with journal entry references and transaction details # Send Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/send-credit-memo https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/credit-memo/{id}/send Send a single credit memo via email. # Update Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/update-credit-memo https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/credit-memo/{id} Performs a complete update of an existing accounting credit memo using PUT semantics. This endpoint allows full replacement of credit memo data including: - Complete credit memo metadata update (dates, amounts, client, entity, currency) - Full line item replacement with new products, accounts, amounts, and departmental allocations - Journal entry recalculation and update with new accounting transactions - Exchange rate updates for multi-currency credit memos - Contract and reference number association updates - Custom field updates and modifications **Important Notes:** - This is a full replacement operation - all credit memo data will be updated - Missing fields in the request will be set to null or default values - Existing line items will be completely replaced with the new line items - Journal entries will be updated to reflect all changes # Update Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/update-invoice https://api.meetcampfire.com/api/schema?format=json put /coa/api/v1/invoice/{id} Performs a complete update of an existing accounting invoice using PUT semantics. This endpoint allows full replacement of invoice data including: - Complete invoice metadata update (dates, amounts, terms, client, entity) - Full line item replacement with new products, quantities, rates, and tax calculations - Journal entry recalculation and update with new accounting transactions - Exchange rate updates for multi-currency invoices **Important Notes:** - This is a full replacement operation - all invoice data will be updated - Missing fields in the request will be set to null or default values - Existing line items will be completely replaced with the new line items - Journal entries will be updated to reflect all changes # Void Credit Memo Source: https://docs.campfire.ai/api-reference/accounts-receivable/void-credit-memo https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo/{credit_memo_id}/void Void an existing credit memo. This creates a reversing journal entry to void the credit memo by reversing all debit and credit amounts. The credit memo status will be updated to reflect the void. # Void Credit Memo Used Payment Source: https://docs.campfire.ai/api-reference/accounts-receivable/void-credit-memo-used-payment https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/credit-memo/{credit_memo_id}/payment/{payment_id}/void Void a credit memo 'mark used' payment by creating a reversing journal entry. This creates a reversing JE that credits the A/R account and debits Uncategorized, then marks the payment as voided. # Void Invoice Source: https://docs.campfire.ai/api-reference/accounts-receivable/void-invoice https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/void Void an existing invoice. This creates a reversing journal entry to void the invoice by reversing all debit and credit amounts. The invoice status will be updated to reflect the void. # Void Invoice Payment Source: https://docs.campfire.ai/api-reference/accounts-receivable/void-invoice-payment https://api.meetcampfire.com/api/schema?format=json post /coa/api/v1/invoice/{invoice_id}/payment/{payment_id}/void Void an existing invoice payment. This creates a reversing journal entry to void the payment and updates the invoice status. For Stripe payments, this will also process a refund through Stripe. Optionally accepts a void_date in the request body to specify when the payment should be voided. If not provided, defaults to today's date. # Bulk Match GL Transactions to Statement Transactions Source: https://docs.campfire.ai/api-reference/bank-reconciliation/bulk-match-gl-transactions-to-statement-transactions https://api.meetcampfire.com/api/schema?format=json post /coa/api/v2/reconciliation/{id}/bulk-match-transactions Match multiple GL transactions to statement transactions in a single request. Pairs are validated atomically — all succeed or none are created. # Confirm Selection of Transactions to Reconcile Source: https://docs.campfire.ai/api-reference/bank-reconciliation/confirm-selection-of-transactions-to-reconcile https://api.meetcampfire.com/api/schema?format=json post /coa/api/v2/reconciliation/{id}/transactions/confirm Confirm the selection of GL transactions for reconciliation. Pass selected transaction IDs in the request body. Selected transactions are marked as RECONCILED; deselected transactions have their status as suggested matches to this reconciliation report cleared. # Create Bank Reconciliation Report Source: https://docs.campfire.ai/api-reference/bank-reconciliation/create-bank-reconciliation-report https://api.meetcampfire.com/api/schema?format=json post /coa/api/v2/reconciliation Create a new bank reconciliation report for a specific account and date range. Cannot create overlapping date ranges for the same account and entity. # Delete Bank Reconciliation Report Source: https://docs.campfire.ai/api-reference/bank-reconciliation/delete-bank-reconciliation-report https://api.meetcampfire.com/api/schema?format=json delete /coa/api/v2/reconciliation/{id} Delete a bank reconciliation report and all associated data. # Get Bank Reconciliation Report Source: https://docs.campfire.ai/api-reference/bank-reconciliation/get-bank-reconciliation-report https://api.meetcampfire.com/api/schema?format=json get /coa/api/v2/reconciliation/{id} Retrieve a specific bank reconciliation report by ID. Includes report metadata, status, async task status for PDF processing, and attached files/CSV statements. # List Bank Reconciliation Reports Source: https://docs.campfire.ai/api-reference/bank-reconciliation/list-bank-reconciliation-reports https://api.meetcampfire.com/api/schema?format=json get /coa/api/v2/reconciliation Retrieve a paginated list of bank reconciliation reports. Supports filtering by start_date, end_date, entity, account, and search query (q). Default sort is by statement_ending_date descending. # List GL Transactions for Reconciliation Source: https://docs.campfire.ai/api-reference/bank-reconciliation/list-gl-transactions-for-reconciliation https://api.meetcampfire.com/api/schema?format=json get /coa/api/v2/reconciliation/{id}/source-transactions List source (GL) transactions available for reconciliation. Supports filtering by date range, bank, vendor, department, tag, currency, and reconciliation status. # Parse Bank Statement Page Source: https://docs.campfire.ai/api-reference/bank-reconciliation/parse-bank-statement-page https://api.meetcampfire.com/api/schema?format=json post /coa/api/v2/reconciliation/parse-statement-page Parse a bank statement PDF. Accepts: ``file_id`` (required) -- ID of the uploaded PDF ``File``. ``pages`` (optional, int) -- How many pages to include in the first parse batch. Defaults to ``BATCH_PAGE_SIZE``. Use a small value (e.g. 2) for a fast initial response with just balances and dates. Only the first batch is parsed in this request. Parsed output is cached under ``file_id`` and the effective first-batch page count (``pages`` or default ``BATCH_PAGE_SIZE``) so different ``pages`` values do not share one cache entry. # Partial Update Bank Reconciliation Report Source: https://docs.campfire.ai/api-reference/bank-reconciliation/partial-update-bank-reconciliation-report https://api.meetcampfire.com/api/schema?format=json patch /coa/api/v2/reconciliation/{id} Partially update a bank reconciliation report. Only provided fields are modified. # Update Bank Reconciliation Report Source: https://docs.campfire.ai/api-reference/bank-reconciliation/update-bank-reconciliation-report https://api.meetcampfire.com/api/schema?format=json put /coa/api/v2/reconciliation/{id} Update a bank reconciliation report. Supports partial updates via PATCH. # Create Bank Account Source: https://docs.campfire.ai/api-reference/cash-management/create-bank-account https://api.meetcampfire.com/api/schema?format=json post /ca/api/account Create a new bank account # Create Bank Transaction Source: https://docs.campfire.ai/api-reference/cash-management/create-bank-transaction https://api.meetcampfire.com/api/schema?format=json post /ca/api/transaction Create a new bank transaction # Delete Bank Account Source: https://docs.campfire.ai/api-reference/cash-management/delete-bank-account https://api.meetcampfire.com/api/schema?format=json delete /ca/api/account/{id} # Delete Bank Transaction Source: https://docs.campfire.ai/api-reference/cash-management/delete-bank-transaction https://api.meetcampfire.com/api/schema?format=json delete /ca/api/transaction/{id} # List Bank Accounts Source: https://docs.campfire.ai/api-reference/cash-management/list-bank-accounts https://api.meetcampfire.com/api/schema?format=json get /ca/api/account Retrieve a paginated list of bank accounts. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, deleted records will have is_deleted=true and include deletion metadata (deleted_at timestamp). Supports sorting by all returned fields: - name, -name (account name) - nickname, -nickname (account nickname) - type, -type (account type) - status, -status (account status) - currency, -currency (account currency) - external_account_id, -external_account_id (external account ID) - institution_id, -institution_id (institution ID) - source, -source (account source) - current_balance, -current_balance (current balance) - available_balance, -available_balance (available balance) - created_at, -created_at (creation date) - last_modified_at, -last_modified_at (last modified date) - account_type, -account_type (chart account type) - account_subtype, -account_subtype (chart account subtype) - account_cashflow_classification, -account_cashflow_classification (cashflow classification) - type_name, -type_name (human-readable account type) - subtype_name, -subtype_name (human-readable account subtype) - cashflow_classification_name, -cashflow_classification_name (human-readable cashflow classification) - entity_name, -entity_name (entity name) - department, -department (department name) - id, -id (account ID) - account_id, -account_id (UUID account ID) # List Bank Transactions Source: https://docs.campfire.ai/api-reference/cash-management/list-bank-transactions https://api.meetcampfire.com/api/schema?format=json get /ca/api/transaction Retrieve a paginated list of bank transactions with optional filtering. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, deleted records will have is_deleted=true and include deletion metadata (deleted_at timestamp). # Partial Update Bank Account Source: https://docs.campfire.ai/api-reference/cash-management/partial-update-bank-account https://api.meetcampfire.com/api/schema?format=json patch /ca/api/account/{id} # Partial Update Bank Transaction Source: https://docs.campfire.ai/api-reference/cash-management/partial-update-bank-transaction https://api.meetcampfire.com/api/schema?format=json patch /ca/api/transaction/{id} # Post Bank Feed Source: https://docs.campfire.ai/api-reference/cash-management/post-bank-feed https://api.meetcampfire.com/api/schema?format=json post /ca/api/bank-feed/{account_id} Ingest bank feed data for a specific bank account. Creates bank transactions, updates account balances, and triggers auto-categorization. Each transaction also posts a journal entry unless the customer has 'skip journal on bank sync' enabled, in which case only the bank transaction is recorded. # Retrieve Bank Account Source: https://docs.campfire.ai/api-reference/cash-management/retrieve-bank-account https://api.meetcampfire.com/api/schema?format=json get /ca/api/account/{id} # Retrieve Bank Transaction Source: https://docs.campfire.ai/api-reference/cash-management/retrieve-bank-transaction https://api.meetcampfire.com/api/schema?format=json get /ca/api/transaction/{id} # Update Bank Account Source: https://docs.campfire.ai/api-reference/cash-management/update-bank-account https://api.meetcampfire.com/api/schema?format=json put /ca/api/account/{id} # Update Bank Transaction Source: https://docs.campfire.ai/api-reference/cash-management/update-bank-transaction https://api.meetcampfire.com/api/schema?format=json put /ca/api/transaction/{id} # Post coaapifixed asset automation delete Source: https://docs.campfire.ai/api-reference/coa/post-coaapifixed-asset-automation-delete https://api.meetcampfire.com/api/schema?format=json post /coa/api/fixed-asset-automation/{id}/delete The type of the None singleton. # Upload Entity Invoice Email Attachment Source: https://docs.campfire.ai/api-reference/coa/upload-entity-invoice-email-attachment https://api.meetcampfire.com/api/schema?format=json post /coa/api/entity/{entity_id}/attachment Upload invoice email attachment with proper permissions # Catch Up Closed Period Allocation Source: https://docs.campfire.ai/api-reference/company-objects/catch-up-closed-period-allocation https://api.meetcampfire.com/api/schema?format=json post /coa/api/cost-allocations/{id}/catch-up Post a closed entity-period's remaining allocation delta into the next open period. # Create Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/create-chart-account https://api.meetcampfire.com/api/schema?format=json post /coa/api/account Lists the chart of accounts (GL accounts). Each account includes metadata about its parent account and its full lineage (the ordered chain of ancestor accounts), so parent/child account relationships can be reconstructed from the response. # Create Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/create-chart-account-1 https://api.meetcampfire.com/api/schema?format=json post /coa/api/account/balance-sheet Lists the chart of accounts (GL accounts). Each account includes metadata about its parent account and its full lineage (the ordered chain of ancestor accounts), so parent/child account relationships can be reconstructed from the response. # Create Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/create-chart-account-2 https://api.meetcampfire.com/api/schema?format=json post /coa/api/account/income-statement Lists the chart of accounts (GL accounts). Each account includes metadata about its parent account and its full lineage (the ordered chain of ancestor accounts), so parent/child account relationships can be reconstructed from the response. # Create Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/create-cost-allocation https://api.meetcampfire.com/api/schema?format=json post /coa/api/cost-allocations Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Custom Dimension Source: https://docs.campfire.ai/api-reference/company-objects/create-custom-dimension https://api.meetcampfire.com/api/schema?format=json post /coa/api/tag Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Custom Dimension Group Source: https://docs.campfire.ai/api-reference/company-objects/create-custom-dimension-group https://api.meetcampfire.com/api/schema?format=json post /coa/api/tag-group Mixin to provide consistent last_modified_at filtering and sorting functionality for List APIs with comprehensive timestamp computation. # Create Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/create-custom-field https://api.meetcampfire.com/api/schema?format=json post /ca/api/v1/custom-fields Create a new custom field for a given app and model # Create Department Source: https://docs.campfire.ai/api-reference/company-objects/create-department https://api.meetcampfire.com/api/schema?format=json post /coa/api/department Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Fixed Asset Class Source: https://docs.campfire.ai/api-reference/company-objects/create-fixed-asset-class https://api.meetcampfire.com/api/schema?format=json post /coa/api/fixed-asset-class Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Vendor Source: https://docs.campfire.ai/api-reference/company-objects/create-vendor https://api.meetcampfire.com/api/schema?format=json post /coa/api/vendor Create a new vendor or customer in the system # Create Vendor Contact Title Source: https://docs.campfire.ai/api-reference/company-objects/create-vendor-contact-title https://api.meetcampfire.com/api/schema?format=json post /coa/api/vendor-contact-title Mixin to provide consistent last_modified_at filtering and sorting functionality for List APIs with comprehensive timestamp computation. # Create Vendor Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/create-vendor-custom-field https://api.meetcampfire.com/api/schema?format=json post /coa/api/vendor_custom_field_1 # Delete Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/delete-chart-account https://api.meetcampfire.com/api/schema?format=json delete /coa/api/account/{id} # Delete Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/delete-cost-allocation https://api.meetcampfire.com/api/schema?format=json delete /coa/api/cost-allocations/{id} # Delete Custom Dimension Source: https://docs.campfire.ai/api-reference/company-objects/delete-custom-dimension https://api.meetcampfire.com/api/schema?format=json post /coa/api/tag/{id}/delete Delete a transaction tag and optionally merge it with another tag # Delete Custom Dimension (deprecated) Source: https://docs.campfire.ai/api-reference/company-objects/delete-custom-dimension-deprecated https://api.meetcampfire.com/api/schema?format=json delete /coa/api/tag/{id} Deprecated: use `POST /coa/api/tag/{id}/delete`, which also takes an optional reason for the audit log. Delete a transaction tag and optionally merge it with another tag # Delete Custom Dimension Group Source: https://docs.campfire.ai/api-reference/company-objects/delete-custom-dimension-group https://api.meetcampfire.com/api/schema?format=json delete /coa/api/tag-group/{id} # Delete Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/delete-custom-field https://api.meetcampfire.com/api/schema?format=json delete /ca/api/v1/custom-fields/{id} # Delete Department Source: https://docs.campfire.ai/api-reference/company-objects/delete-department https://api.meetcampfire.com/api/schema?format=json post /coa/api/department/{id}/delete Delete a department and optionally reassign all related records to another department # Delete Department (deprecated) Source: https://docs.campfire.ai/api-reference/company-objects/delete-department-deprecated https://api.meetcampfire.com/api/schema?format=json delete /coa/api/department/{id} Deprecated: use `POST /coa/api/department/{id}/delete`, which also takes an optional reason for the audit log. Delete a department and optionally reassign all related records to another department # Delete Fixed Asset Class Source: https://docs.campfire.ai/api-reference/company-objects/delete-fixed-asset-class https://api.meetcampfire.com/api/schema?format=json delete /coa/api/fixed-asset-class/{id} # Delete Vendor Source: https://docs.campfire.ai/api-reference/company-objects/delete-vendor https://api.meetcampfire.com/api/schema?format=json delete /coa/api/vendor/{id} Delete a vendor and optionally reassign all related records to another vendor. Returns 202 Accepted as deletion is processed asynchronously. # Delete Vendor Contact Title Source: https://docs.campfire.ai/api-reference/company-objects/delete-vendor-contact-title https://api.meetcampfire.com/api/schema?format=json delete /coa/api/vendor-contact-title/{id} # Delete Vendor Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/delete-vendor-custom-field https://api.meetcampfire.com/api/schema?format=json delete /coa/api/vendor_custom_field_1/{id} # Get Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/get-cost-allocation https://api.meetcampfire.com/api/schema?format=json get /coa/api/cost-allocations/{id} # List Allocation Sync Runs Source: https://docs.campfire.ai/api-reference/company-objects/list-allocation-sync-runs https://api.meetcampfire.com/api/schema?format=json get /coa/api/cost-allocations/{id}/sync-runs # List Chart Accounts Source: https://docs.campfire.ai/api-reference/company-objects/list-chart-accounts https://api.meetcampfire.com/api/schema?format=json get /coa/api/account/balance-sheet Retrieve a list of chart accounts with optional filtering and sorting # List Chart of Accounts Source: https://docs.campfire.ai/api-reference/company-objects/list-chart-of-accounts https://api.meetcampfire.com/api/schema?format=json get /coa/api/account Lists the chart of accounts (GL accounts). Each account includes metadata about its parent account and its full lineage (the ordered chain of ancestor accounts), so parent/child account relationships can be reconstructed from the response. # List Chart of Accounts Source: https://docs.campfire.ai/api-reference/company-objects/list-chart-of-accounts-1 https://api.meetcampfire.com/api/schema?format=json get /coa/api/account/income-statement Lists the chart of accounts (GL accounts). Each account includes metadata about its parent account and its full lineage (the ordered chain of ancestor accounts), so parent/child account relationships can be reconstructed from the response. # List Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/list-cost-allocation https://api.meetcampfire.com/api/schema?format=json get /coa/api/cost-allocations Retrieve a list of cost allocations with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Custom Dimension Groups Source: https://docs.campfire.ai/api-reference/company-objects/list-custom-dimension-groups https://api.meetcampfire.com/api/schema?format=json get /coa/api/tag-group Retrieve a list of transaction tag groups with optional filtering and sorting. Supports timestamp-based filtering for synchronization and audit purposes. # List Custom Dimensions Source: https://docs.campfire.ai/api-reference/company-objects/list-custom-dimensions https://api.meetcampfire.com/api/schema?format=json get /coa/api/tag Retrieve a list of transaction tags (custom dimensions) with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Custom Fields Source: https://docs.campfire.ai/api-reference/company-objects/list-custom-fields https://api.meetcampfire.com/api/schema?format=json get /ca/api/v1/custom-fields List all custom fields for a given app and model. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Departments Source: https://docs.campfire.ai/api-reference/company-objects/list-departments https://api.meetcampfire.com/api/schema?format=json get /coa/api/department Retrieve a list of departments with optional filtering and sorting. Each department includes metadata about its parent department (`parent`, `parent_name`), so parent/child department relationships can be reconstructed from the response. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Fixed Asset Classes Source: https://docs.campfire.ai/api-reference/company-objects/list-fixed-asset-classes https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-class Retrieve a list of fixed asset classes with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Vendor Contact Titles Source: https://docs.campfire.ai/api-reference/company-objects/list-vendor-contact-titles https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor-contact-title Retrieve a list of vendor contact titles with optional filtering and sorting. Supports timestamp-based filtering for synchronization and audit purposes. # List Vendor Custom Fields Source: https://docs.campfire.ai/api-reference/company-objects/list-vendor-custom-fields https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor_custom_field_1 # List Vendor Summaries Source: https://docs.campfire.ai/api-reference/company-objects/list-vendor-summaries https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor/summary # List Vendors Source: https://docs.campfire.ai/api-reference/company-objects/list-vendors https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor Retrieve a list of vendors/customers with optional filtering and sorting. Each vendor includes metadata about its parent vendor (`parent`, `parent_name`) and its full `lineage` (the ordered chain of ancestor vendors), so parent/child vendor relationships can be reconstructed from the response. Supports retrieving deleted records for audit purposes. When include_deleted=true, returns ONLY deleted records with minimal data (id, is_deleted, deleted_at, last_modified_at). When false or omitted, returns ONLY active records. # Partial Fixed Asset Class Source: https://docs.campfire.ai/api-reference/company-objects/partial-fixed-asset-class https://api.meetcampfire.com/api/schema?format=json patch /coa/api/fixed-asset-class/{id} # Partial Update Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-chart-account https://api.meetcampfire.com/api/schema?format=json patch /coa/api/account/{id} # Partial Update Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-cost-allocation https://api.meetcampfire.com/api/schema?format=json patch /coa/api/cost-allocations/{id} # Partial Update Custom Dimension Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-custom-dimension https://api.meetcampfire.com/api/schema?format=json patch /coa/api/tag/{id} # Partial Update Custom Dimension Group Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-custom-dimension-group https://api.meetcampfire.com/api/schema?format=json patch /coa/api/tag-group/{id} # Partial Update Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-custom-field https://api.meetcampfire.com/api/schema?format=json patch /ca/api/v1/custom-fields/{id} # Partial Update Department Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-department https://api.meetcampfire.com/api/schema?format=json patch /coa/api/department/{id} # Partial Update Vendor Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-vendor https://api.meetcampfire.com/api/schema?format=json patch /coa/api/vendor/{id} # Partial Update Vendor Contact Title Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-vendor-contact-title https://api.meetcampfire.com/api/schema?format=json patch /coa/api/vendor-contact-title/{id} # Partial Update Vendor Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/partial-update-vendor-custom-field https://api.meetcampfire.com/api/schema?format=json patch /coa/api/vendor_custom_field_1/{id} # Preview Cost Allocation Split Source: https://docs.campfire.ai/api-reference/company-objects/preview-cost-allocation-split https://api.meetcampfire.com/api/schema?format=json get /coa/api/cost-allocations/{id}/preview Fan-out lines the posting path would produce for an amount, period, and entity. Writes nothing. # Recalculate Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/recalculate-cost-allocation https://api.meetcampfire.com/api/schema?format=json post /coa/api/cost-allocations/{id}/sync Queue sync runs for an allocation's open entity-periods in the requested period, optionally for one entity. # Retrieve Allocation Sync Run Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-allocation-sync-run https://api.meetcampfire.com/api/schema?format=json get /coa/api/cost-allocations/{id}/sync-runs/{run_pk} # Retrieve Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-chart-account https://api.meetcampfire.com/api/schema?format=json get /coa/api/account/{id} # Retrieve Custom Dimension Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-custom-dimension https://api.meetcampfire.com/api/schema?format=json get /coa/api/tag/{id} # Retrieve Custom Dimension Group Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-custom-dimension-group https://api.meetcampfire.com/api/schema?format=json get /coa/api/tag-group/{id} # Retrieve Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-custom-field https://api.meetcampfire.com/api/schema?format=json get /ca/api/v1/custom-fields/{id} # Retrieve Department Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-department https://api.meetcampfire.com/api/schema?format=json get /coa/api/department/{id} # Retrieve Fixed Asset Class Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-fixed-asset-class https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-class/{id} # Retrieve Vendor Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-vendor https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor/{id} # Retrieve Vendor Contact Title Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-vendor-contact-title https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor-contact-title/{id} # Retrieve Vendor Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/retrieve-vendor-custom-field https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor_custom_field_1/{id} # Update Chart Account Source: https://docs.campfire.ai/api-reference/company-objects/update-chart-account https://api.meetcampfire.com/api/schema?format=json put /coa/api/account/{id} # Update Cost Allocation Source: https://docs.campfire.ai/api-reference/company-objects/update-cost-allocation https://api.meetcampfire.com/api/schema?format=json put /coa/api/cost-allocations/{id} # Update Custom Dimension Source: https://docs.campfire.ai/api-reference/company-objects/update-custom-dimension https://api.meetcampfire.com/api/schema?format=json put /coa/api/tag/{id} # Update Custom Dimension Group Source: https://docs.campfire.ai/api-reference/company-objects/update-custom-dimension-group https://api.meetcampfire.com/api/schema?format=json put /coa/api/tag-group/{id} # Update Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/update-custom-field https://api.meetcampfire.com/api/schema?format=json put /ca/api/v1/custom-fields/{id} # Update Department Source: https://docs.campfire.ai/api-reference/company-objects/update-department https://api.meetcampfire.com/api/schema?format=json put /coa/api/department/{id} # Update Fixed Asset Class Source: https://docs.campfire.ai/api-reference/company-objects/update-fixed-asset-class https://api.meetcampfire.com/api/schema?format=json put /coa/api/fixed-asset-class/{id} # Update Vendor Source: https://docs.campfire.ai/api-reference/company-objects/update-vendor https://api.meetcampfire.com/api/schema?format=json put /coa/api/vendor/{id} # Update Vendor Contact Title Source: https://docs.campfire.ai/api-reference/company-objects/update-vendor-contact-title https://api.meetcampfire.com/api/schema?format=json put /coa/api/vendor-contact-title/{id} # Update Vendor Custom Field Source: https://docs.campfire.ai/api-reference/company-objects/update-vendor-custom-field https://api.meetcampfire.com/api/schema?format=json put /coa/api/vendor_custom_field_1/{id} # Balance Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/balance-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json post /coa/api/intercompany-journal-entry/balance Balances an intercompany journal entry by entity and currency. This endpoint performs the same balancing logic as the frontend, applying: 1. Auto-fetching of exchange rates if not provided (requires date field) 2. Exchange rate roll-forward from native to book to consolidation currencies 3. Exchange rate plugging to ensure consolidation amounts match across currencies within an entity 4. Automatic creation of balancing transactions when debits != credits at any currency level The endpoint accepts a partial intercompany journal entry with transactions and optionally exchange rates, and returns the balanced version with: - Auto-fetched exchange rates (if exchange_rates is empty and date is provided) - Updated transactions with calculated book and consolidation amounts - New balancing transactions added where needed - Plugged exchange rates to maintain consolidation consistency This is useful for: - Validating journal entries before submission - Understanding what balancing entries will be created - Testing multi-currency and multi-entity scenarios - Auto-fetching exchange rates for the journal date # Bulk Accept Suggestions Source: https://docs.campfire.ai/api-reference/core-accounting/bulk-accept-suggestions https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-matches/bulk-accept Apply one class of pending suggestions (match | rule | merge | ai) across an explicit or filter-implicit transaction selection, each through its existing single-item flow. Per-item outcomes; capped per call — drain until 'truncated' is false, excluding blocked transaction ids on subsequent calls. # Bulk Search Custom Dimensions by Name Source: https://docs.campfire.ai/api-reference/core-accounting/bulk-search-custom-dimensions-by-name https://api.meetcampfire.com/api/schema?format=json post /coa/api/tag/bulk-search Search for tags by exact name match in a single request. Supports upsert to create missing tags. # Bulk Search Departments by Name Source: https://docs.campfire.ai/api-reference/core-accounting/bulk-search-departments-by-name https://api.meetcampfire.com/api/schema?format=json post /coa/api/department/bulk-search Search for thousands of departments by exact name match in a single request. Optimized for performance. Supports upsert to create missing departments. # Bulk Search Vendors by External ID or Name Source: https://docs.campfire.ai/api-reference/core-accounting/bulk-search-vendors-by-external-id-or-name https://api.meetcampfire.com/api/schema?format=json post /coa/api/vendor/bulk-search Search for thousands of vendors in a single request, resolving each cell by external_id, then a Campfire ID or internal pk parsed from the cell, then name. Optimized for performance. Supports upsert to create missing vendors. A row that supplies an external_id matching no payee is reported rather than failing the request: the body becomes `{vendors, errors}` instead of the payee list, still a 200, so the payees that did resolve are not discarded along with it. A name-only row that matches nothing is not reported — with `upsert` it is created, and without it the row is simply absent from `vendors`. # Bulk Update Chart Transactions Source: https://docs.campfire.ai/api-reference/core-accounting/bulk-update-chart-transactions https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/bulk-update # Create a pending GL coding suggestion Source: https://docs.campfire.ai/api-reference/core-accounting/create-a-pending-gl-coding-suggestion https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-gl-codings/propose Wraps ``CreateModelMixin.create`` (or any method named ``create``) with ``Idempotency-Key`` handling. Place this mixin **before** the view's other base classes so its ``create`` overrides the inherited one:: class JournalEntryListCreate( IdempotentCreateMixin, HistoryFilteringMixin, ListCreateAPIView, ): ... # Create a pending transaction merge Source: https://docs.campfire.ai/api-reference/core-accounting/create-a-pending-transaction-merge https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-merges/propose Wraps ``CreateModelMixin.create`` (or any method named ``create``) with ``Idempotency-Key`` handling. Place this mixin **before** the view's other base classes so its ``create`` overrides the inherited one:: class JournalEntryListCreate( IdempotentCreateMixin, HistoryFilteringMixin, ListCreateAPIView, ): ... # Create Bill Payments for Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/create-bill-payments-for-transaction https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/{transaction_id}/bill_payments # Create Budget Source: https://docs.campfire.ai/api-reference/core-accounting/create-budget https://api.meetcampfire.com/api/schema?format=json post /coa/api/budgets Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Budget Source: https://docs.campfire.ai/api-reference/core-accounting/create-budget-1 https://api.meetcampfire.com/api/schema?format=json post /coa/api/budgets/{budget_pk}/accounts Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Credit Memo Payments for Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/create-credit-memo-payments-for-transaction https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/{transaction_id}/credit_memo_payments # Create Debit Memo Payments for Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/create-debit-memo-payments-for-transaction https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/{transaction_id}/debit_memo_payments # Create Fixed Asset Source: https://docs.campfire.ai/api-reference/core-accounting/create-fixed-asset https://api.meetcampfire.com/api/schema?format=json post /coa/api/fixed-asset Wraps ``CreateModelMixin.create`` (or any method named ``create``) with ``Idempotency-Key`` handling. Place this mixin **before** the view's other base classes so its ``create`` overrides the inherited one:: class JournalEntryListCreate( IdempotentCreateMixin, HistoryFilteringMixin, ListCreateAPIView, ): ... # Create Fixed Asset Automation Source: https://docs.campfire.ai/api-reference/core-accounting/create-fixed-asset-automation https://api.meetcampfire.com/api/schema?format=json post /coa/api/fixed-asset-automation List all automation rules or create a new one. GET /api/fixed-asset-automation/ POST /api/fixed-asset-automation/ # Create Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/create-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json post /coa/api/intercompany-journal-entry Creates a new intercompany journal entry This endpoint allows for complex multi-entity transactions where: - Transactions are balanced across different entities - Exchange rates are handled for multi-currency transactions Key requirements: - Total debits must equal total credits for each entity (debit_amount_native must equal credit_amount_native) - Cannot create entries before closed book dates - All referenced accounts must be active - Exchange rates must be provided for all currency conversions (native to book, book to consolidation) # Create Invoice Payments for Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/create-invoice-payments-for-transaction https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/{transaction_id}/invoice_payments # Create Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/create-journal-entry https://api.meetcampfire.com/api/schema?format=json post /coa/api/journal_entry Create a new journal entry with transactions. Journal entries must balance - total debits must equal total credits. **Key Features:** - Automatic currency conversion using exchange rates - Vendor, Department and Custom Dimension assignment - Optional reversal date for automatic reversal entries - Validation against closed book periods **Validation Rules:** - Debits must equal credits in transaction currency (debit_native and credit_native) - Cannot create entries before closed book dates - Accounts must be active - Exchange rates are auto-calculated if not provided # Create pending transaction matches Source: https://docs.campfire.ai/api-reference/core-accounting/create-pending-transaction-matches https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-matches/propose Wraps ``CreateModelMixin.create`` (or any method named ``create``) with ``Idempotency-Key`` handling. Place this mixin **before** the view's other base classes so its ``create`` overrides the inherited one:: class JournalEntryListCreate( IdempotentCreateMixin, HistoryFilteringMixin, ListCreateAPIView, ): ... # Create Vendor Contact Source: https://docs.campfire.ai/api-reference/core-accounting/create-vendor-contact https://api.meetcampfire.com/api/schema?format=json post /coa/api/vendor/{id}/contacts Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Delete Budget Source: https://docs.campfire.ai/api-reference/core-accounting/delete-budget https://api.meetcampfire.com/api/schema?format=json delete /coa/api/budgets/{id} # Delete Budget Account Source: https://docs.campfire.ai/api-reference/core-accounting/delete-budget-account https://api.meetcampfire.com/api/schema?format=json delete /coa/api/budgets/{budget_pk}/accounts/{id} # Delete Chart Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/delete-chart-transaction https://api.meetcampfire.com/api/schema?format=json delete /coa/api/transaction/{id} # Delete Fixed Asset Source: https://docs.campfire.ai/api-reference/core-accounting/delete-fixed-asset https://api.meetcampfire.com/api/schema?format=json delete /coa/api/fixed-asset/{id} # Delete Fixed Asset Automation (deprecated) Source: https://docs.campfire.ai/api-reference/core-accounting/delete-fixed-asset-automation-deprecated https://api.meetcampfire.com/api/schema?format=json delete /coa/api/fixed-asset-automation/{id} Deprecated: use `POST /coa/api/fixed-asset-automation/{id}/delete`, which also takes an optional reason for the audit log. Retrieve, update, or delete an automation rule. GET/PUT/PATCH/DELETE /api/fixed-asset-automation// # Delete Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/delete-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json delete /coa/api/intercompany-journal-entry/{id} Permanently deletes an intercompany journal entry and all related transactions. This endpoint performs a comprehensive cleanup when deleting an intercompany journal entry: - Validates that the entry can be deleted (not in closed period) - Removes all associated journal entries across entities - Updates summary tables and account balances - Handles cascade deletion of related transactions - Ensures data integrity across the accounting system Deletion restrictions: - Cannot delete entries in closed accounting periods Error conditions: - 400 Bad Request: Entry date is in a closed period - 409 Conflict: Entry has protected relationships (e.g., close checklist tasks) - 404 Not Found: Entry does not exist or user lacks access On successful deletion, all related journal entries are removed and accounting summaries are recalculated. # Delete Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/delete-journal-entry https://api.meetcampfire.com/api/schema?format=json delete /coa/api/journal_entry/{id} Delete a journal entry and all its associated transactions. **Restrictions:** - Cannot delete entries before closed book dates **Response Codes:** - 204: Successfully deleted - 400: Cannot delete (books closed for this date) - 409: Cannot delete (associated with other objects) # Delete Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/delete-transaction-match https://api.meetcampfire.com/api/schema?format=json delete /coa/api/transaction-matches/{id} # Delete Vendor Contact Source: https://docs.campfire.ai/api-reference/core-accounting/delete-vendor-contact https://api.meetcampfire.com/api/schema?format=json delete /coa/api/vendor-contact/{id} Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Discover bill or invoice match candidates for a bank transaction Source: https://docs.campfire.ai/api-reference/core-accounting/discover-bill-or-invoice-match-candidates-for-a-bank-transaction https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction-matches/candidates # Get Chart Transaction Totals Source: https://docs.campfire.ai/api-reference/core-accounting/get-chart-transaction-totals https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction/totals Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Get Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/get-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json get /coa/api/intercompany-journal-entry/{id} Retrieves a single intercompany journal entry by its ID with complete details. This endpoint returns: - Complete intercompany journal entry information - Full transaction details with all accounting fields - Entity information and exchange rates - Attachment and reversal information - Comprehensive transaction metadata The response includes: - All transaction details with account information - Exchange rate data for all currency conversions (native to book, book to consolidation) - Vendor, department, and tag information - Balance calculations and transaction history - File attachments and reversal relationships - Complete audit trail information This is the detailed view used for editing and complete transaction analysis. # Get Transaction Matches Count Source: https://docs.campfire.ai/api-reference/core-accounting/get-transaction-matches-count https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction-matches-count # List Budget Accounts Source: https://docs.campfire.ai/api-reference/core-accounting/list-budget-accounts https://api.meetcampfire.com/api/schema?format=json get /coa/api/budgets/{budget_pk}/accounts Retrieve a list of budget accounts with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Budgets Source: https://docs.campfire.ai/api-reference/core-accounting/list-budgets https://api.meetcampfire.com/api/schema?format=json get /coa/api/budgets Retrieve a list of budgets with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Chart Transactions Source: https://docs.campfire.ai/api-reference/core-accounting/list-chart-transactions https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction Lists general-ledger transactions (`ChartTransaction` records) - Campfire's GL transaction log, and the recommended endpoint for retrieving GL transaction data. Each transaction carries account, department, vendor, entity, journal/date metadata, and tags (where applicable). Product metadata is not stored directly on a transaction; it is reached through relations with other Campfire objects. **Date range:** filter with `start_date` and `end_date` (both `YYYY-MM-DD`, inclusive); `date_from` and `date_to` are aliases, and `start_date`/`end_date` win when both are sent. The bounds match on transaction date (the journal entry date, which `posted_at` mirrors). **Pagination:** results are paginated via `limit` (default 100, max 10000) and `offset`. To retrieve more than 10000 records, page through with `offset`, or use cursor pagination by passing an empty `cursor=` parameter and following the `next` link. **Key response fields:** - `amount` - amount in consolidated currency (the root entity's currency). - `amount_book` - amount in the currency of the entity the transaction belongs to. - `amount_native` - amount in the currency the transaction was originally created in. Example: for a transaction made in GBP where the entity uses EUR and the root entity uses USD, `amount_native` is GBP, `amount_book` is EUR, and `amount` is USD. - `posted_at` - the transaction date; determines which period the transaction falls in. `date_year` and `date_month` are derived from it. - `vendor` / `vendor_name` - the linked Campfire `Vendor` object's ID and name. - `merchant_name` - a free-text field stored directly on the transaction; not linked to any Campfire object. - `account` - the Campfire `ChartAccount` (GL account) the transaction is posted to. - `entity` - the Campfire `ChartEntity` ID. - `tags` - the transaction's tags; each tag's `group`/`group_name` identify the tag group (dimension) it belongs to. List a customer's tag groups via `/coa/api/tag-group` and tags via `/coa/api/tag`. **Dynamic tag-group columns:** in addition to `tags`, each row carries flattened per-dimension columns `tag_group_` (tag ID) and `tag_group__name` (tag name), one pair per tag group defined by the customer, plus `tag_group_none` / `tag_group_none_name` for ungrouped tags. Journal-level custom fields are merged in as `custom_field_` keys. These columns are customer-specific, so they cannot appear in this static schema - discover tag groups via `/coa/api/tag-group` and custom fields via `/ca/api/v1/custom-fields`. # List Fixed Asset Automation Accounts Source: https://docs.campfire.ai/api-reference/core-accounting/list-fixed-asset-automation-accounts https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation/accounts List accounts that are of type FIXED_ASSET for use in automation rule creation. GET /api/fixed-asset-automation/accounts This endpoint returns only accounts with account_subtype='FIXED_ASSET' to ensure automation rules are created with appropriate accounts. # List Fixed Asset Automation Asset Classes Source: https://docs.campfire.ai/api-reference/core-accounting/list-fixed-asset-automation-asset-classes https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation/asset-classes List fixed asset classes that match a specific account. GET /api/fixed-asset-automation/asset-classes?account_id= Filters asset classes to only those where asset_account matches the provided account_id. This ensures users can only select compatible asset classes for the chosen account. # List Fixed Asset Automation Matches Source: https://docs.campfire.ai/api-reference/core-accounting/list-fixed-asset-automation-matches https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation/matches List pending asset matches for review. GET /api/fixed-asset-automation/matches # List Fixed Asset Automations Source: https://docs.campfire.ai/api-reference/core-accounting/list-fixed-asset-automations https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation List all automation rules or create a new one. GET /api/fixed-asset-automation/ POST /api/fixed-asset-automation/ # List Fixed Assets Source: https://docs.campfire.ai/api-reference/core-accounting/list-fixed-assets https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset Retrieve a list of fixed assets with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Intercompany Journal Entries Source: https://docs.campfire.ai/api-reference/core-accounting/list-intercompany-journal-entries https://api.meetcampfire.com/api/schema?format=json get /coa/api/intercompany-journal-entry Retrieves a paginated list of intercompany journal entries for the authenticated user's customer. This endpoint returns: - Summary information for each intercompany journal entry - Basic transaction details (simplified view for list performance) - Entity and exchange rate information - Pagination metadata (count, next, previous) - Reversal relationships and attachment counts The response includes: - Intercompany journal entry metadata - Associated transaction summaries - Exchange rate information for currency conversions - Links to related reversals - Attachment information Results can be sorted using the 'sort' query parameter with field names like 'date', 'id', etc. Prefix with '-' for descending order (e.g., '-date'). # List Journal Entries Source: https://docs.campfire.ai/api-reference/core-accounting/list-journal-entries https://api.meetcampfire.com/api/schema?format=json get /coa/api/journal_entry Retrieve a paginated list of journal entries with optional filtering and sorting. **Query Parameters:** - `start_date`, `end_date`: Filter by date range (defaults to last 6 months) - `account`: Filter by account ID(s) - supports multiple values - `source`: Filter by journal entry source. Payroll auto-sync sources (`rippling_payroll_auto`, `finch_payroll_auto`, `deel_payroll_auto`, `adp_workforce_now_payroll_auto`) are exempt from the default window, since they page on `last_modified_at` and re-post back-dated corrections. - `journal_id`: Filter by specific journal ID - `all_time`: Include all entries regardless of date (true/false) - `sort`: Sort field (default: "date") **Response includes:** - Complete journal entry details with all transactions - Account information with names and numbers - Vendor and department details - Tag associations with groups - Attachment information - Exchange rate data for multi-currency entries # List Transaction Matches Source: https://docs.campfire.ai/api-reference/core-accounting/list-transaction-matches https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction-matches # List Unmatched GL Transactions for Fixed Asset Reconciliation Source: https://docs.campfire.ai/api-reference/core-accounting/list-unmatched-gl-transactions-for-fixed-asset-reconciliation https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset/reconciliation/unmatched-gl Drilldown showing GL transactions NOT linked to any fixed asset. Returns the journal entries on a control account that cannot be traced back to a specific asset's purchase, depreciation, or disposal entries. These are the transactions that make up the "Unmatched GL" amount in the reconciliation report. # List Vendor Contacts Source: https://docs.campfire.ai/api-reference/core-accounting/list-vendor-contacts https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor/{id}/contacts Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Merge Chart Transactions Source: https://docs.campfire.ai/api-reference/core-accounting/merge-chart-transactions https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction/merge Merge two offsetting chart transactions from different journals. This endpoint consolidates journals containing offsetting transactions by removing the specified transactions and combining the remaining transactions into a single journal entry. **Request Body:** - `transaction_ids` (array, required): Array of exactly two transaction IDs to merge - `transaction_match_id` (integer, optional): The AutoMergeSuggestion TransactionMatch the user explicitly accepted; when it names a suggestion over exactly this pair, the merge is recorded as a suggestion accept rather than a manual merge **Returns:** The merged journal entry with all remaining transactions. **Requirements:** - Must provide exactly two transaction IDs - Transactions must be from different journals - Transactions must have matching amounts - Transactions must belong to the same entity **Result:** - The two specified transactions are deleted - Other transactions from both journals are consolidated into a single journal - A draft queue record is created for audit purposes and auto-approved # Partial Update Budget Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-budget https://api.meetcampfire.com/api/schema?format=json patch /coa/api/budgets/{id} # Partial Update Budget Account Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-budget-account https://api.meetcampfire.com/api/schema?format=json patch /coa/api/budgets/{budget_pk}/accounts/{id} # Partial Update Chart Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-chart-transaction https://api.meetcampfire.com/api/schema?format=json patch /coa/api/transaction/{id} # Partial Update Fixed Asset Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-fixed-asset https://api.meetcampfire.com/api/schema?format=json patch /coa/api/fixed-asset/{id} # Partial Update Fixed Asset Automation Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-fixed-asset-automation https://api.meetcampfire.com/api/schema?format=json patch /coa/api/fixed-asset-automation/{id} Retrieve, update, or delete an automation rule. GET/PUT/PATCH/DELETE /api/fixed-asset-automation// # Partial Update Fixed Asset Automation Match Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-fixed-asset-automation-match https://api.meetcampfire.com/api/schema?format=json patch /coa/api/fixed-asset-automation-match/{id} Retrieve or update an automation match (for editing proposed values before acceptance). GET/PATCH /api/fixed-asset-automation-match// # Partial Update Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json patch /coa/api/intercompany-journal-entry/{id} Performs a partial update of an intercompany journal entry, allowing modification of specific fields without replacing the entire entry. This endpoint supports partial updates to: - Journal entry metadata (memo, date, currency, reference number) - Individual transaction modifications - Entity exchange rate adjustments - Vendor, department, and tag assignments - Account categorizations and amounts Key differences from PUT: - Only specified fields are updated (vs. full replacement) - Maintains existing data for unspecified fields - Supports granular transaction modifications - Preserves audit trail and timestamps - Allows incremental changes without full transaction rebuilds Validation requirements: - Modified transactions must maintain entity balance (debits = credits) - Cannot modify entries in closed accounting periods - All referenced accounts, vendors, departments must be active - Exchange rates must be valid for multi-currency transactions - Account assignments must be appropriate for transaction types # Partial Update Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-journal-entry https://api.meetcampfire.com/api/schema?format=json patch /coa/api/journal_entry/{id} Partially update a journal entry. Only provided fields will be updated. **Common Use Cases:** - Update memo or reference number - Change journal entry date - Modify specific transaction amounts - Add or remove tags from transactions **Validation Rules:** - Journal entry must still balance after updates - Cannot modify entries in closed periods - Account changes must maintain chart of accounts rules # Partial Update Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-transaction-match https://api.meetcampfire.com/api/schema?format=json patch /coa/api/transaction-matches/{id} # Partial Update Vendor Contact Source: https://docs.campfire.ai/api-reference/core-accounting/partial-update-vendor-contact https://api.meetcampfire.com/api/schema?format=json patch /coa/api/vendor-contact/{id} Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Preview Chart Transaction Merge Source: https://docs.campfire.ai/api-reference/core-accounting/preview-chart-transaction-merge https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction/merge Preview the result of merging two chart transactions. This endpoint shows what the merged journal entry will look like, allowing you to verify the merge before committing. The preview includes the journal that will be retained and the transactions that will remain after the merge. **Parameters:** - `transaction_ids` (query, required): Comma-separated list of exactly two transaction IDs **Returns:** A journal entry object containing the merged result with all remaining transactions. **Requirements:** - Must provide exactly two transaction IDs - Transactions must be from different journals - Transactions must have matching amounts - Transactions must belong to the same entity # Process Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/process-transaction-match https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-match-process # Reject Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/reject-transaction-match https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-matches/{id}/reject # Retrieve Budget Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-budget https://api.meetcampfire.com/api/schema?format=json get /coa/api/budgets/{id} # Retrieve Budget Account Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-budget-account https://api.meetcampfire.com/api/schema?format=json get /coa/api/budgets/{budget_pk}/accounts/{id} # Retrieve Chart Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-chart-transaction https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction/{id} # Retrieve Fixed Asset Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-fixed-asset https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset/{id} # Retrieve Fixed Asset Automation Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-fixed-asset-automation https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation/{id} Retrieve, update, or delete an automation rule. GET/PUT/PATCH/DELETE /api/fixed-asset-automation// # Retrieve Fixed Asset Automation Match Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-fixed-asset-automation-match https://api.meetcampfire.com/api/schema?format=json get /coa/api/fixed-asset-automation-match/{id} Retrieve or update an automation match (for editing proposed values before acceptance). GET/PATCH /api/fixed-asset-automation-match// # Retrieve Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-journal-entry https://api.meetcampfire.com/api/schema?format=json get /coa/api/journal_entry/{id} Retrieve a specific journal entry by ID with all transaction details. **Response includes:** - Complete journal entry with all transactions - Account names, numbers, and types - Vendor and department information - Tag associations with groups - Exchange rate data for multi-currency entries - Attachment information - Reversal information if applicable # Retrieve Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-transaction-match https://api.meetcampfire.com/api/schema?format=json get /coa/api/transaction-matches/{id} # Retrieve Vendor Contact Source: https://docs.campfire.ai/api-reference/core-accounting/retrieve-vendor-contact https://api.meetcampfire.com/api/schema?format=json get /coa/api/vendor-contact/{id} Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Run Fixed Asset Automation Source: https://docs.campfire.ai/api-reference/core-accounting/run-fixed-asset-automation https://api.meetcampfire.com/api/schema?format=json post /coa/api/fixed-asset-automation/run Trigger automation processing. POST /api/fixed-asset-automation/run Optional body: {"rule_id": 123} # Set Transaction Match Status Source: https://docs.campfire.ai/api-reference/core-accounting/set-transaction-match-status https://api.meetcampfire.com/api/schema?format=json post /coa/api/transaction-matches/{id}/status Handle POST requests with 'action' parameter (accept/reject) # Update Budget Source: https://docs.campfire.ai/api-reference/core-accounting/update-budget https://api.meetcampfire.com/api/schema?format=json put /coa/api/budgets/{id} # Update Budget Account Source: https://docs.campfire.ai/api-reference/core-accounting/update-budget-account https://api.meetcampfire.com/api/schema?format=json put /coa/api/budgets/{budget_pk}/accounts/{id} # Update Chart Transaction Source: https://docs.campfire.ai/api-reference/core-accounting/update-chart-transaction https://api.meetcampfire.com/api/schema?format=json put /coa/api/transaction/{id} # Update Fixed Asset Source: https://docs.campfire.ai/api-reference/core-accounting/update-fixed-asset https://api.meetcampfire.com/api/schema?format=json put /coa/api/fixed-asset/{id} # Update Fixed Asset Automation Source: https://docs.campfire.ai/api-reference/core-accounting/update-fixed-asset-automation https://api.meetcampfire.com/api/schema?format=json put /coa/api/fixed-asset-automation/{id} Retrieve, update, or delete an automation rule. GET/PUT/PATCH/DELETE /api/fixed-asset-automation// # Update Fixed Asset Automation Match Source: https://docs.campfire.ai/api-reference/core-accounting/update-fixed-asset-automation-match https://api.meetcampfire.com/api/schema?format=json put /coa/api/fixed-asset-automation-match/{id} Retrieve or update an automation match (for editing proposed values before acceptance). GET/PATCH /api/fixed-asset-automation-match// # Update Intercompany Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/update-intercompany-journal-entry https://api.meetcampfire.com/api/schema?format=json put /coa/api/intercompany-journal-entry/{id} Updates an existing intercompany journal entry with new transaction details. This endpoint allows for: - Modifying transaction amounts and details - Updating entity assignments and exchange rates - Changing account assignments and categorizations - Updating vendor, department, and tag information - Maintaining balance validation across all entities Key requirements: - Total debits must equal total credits for each entity - All account balances must be valid in all currencies - Cannot modify entries in closed periods - All referenced accounts must be active - Existing transactions are replaced with new transaction set - Exchange rates must be provided for all currency conversions The update process atomically replaces all transactions while preserving the journal entry ID and audit trail. # Update Journal Entry Source: https://docs.campfire.ai/api-reference/core-accounting/update-journal-entry https://api.meetcampfire.com/api/schema?format=json put /coa/api/journal_entry/{id} Update a journal entry completely. All transactions will be replaced with the new ones provided. **Important Notes:** - Cannot update entries before closed book dates - Must maintain double-entry bookkeeping (debits = credits) - All existing transactions will be replaced - Exchange rates will be recalculated if not provided **Validation Rules:** - Journal entry must balance in all currencies - Accounts must be active - Cannot modify entries in closed periods # Update Transaction Match Source: https://docs.campfire.ai/api-reference/core-accounting/update-transaction-match https://api.meetcampfire.com/api/schema?format=json put /coa/api/transaction-matches/{id} # Update Transaction Match Status Source: https://docs.campfire.ai/api-reference/core-accounting/update-transaction-match-status https://api.meetcampfire.com/api/schema?format=json put /coa/api/transaction-matches/{id}/status # Update Vendor Contact Source: https://docs.campfire.ai/api-reference/core-accounting/update-vendor-contact https://api.meetcampfire.com/api/schema?format=json put /coa/api/vendor-contact/{id} Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Reorder Custom Fields Source: https://docs.campfire.ai/api-reference/custom-fields/reorder-custom-fields https://api.meetcampfire.com/api/schema?format=json post /ca/api/v1/custom-fields/reorder Reorder custom fields # Execute Custom Report Source: https://docs.campfire.ai/api-reference/financial-statements/execute-custom-report https://api.meetcampfire.com/api/schema?format=json get /ca/api/custom-reports/{id}/data Execute custom report and return DataTable-compatible response. :param request: HTTP request with query params :param pk: Custom report ID :return: Paginated, sparse-formatted response # Get Balance Sheet Source: https://docs.campfire.ai/api-reference/financial-statements/get-balance-sheet https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_balance_sheet Returns ending account balances for each period between `start_date` and `end_date` (both inclusive), split by `cadence`. This is the recommended endpoint for balance sheet ending balances. **How the date range works:** `start_date` is *not* the date balances are calculated *from*. Account balances are always accumulated from the beginning of time through each period end. `start_date`, `end_date`, and `cadence` only determine how the report is split into periods (columns). **Retained earnings:** included as its own row. **Breakdowns:** the report can be broken down or filtered by entity, department, and tag dimensions via `group_by` (pass `group` with a tag group ID when grouping by tag). # Get Cash Basis Income Statement Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-basis-income-statement https://api.meetcampfire.com/api/schema?format=json get /ca/api/cash-basis # Get Cash Basis Operating Statement Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-basis-operating-statement https://api.meetcampfire.com/api/schema?format=json get /ca/api/cash-basis-operating-statement # Get Cash Flow Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-flow https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_cash_flow # Get Cash Flow Activity Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-flow-activity https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_cash_flow_activity # Get Cash Flow Statement Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-flow-statement https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_cash_flow_v2 Sectioned cash flow statement (indirect method): operating (net income, non-cash adjustments, working-capital deltas), transactional investing and financing lines, the effect of exchange-rate changes on cash, and non-cash disclosures. The statement reconciles beginning to ending cash with a zero plug or is not rendered: an unreconciled ledger returns HTTP 422 with the plug by period and the journal entries whose accounts need cashflow classification. Monetary amounts are decimal strings. Pass export=xlsx for a workbook download. # Get Cash Operating Transactions with Projected Transactions Source: https://docs.campfire.ai/api-reference/financial-statements/get-cash-operating-transactions-with-projected-transactions https://api.meetcampfire.com/api/schema?format=json get /ca/api/cash-operating-statement/transactions # Get Comparative Balance Sheet Source: https://docs.campfire.ai/api-reference/financial-statements/get-comparative-balance-sheet https://api.meetcampfire.com/api/schema?format=json get /ca/api/balance-sheet/comparative API view for comparative balance sheet that handles budget vs actual comparisons # Get Comparative Income Statement Source: https://docs.campfire.ai/api-reference/financial-statements/get-comparative-income-statement https://api.meetcampfire.com/api/schema?format=json get /ca/api/income-statement/comparative # Get General Ledger Source: https://docs.campfire.ai/api-reference/financial-statements/get-general-ledger https://api.meetcampfire.com/api/schema?format=json get /coa/api/general-ledger Returns general-ledger transactions with running balances. Each row includes a `tags` array with the transaction's tags; a tag's `group`/`group_name` identify the tag group (dimension) it belongs to. List a customer's tag groups via `/coa/api/tag-group` and tags via `/coa/api/tag`. # Get Income Statement Source: https://docs.campfire.ai/api-reference/financial-statements/get-income-statement https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_income_statement Returns account activity (revenue and expense movement) within the `start_date`-`end_date` range, split by `cadence`. Unlike the balance sheet, the income statement reflects only the activity that falls *inside* the requested date range - `start_date` is the true start of the activity window. **Breakdowns:** supports entity, department, vendor, and tag breakdowns/filters via `group_by` (pass `group` with a tag group ID when grouping by tag). # Get Trial Balance Source: https://docs.campfire.ai/api-reference/financial-statements/get-trial-balance https://api.meetcampfire.com/api/schema?format=json get /ca/api/get_trial_balance Returns debit and credit totals for each account over a date range. **The summation window depends on the account type:** - **Balance sheet accounts** (assets, liabilities, equity): totals are summed from the beginning of time through `end_date`. - **Income statement accounts** (revenue, expenses): the window depends on `income_statement_basis`. With the default `period` basis, totals are summed from `start_date` through `end_date` and a synthetic Net Income (Prior Periods) row carries current-fiscal-year income earned before `start_date`. With `fiscal_ytd`, totals are summed from the fiscal-year start through `end_date` and no Net Income row is emitted. The effective income-statement window start is returned as `income_statement_start`. Each account also carries rollforward columns, all presented as one-sided debit/credit pairs: `beginning_balances` (balance as of the day before `start_date`; fiscal-window-scoped for income-statement accounts), `activity` (gross period debits and credits), and `ending_balances` (`beginning + activity`, the net one-sided presentation of the account's balance). Beginning and ending columns each foot to zero across the report and period debits equal period credits. Retained earnings is included as its own row. For balance sheet ending balances specifically, prefer `GET /ca/api/get_balance_sheet`. # List Custom Reports Source: https://docs.campfire.ai/api-reference/financial-statements/list-custom-reports https://api.meetcampfire.com/api/schema?format=json get /ca/api/custom-reports # Retrieve Custom Report Source: https://docs.campfire.ai/api-reference/financial-statements/retrieve-custom-report https://api.meetcampfire.com/api/schema?format=json get /ca/api/custom-reports/{id} # Create Webhook Source: https://docs.campfire.ai/api-reference/integrations/create-webhook https://api.meetcampfire.com/api/schema?format=json post /integrations/api/v1/webhook # Delete Webhook Source: https://docs.campfire.ai/api-reference/integrations/delete-webhook https://api.meetcampfire.com/api/schema?format=json delete /integrations/api/v1/webhook/{id} # List Webhook Events Source: https://docs.campfire.ai/api-reference/integrations/list-webhook-events https://api.meetcampfire.com/api/schema?format=json get /integrations/api/v1/webhook/{id}/events # List Webhooks Source: https://docs.campfire.ai/api-reference/integrations/list-webhooks https://api.meetcampfire.com/api/schema?format=json get /integrations/api/v1/webhook # Partial Update Webhook Source: https://docs.campfire.ai/api-reference/integrations/partial-update-webhook https://api.meetcampfire.com/api/schema?format=json patch /integrations/api/v1/webhook/{id} # Retrieve Webhook Source: https://docs.campfire.ai/api-reference/integrations/retrieve-webhook https://api.meetcampfire.com/api/schema?format=json get /integrations/api/v1/webhook/{id} # Update Webhook Source: https://docs.campfire.ai/api-reference/integrations/update-webhook https://api.meetcampfire.com/api/schema?format=json put /integrations/api/v1/webhook/{id} # Bulk Search Contracts Source: https://docs.campfire.ai/api-reference/revenue-recognition/bulk-search-contracts https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/bulk-search Search for contracts by deal_name in a single request. # Bulk Search Products Source: https://docs.campfire.ai/api-reference/revenue-recognition/bulk-search-products https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/product/bulk-search Resolve many product cells in a single request. Each term is matched against product_id, display_name, product_uuid, id, then product_name, in that order. A term matching more than one product is returned in the ambiguous list instead of being resolved. # Create Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts Create a new contract. Evergreen vs standard: - Standard contract: set is_evergreen=false and provide a fixed contract_end_date. - Evergreen contract: set is_evergreen=true and leave contract_end_date as null. The system manages a rolling effective_end_date, exposes working_end_date for downstream usage, and returns evergreen_locked_date for immutable historical boundary rules. Additional evergreen constraints: - is_evergreen and auto_renew cannot both be true. - billing_frequency is required for evergreen behavior. - default_payment_term is not implemented yet for standard contracts. It can currently be set only for Evergreen contracts and is applied to their automatically generated invoices. Other contract invoice flows retain their existing payment-term selection behavior; support may be extended to additional contract types in the future. - When default_payment_term is omitted or null, automatically generated Evergreen invoices retain the existing Net 30 fallback. - skip_evergreen_invoice_generation is creation-time only and cannot be changed on existing contracts. - skip_evergreen_invoice_generation=true skips only Campfire's auto-generated evergreen invoices. Revenue transactions still generate. # Create Contract Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-bundle https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/bundles Create a new contract bundle. Evergreen vs standard: - Standard contracts require a fixed bundle end_date. - Evergreen contracts allow end_date to be null (open-ended) or set to a billing-period end date. Evergreen bundle start/end dates must align with billing period boundaries. Evergreen-specific option: - rebalance_journal_entries_indefinitely=true keeps invoice-journal rebalancing in sync as the evergreen contract extends. # Create Contract Milestone Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-milestone https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/milestones Create a new milestone for a contract. This will automatically create an associated revenue transaction. # Create Contract Product Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-product https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/product Create a new product # Create Contract Subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-subscription https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/subscriptions Create a new contract subscription. Evergreen vs standard: - Standard contract subscriptions generally provide explicit lines and fixed start/end dates. - Evergreen contract subscriptions can provide period_amount to auto-generate lines. Their dates must align to billing period boundaries and must not exceed the contract's current working_end_date. Notes: - Usage and milestone subscription flows are not supported for evergreen contracts. - For evergreen contracts, period_amount is the source-of-truth amount per billing period. - renewal_behavior: - FOLLOW_CONTRACT: subscription follows evergreen contract extension windows. - FIXED_END: subscription keeps its own fixed end_date and does not extend automatically. # Create Contract Tier Price Override Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-tier-price-override https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/tier-price-overrides # Create Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/usage List usage revenue records # Create Prepaid Commit Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-prepaid-commit https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/prepaid-commits # Create Prepaid Commit Consumption Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-prepaid-commit-consumption https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/consumption # Create Product Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-product-bundle https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/product-bundles Create a new product bundle with products and percentage allocations. Total percentage must equal 100. # Create Revenue Transaction Source: https://docs.campfire.ai/api-reference/revenue-recognition/create-revenue-transaction https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/transactions Create a new revenue transaction # Delete Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{id} # Delete Contract Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract-bundle https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/bundles/{id} # Delete Contract Customer Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract-customer https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/customers/{id} # Delete Contract Milestone Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract-milestone https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/milestones/{id} # Delete Contract Subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract-subscription https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/subscriptions/{id} # Delete Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/usage/{id} Retrieve, update, and delete contract usage revenue records # Delete Prepaid Commit Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-prepaid-commit https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/prepaid-commits/{id} # Delete Prepaid Commit Consumption Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-prepaid-commit-consumption https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/consumption/{id} # Delete Product Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-product https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/product/{id}/delete The type of the None singleton. # Delete Product Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-product-bundle https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/product-bundles/{id} # Delete Product (deprecated) Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-product-deprecated https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/product/{id} Deprecated: use `POST /rr/api/v1/product/{id}/delete`, which also takes an optional reason for the audit log. # Delete Revenue Transaction Source: https://docs.campfire.ai/api-reference/revenue-recognition/delete-revenue-transaction https://api.meetcampfire.com/api/schema?format=json delete /rr/api/v1/transactions/{id} # Duplicate Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/duplicate-contract https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{id}/duplicate # Fully reverse a usage-relative subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/fully-reverse-a-usage-relative-subscription https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/subscriptions/{id}/full-reversal Wraps ``CreateModelMixin.create`` (or any method named ``create``) with ``Idempotency-Key`` handling. Place this mixin **before** the view's other base classes so its ``create`` overrides the inherited one:: class JournalEntryListCreate( IdempotentCreateMixin, HistoryFilteringMixin, ListCreateAPIView, ): ... # Get Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-bundle-allocations https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/milestones/{milestone_id}/allocations Retrieve the current bundle allocation details for a contract subscription, milestone, or usage. # Get Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-bundle-allocations-1 https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/subscriptions/{subscription_id}/allocations Retrieve the current bundle allocation details for a contract subscription, milestone, or usage. # Get Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-bundle-allocations-2 https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/usage/{usage_id}/allocations Retrieve the current bundle allocation details for a contract subscription, milestone, or usage. # Get Prepaid Commit Summary Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-prepaid-commit-summary https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commit-summary # Get Prepaid Commit Usage Event Distinct Values Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-prepaid-commit-usage-event-distinct-values https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/usage-events/distinct-values Return distinct values for a given JSONB data field, for filter dropdowns. # Get Prepaid Commit Usage Events Template Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-prepaid-commit-usage-events-template https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/usage-events/template Download a CSV template (commit-scoped). # Get rrapiv1contracts minimum commit preview Source: https://docs.campfire.ai/api-reference/revenue-recognition/get-rrapiv1contracts-minimum-commit-preview https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{id}/minimum-commit-preview Projected monthly minimum commitment true-up for a contract. Read-only. Returns the shortfall the month-end batch *would* post if it ran right now. Lets the contract detail screen show a live floor preview without triggering writes from the UI. # List Contract Bundles Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-bundles https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/bundles Retrieve a list of contract bundles with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Contract Customers Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-customers https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/customers Retrieve a list of contract customers with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Contract Milestones Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-milestones https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/milestones Retrieve a list of milestones for a specific contract with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Contract Products Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-products https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/product Retrieve a list of contract products with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Contract Subscriptions Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-subscriptions https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/subscriptions Retrieve a list of contract subscriptions with optional filtering and sorting. Subscriptions on Stripe contracts with no linked revenue transactions are omitted. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Contract Tier Price Overrides Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-tier-price-overrides https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/tier-price-overrides # List Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/usage List usage revenue records # List Contracts Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-contracts https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts Retrieve a list of contracts with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. When download=true, triggers an async workflow that generates a ZIP file with contracts_summary.csv and contracts_detail.csv, uploads to S3, and sends an email with the download link. # List Prepaid Commit Consumption Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-prepaid-commit-consumption https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/consumption # List Prepaid Commit Usage Events Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-prepaid-commit-usage-events https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/usage-events # List Prepaid Commits Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-prepaid-commits https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits # List Product Bundles Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-product-bundles https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/product-bundles Retrieve a list of product bundles with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Revenue Transactions Source: https://docs.campfire.ai/api-reference/revenue-recognition/list-revenue-transactions https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/transactions Retrieve a list of revenue transactions with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # Modify Subscription Schedule Source: https://docs.campfire.ai/api-reference/revenue-recognition/modify-subscription-schedule https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/modify-subscription-schedule Generate a modified subscription schedule by comparing a new schedule against an existing subscription. Returns the delta between the original and modified schedules, with support for catch-up accounting and contract end date modifications. # Parse Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/parse-contract https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/parse Parse contract details from uploaded PDF files using AI. # Partial Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-bundle-allocations https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/milestones/{milestone_id}/allocations Partially update bundle allocations. Same behavior as PUT. # Partial Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-bundle-allocations-1 https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/subscriptions/{subscription_id}/allocations Partially update bundle allocations. Same behavior as PUT. # Partial Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-bundle-allocations-2 https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/usage/{usage_id}/allocations Partially update bundle allocations. Same behavior as PUT. # Partial Update Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-contract https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{id} # Partial Update Contract Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-contract-bundle https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/bundles/{id} # Partial Update Contract Customer Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-contract-customer https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/customers/{id} # Partial Update Contract Milestone Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-contract-milestone https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/milestones/{id} # Partial Update Contract Subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-contract-subscription https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/subscriptions/{id} # Partial Update Prepaid Commit Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-prepaid-commit https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/prepaid-commits/{id} # Partial Update Product Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-product https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/product/{id} # Partial Update Product Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-product-bundle https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/product-bundles/{id} # Partial Update Revenue Transaction Source: https://docs.campfire.ai/api-reference/revenue-recognition/partial-update-revenue-transaction https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/transactions/{id} # Partially Update Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/partially-update-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json patch /rr/api/v1/contracts/{contract_id}/usage/{id} Retrieve, update, and delete contract usage revenue records # Preview Contract Termination Settlement Source: https://docs.campfire.ai/api-reference/revenue-recognition/preview-contract-termination-settlement https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{id}/termination-settlement-preview # Process Prepaid Commit Adjustments Source: https://docs.campfire.ai/api-reference/revenue-recognition/process-prepaid-commit-adjustments https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/process-adjustments Process adjustment events for a prepaid commit and create credit memos. # Retrieve Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{id} # Retrieve Contract Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract-bundle https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/bundles/{id} # Retrieve Contract Customer Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract-customer https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/customers/{id} # Retrieve Contract Milestone Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract-milestone https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/milestones/{id} # Retrieve Contract Subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract-subscription https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/subscriptions/{id} Subscriptions on Stripe contracts with no linked revenue transactions return 404. # Retrieve Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/usage/{id} Retrieve, update, and delete contract usage revenue records # Retrieve Prepaid Commit Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-prepaid-commit https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/contracts/{contract_id}/prepaid-commits/{id} # Retrieve Product Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-product https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/product/{id} # Retrieve Product Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-product-bundle https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/product-bundles/{id} # Retrieve Revenue Transaction Source: https://docs.campfire.ai/api-reference/revenue-recognition/retrieve-revenue-transaction https://api.meetcampfire.com/api/schema?format=json get /rr/api/v1/transactions/{id} # Terminate Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/terminate-contract https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{id}/terminate Terminate a contract and optionally void associated invoices. If the user has permission to terminate contracts and void invoices, both operations are performed atomically. If the user lacks permission for either operation, a draft is created instead, and the response indicates which operations were drafted. Returns 400 if any of the provided void_invoice_ids are invalid (not found, already voided, has payments, void date is before the invoice date, or in a closed period). # Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-bundle-allocations https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/milestones/{milestone_id}/allocations Update the bundle allocations for a contract item. The sum of all line amounts must equal the bundle's total_amount. Changes will cascade to related RevenueTransactions and JournalEntries. # Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-bundle-allocations-1 https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/subscriptions/{subscription_id}/allocations Update the bundle allocations for a contract item. The sum of all line amounts must equal the bundle's total_amount. Changes will cascade to related RevenueTransactions and JournalEntries. # Update Bundle Allocations Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-bundle-allocations-2 https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/usage/{usage_id}/allocations Update the bundle allocations for a contract item. The sum of all line amounts must equal the bundle's total_amount. Changes will cascade to related RevenueTransactions and JournalEntries. # Update Contract Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{id} # Update Contract Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract-bundle https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/bundles/{id} # Update Contract Customer Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract-customer https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/customers/{id} # Update Contract Milestone Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract-milestone https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/milestones/{id} # Update Contract Subscription Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract-subscription https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/subscriptions/{id} # Update Contract Usage Revenue Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-contract-usage-revenue https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/usage/{id} Retrieve, update, and delete contract usage revenue records # Update Prepaid Commit Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-prepaid-commit https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/prepaid-commits/{id} # Update Prepaid Commit Consumption Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-prepaid-commit-consumption https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/consumption/{id} # Update Product Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-product https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/product/{id} # Update Product Bundle Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-product-bundle https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/product-bundles/{id} # Update Revenue Transaction Source: https://docs.campfire.ai/api-reference/revenue-recognition/update-revenue-transaction https://api.meetcampfire.com/api/schema?format=json put /rr/api/v1/transactions/{id} # Upload Prepaid Commit Usage Events Source: https://docs.campfire.ai/api-reference/revenue-recognition/upload-prepaid-commit-usage-events https://api.meetcampfire.com/api/schema?format=json post /rr/api/v1/contracts/{contract_id}/prepaid-commits/{commit_id}/usage-events/upload Upload a CSV of usage events for a specific prepaid commit (commit-scoped). # Create Chart Entity Source: https://docs.campfire.ai/api-reference/settings/create-chart-entity https://api.meetcampfire.com/api/schema?format=json post /coa/api/entity Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Create Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/create-customer-currencies https://api.meetcampfire.com/api/schema?format=json post /ca/api/user_currency Complete mixin for history filtering with pagination support. Returns either active OR deleted records based on include_deleted parameter. # Delete Chart Entity Source: https://docs.campfire.ai/api-reference/settings/delete-chart-entity https://api.meetcampfire.com/api/schema?format=json delete /coa/api/entity/{id} # Delete Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/delete-customer-currencies https://api.meetcampfire.com/api/schema?format=json delete /ca/api/user_currency/{id} # Delete File Source: https://docs.campfire.ai/api-reference/settings/delete-file https://api.meetcampfire.com/api/schema?format=json delete /ca/api/file/{id} # Get Currencies Exchange Rates for Currency Source: https://docs.campfire.ai/api-reference/settings/get-currencies-exchange-rates-for-currency https://api.meetcampfire.com/api/schema?format=json get /ca/api/user_currency/with_rate # Get Currency Exchange Rate Source: https://docs.campfire.ai/api-reference/settings/get-currency-exchange-rate https://api.meetcampfire.com/api/schema?format=json get /ca/api/user_currency/rate # Get File Source: https://docs.campfire.ai/api-reference/settings/get-file https://api.meetcampfire.com/api/schema?format=json get /ca/api/file/{id} # Get File Temporary Download URL Source: https://docs.campfire.ai/api-reference/settings/get-file-temporary-download-url https://api.meetcampfire.com/api/schema?format=json get /ca/api/file/{id}/temp-download-url Return a short-lived presigned S3 URL for downloading a file. Pass ``?disposition=inline`` to render preview-safe types (PDF, images) in the browser instead of forcing a download. :param request: The incoming DRF request (must be authenticated). :return: JSON response with ``url`` key or an error. # List All Entities for Intercompany JE Source: https://docs.campfire.ai/api-reference/settings/list-all-entities-for-intercompany-je https://api.meetcampfire.com/api/schema?format=json get /coa/api/entity/for-intercompany Returns ALL entities for intercompany journal entry creation. This endpoint bypasses entity-scoped filtering because users need to select entities they don't normally have access to when creating intercompany journal entries (per the entity-scoped-user-access spec). Uses minimal serializer to only expose id, name, and currency - preventing data leakage of sensitive entity details to users who may not have full access to all entities. # List Chart Entities Source: https://docs.campfire.ai/api-reference/settings/list-chart-entities https://api.meetcampfire.com/api/schema?format=json get /coa/api/entity Retrieve a list of chart entities with optional filtering # List Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/list-customer-currencies https://api.meetcampfire.com/api/schema?format=json get /ca/api/user_currency Retrieve a list of customer currencies with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # List Files Source: https://docs.campfire.ai/api-reference/settings/list-files https://api.meetcampfire.com/api/schema?format=json get /ca/api/file Retrieve a list of files with optional filtering and sorting. Supports including soft-deleted records for audit and recovery purposes. When include_deleted=true, returns ONLY deleted records instead of active records. Deleted records contain minimal data: 'id', 'is_deleted=true', 'deleted_at' timestamp, and 'last_modified_at'. When 'false' or omitted, returns ONLY active records. This provides clean separation between active and deleted data. # Partial Update Chart Entity Source: https://docs.campfire.ai/api-reference/settings/partial-update-chart-entity https://api.meetcampfire.com/api/schema?format=json patch /coa/api/entity/{id} # Partial Update Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/partial-update-customer-currencies https://api.meetcampfire.com/api/schema?format=json patch /ca/api/user_currency/{id} # Partially Update Chart Account Settings Source: https://docs.campfire.ai/api-reference/settings/partially-update-chart-account-settings https://api.meetcampfire.com/api/schema?format=json patch /coa/api/chart-account-settings Partially update the default chart accounts to be used across the platform. Each input is the id to an existing chart account. # Patch File Source: https://docs.campfire.ai/api-reference/settings/patch-file https://api.meetcampfire.com/api/schema?format=json patch /ca/api/file/{id} # Retrieve Chart Account Settings Source: https://docs.campfire.ai/api-reference/settings/retrieve-chart-account-settings https://api.meetcampfire.com/api/schema?format=json get /coa/api/chart-account-settings These are the defaults chart accounts to be used across the platform. Each input is the id to an existing chart account. # Retrieve Chart Entity Source: https://docs.campfire.ai/api-reference/settings/retrieve-chart-entity https://api.meetcampfire.com/api/schema?format=json get /coa/api/entity/{id} # Retrieve Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/retrieve-customer-currencies https://api.meetcampfire.com/api/schema?format=json get /ca/api/user_currency/{id} # Update Chart Account Settings Source: https://docs.campfire.ai/api-reference/settings/update-chart-account-settings https://api.meetcampfire.com/api/schema?format=json put /coa/api/chart-account-settings These are the defaults chart accounts to be used across the platform. Each input is the id to an existing chart account. # Update Chart Entity Source: https://docs.campfire.ai/api-reference/settings/update-chart-entity https://api.meetcampfire.com/api/schema?format=json put /coa/api/entity/{id} # Update Customer Currencies Source: https://docs.campfire.ai/api-reference/settings/update-customer-currencies https://api.meetcampfire.com/api/schema?format=json put /ca/api/user_currency/{id} # Update File Source: https://docs.campfire.ai/api-reference/settings/update-file https://api.meetcampfire.com/api/schema?format=json put /ca/api/file/{id} # Upload Chart Entity Logo Source: https://docs.campfire.ai/api-reference/settings/upload-chart-entity-logo https://api.meetcampfire.com/api/schema?format=json post /coa/api/entity/{id}/logo # Upload File Source: https://docs.campfire.ai/api-reference/settings/upload-file https://api.meetcampfire.com/api/schema?format=json post /ca/api/file/upload Upload a file directly to Campfire. This is the primary way to upload files. **Supported Models:** bill, chat, close_task, closecheckitem, contract, credit_memo, customer, debit_memo, draft_queue, fixed_asset, forecast, intercompany_journal, invoice, journal_entry, journalentry, lease_v2, migration_record, policy, reconciliation, reconciliation_report, revenue_contract **Supported Content Types:** application/msword, application/pdf, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.openxmlformats-officedocument.wordprocessingml.document, image/gif, image/jpeg, image/jpg, image/png, image/webp, text/csv, text/markdown, text/plain, text/x-markdown **Maximum File Size:** 100MB **Example:** ```bash curl -X POST "https://api.meetcampfire.com/ca/api/file/upload?model=bill&object_id=12345" \ -H "Authorization: Token YOUR_TOKEN" \ -F "file=@receipt.pdf" ``` **OAuth Apps:** attaching a file changes the record, so an app token needs the write scope for that record type (e.g. `journal_entries:write` for `model=journal_entry`), and the person who connected the app must hold the same permission. Apps pass `model` alone, never `app`. **Query Parameters:** - `model` (required): Model type (e.g., "bill", "invoice", "contract") - `object_id` (optional): ID of the object to attach the file to **Request Body:** - `file` (required): The file to upload (multipart/form-data) # Accounts Payable Workflows Source: https://docs.campfire.ai/guides/accounts-payable How to create, modify, pay and void bills in Campfire > [!NOTE] > > All requests in this flow assume you have a valid access token attached in your request headers. See our [authentication guide](/quickstart) for more information. ## Creating a bill This section will guide you through the process of creating a bill in Campfire. **1. Fetch related data** We'll need to grab some object references for related objects to create our bill. We'll need to pass in the id's of the related objects where applicable in the bill creation request. Linked here are the filter endpoints for the applicable objects. These include: * [Accounts (Expense Account on the Line Items)(Required)](/api-reference/company-objects/list-chart-accounts) * [Vendors (Required)](/api-reference/company-objects/list-vendors) * [Entities (Required)](/api-reference/settings/list-chart-entities) * [Departments (Optional)](/api-reference/company-objects/list-departments) * [Custom Dimension Fields (Optional)](/api-reference/company-objects/list-custom-dimensions) **2. Assemble the request** We can now create our request body by filling in the related fields. Here are the required fields: | Field | Description | Example | | - | - | - | | `terms` | Payment terms (default is net\_30, can be: 7, 10, 15, 20, 30, 40, 45, 60, 90, 105, 120 or due\_on\_receipt) | `"net_30"` | | `bill_date` | Accounting date for the bill in YYYY-MM-DD format | `"2025-07-01"` | | `due_date` | Due date for the bill in YYYY-MM-DD format | `"2025-08-25"` | | `lines` | Array of line items for the bill | See line item fields below | | `entity` | ID from entity | `"5"` | | `currency` | Currency code | `"USD"` | | `exchange_rate_book` | Exchange rate between transactional and entity currency (auto-computed if not provided) | `1` | | `exchange_rate` | Exchange rate between entity and consolidation currency (auto-computed if not provided) | `1.373` | | `vendor` | ID from vendor | `"34182"` | | `bill_number` | Bill number | `"098765"` | | `item_date` | Bill date in YYYY-MM-DD format | `"2025-07-01"` | | `message_on_bill` | Message to display on bill | `"Bill Message"` | | `mailing_address` | Free text address | `"1234 Main St. San Francisco CA"` | **Line Item Fields:** | Field | Description | Example | | - | - | - | | `tags` | Array of custom dimension field IDs (optional) | `[{"id": "8114"}]` | | `account` | ID from accounts (expense account) | `"180564"` | | `amount` | Line item amount | `10000` | | `description` | Line item description | `"Line Desc"` | | `bill_customer` | ID from vendor | `"34182"` | | `department` | ID from department (optional) | `"35"` | Example request body: ```json theme={null} { "terms": "net_30", "bill_date": "2025-07-01", "due_date": "2025-08-25", "lines": [ { "tags": [ { "id": "8114" } ], "account": "180564", "amount": 10000, "description": "Line Desc", "bill_customer": "34182", "department": "35" } ], "entity": "5", "currency": "USD", "exchange_rate_book": 1, "exchange_rate": 1.373, "vendor": "34182", "bill_number": "098765", "item_date": "2025-07-01", "message_on_bill": "Bill Message", "mailing_address": "1234 Main St. San Francisco CA" } ``` **3. Post the bill** Now that we have the request we can post it via the [Create Bill](/api-reference/accounts-payable/create-accounting-bill) endpoint. Congrats! You've created your first bill! ## Paying a Bill This section will walk you through posting a payment to a bill. **1. Get a Journal & Transaction** We need to get a transaction id to reference in the payment. You have two options for this: * [Creating a Journal, and using one of its transactions](/guides/journal-entries) * [Finding Existing Transactions](/api-reference/core-accounting/list-chart-transactions) **2. Assembling the payment** Now that we have a transaction id, we can create our payment request body. Payments that don't use the full amount of a transaction will bump out a new line of the journal based on the referenced transaction. > [!TIP] > > You can apply multiple transactions to a bill at the same time. Each transaction will be a separate payment. | Field | Description | Example | | - | - | - | | `transaction_id` | ID from transaction | `"1234"` | | `amount` | Payment amount | `10000` | | `account` | ID from account (If you want to categorize the transaction at the same time) | `"1234"` | Example request body: ```json theme={null} { "transactions": [ { "transaction_id": 21069178, "account_id": "2550", "amount": 8999.99 } ], } ``` **3. Post the payment** Now that we have the request we can post it via the [Create Payment](/api-reference/accounts-payable/mark-bill-as-paid) endpoint. Congrats! You've paid your bill! # Accounts Receivable Workflows Source: https://docs.campfire.ai/guides/accounts-receivable How to create, modify, pay and void invoices in Campfire > [!NOTE] > > All requests in this flow assume you have a valid access token attached in your request headers. See our [authentication guide](/quickstart) for more information. ## Creating an invoice This section will guide you through the process of creating an invoice in Campfire. **1. Fetch related data** We'll need to grab some object references for related objects to create our invoice. We'll need to pass in the id's of the related objects where applicable in the invoice creation request. Linked here are the filter endpoints for the applicable objects. These include: * [Products (Required)](/api-reference/revenue-recognition/list-contract-products) * [Customers (Required)](/api-reference/company-objects/list-vendors) * [Entities (Required)](/api-reference/settings/list-chart-entities) * [Contracts (Optional)](/api-reference/revenue-recognition/list-contracts) **2. Assemble the request** We can now create our request body by filling in the related fields. Here are the required fields: | Field | Description | Example | | - | - | - | | `terms` | Payment terms (default is net\_30, can be: 7, 10, 15, 20, 30, 40, 45, 60, 90, 105, 120 or due\_on\_receipt) | `"net_30"` | | `invoice_date` | Accounting date for the invoice in YYYY-MM-DD format | `"2025-07-01"` | | `due_date` | Due date for the invoice in YYYY-MM-DD format | `"2025-07-31"` | | `lines` | Array of line items for the invoice | See line item fields below | | `entity` | ID from entity | `"54"` | | `currency` | Currency code | `"USD"` | | `message_on_invoice` | Message to display on invoice | `"Invoice Message"` | | `exchange_rate_book` | Exchange rate between transactional and entity currency (auto-computed if not provided) | `1` | | `exchange_rate` | Exchange rate between entity and consolidation currency (auto-computed if not provided) | `1` | | `client` | ID from client | `"24020"` | | `billing_address` | Billing address | `"Billing Address"` | | `shipping_address` | Shipping address | `"Shipping Address"` | | `contract` | ID from contract (optional) | `"24899"` | | `purchase_order_number` | Purchase order number | `"123456789"` | | `invoice_number` | Invoice number | `"1234567890"` | | `location_of_sale` | Location of sale description | `"Location of sale desc"` | | `item_date` | Bill date in YYYY-MM-DD format | `"2025-07-01"` | | `period_start` | Period start date in YYYY-MM-DD format | `"2025-07-01"` | | `period_end` | Period end date in YYYY-MM-DD format | `"2025-07-31"` | | `shipping_date` | Shipping date in YYYY-MM-DD format | `"2025-07-01"` | **Line Item Fields:** | Field | Description | Example | | - | - | - | | `service_date` | Service date in YYYY-MM-DD format | `"2025-07-01"` | | `amount` | Line item amount | `300` | | `product` | ID from product | `"3560"` | | `rate` | Rate per unit | `15` | | `description` | Line item description | `"Line desc"` | | `quantity` | Quantity | `20` | | `tax` | Tax amount | `12` | Example request body: ```json theme={null} { "terms": "net_30", "invoice_date": "2025-07-01", "due_date": "2025-07-31", "lines": [ { "service_date": "2025-07-01", "amount": 300, "product": "3560", "rate": 15, "description": "Line desc", "quantity": 20, "tax": 12 } ], "entity": "54", "currency": "USD", "message_on_invoice": "Invoice Message", "exchange_rate_book": 1, "exchange_rate": 1, "client": "24020", "billing_address": "Billing Address", "shipping_address": "Shipping Address", "contract": "24899", "purchase_order_number": "123456789", "invoice_number": "1234567890", "location_of_sale": "Location of sale desc", "item_date": "2025-07-01", "period_start": "2025-07-01", "period_end": "2025-07-31", "shipping_date": "2025-07-01" } ``` **3. Post the invoice** Now that we have the request we can post it via the [Create Invoice](/api-reference/accounts-receivable/create-invoice) endpoint. Congrats! You've created your first invoice! ## Paying an invoice This section will walk you through posting a payment to an invoice. **1. Get a Journal & Transaction** We need to get a transaction id to reference in the payment. You have two options for this: * [Creating a Journal, and using one of its transactions](/guides/journal-entries) * [Finding Existing Transactions](/api-reference/core-accounting/list-chart-transactions) **2. Assembling the payment** Now that we have a transaction id, we can create our payment request body. Payments that don't use the full amount of a transaction will bump out a new line of the journal based on the referenced transaction. > [!TIP] > > You can apply multiple transactions to an invoice at the same time. Each transaction will be a separate payment. | Field | Description | Example | | - | - | - | | `transaction_id` | ID from transaction | `"1234"` | | `amount` | Payment amount | `10000` | | `account` | ID from account (If you want to categorize the transaction at the same time) | `"1234"` | Example request body: ```json theme={null} { "transactions": [ { "transaction_id": 21069178, "account_id": "2550", "amount": 8999.99 } ], } ``` **3. Post the payment** Now that we have the request we can post it via the [Create Payment](/api-reference/accounts-receivable/mark-invoice-as-paid) endpoint. Congrats! You've paid your invoice! # AI Integration with Model Context Protocol Source: https://docs.campfire.ai/guides/ai-integration Connect Campfire to your favorite AI tools using MCP > [!NOTE] > > MCP (Model Context Protocol) allows you to access Campfire's APIs through AI tools like Cursor, VS Code, Claude Desktop, and others. ## What is MCP? The Model Context Protocol (MCP) is an open standard that enables AI applications to securely connect to external data sources and tools. Campfire exposes an MCP server so you can: * Query your accounting data through AI assistants * Generate reports using natural language * Analyze financial trends with AI-powered insights * Automate accounting workflows through AI tools ## How the MCP Server Works The MCP server provides AI tools that map directly to Campfire API endpoints. When an AI assistant uses a tool, the MCP server: 1. Authenticates your request using your API token 2. Calls the corresponding Campfire API endpoint with your credentials 3. Returns the response to the AI assistant Your token is sent with every API tool call so results stay scoped to your organization. ## Available Tools The MCP server provides 12 tools that map directly to Campfire API endpoints: > **Core Accounting** > > * **Chart of Accounts**: Retrieve chart of accounts with optional filtering by type, subtype, or search query > * **Transactions**: Search and filter general ledger transactions with support for entity, account, vendor, department, tag, and date range filters > **Company Data** > > * **Entities**: Retrieve chart entities (parent companies, subsidiaries, locations) > * **Vendors**: Retrieve vendor/payee directory with contact details and status > * **Departments**: Retrieve department hierarchy (cost centers, business units) > * **Tags**: Retrieve transaction tags (custom dimensions) used for analytics > **Financial Reports** > > * **Income Statement**: Generate profit & loss statements for specified periods with configurable cadence (monthly, quarterly, yearly) > * **Balance Sheet**: Generate balance sheet showing assets, liabilities, and equity > * **Cash Flow Statement**: Generate cash flow by operating, investing, and financing activities > **Budgeting & Revenue** > > * **Budgets**: Retrieve budget records with entity and time-period metadata > * **Contracts**: Retrieve revenue recognition contracts with performance obligations > * **Aging Report**: Generate AP/AR aging reports with age bucket breakdowns > [!NOTE] > > All tools return data scoped to your organization based on your authentication token. ## How the tools are used Your AI tool maps your question to the right Campfire API using the OpenAPI schema. You ask in natural language; the AI translates your request into the appropriate endpoint and parameters (filters, date ranges, pagination). Results are scoped to the organization tied to your API token. For full request parameters (filters, date formats, pagination), see the [API reference](/api-reference) for each endpoint. ## Getting Started **1. Configure Your AI Tool** Add the Campfire MCP server to your AI tool's configuration: **Cursor** Open the Command Palette (Cmd+Shift+P), select **MCP: Open Settings**, and add: ```json theme={null} { "mcpServers": { "Campfire": { "url": "https://api.meetcampfire.com/mcp" } } } ``` **Claude Desktop** In Claude Desktop, go to **Settings** > **Connectors** > **Search for Campfire**, and click on Connect. **VS Code** Create or edit `.vscode/mcp.json` in your workspace: ```json theme={null} { "servers": { "Campfire": { "url": "https://api.meetcampfire.com/mcp" } } } ``` **2. Restart Your AI Tool** Restart your AI tool to load the new MCP configuration. **3. Start Querying** You can now ask your AI assistant questions about your Campfire data: * "Show me the income statement for Q1 2024" * "Find all transactions from vendor ABC Corp in the last month" * "What are my top 10 expense accounts by amount?" * "List all departments in my organization" * "Show me all active contracts" ## Example Queries Here are some example queries you can try with your AI tool: > **Chart of Accounts** > > ``` > Get all accounts of type ASSET > ``` > > ``` > Find accounts with "cash" in the name > ``` > > ``` > Show me all bank accounts > ``` > **Transactions** > > ``` > Find transactions from the last 30 days > ``` > > ``` > Show me all transactions for vendor ABC Corp > ``` > > ``` > Get transactions for the Marketing department > ``` > > ``` > Find all transactions over $1000 in December 2023 > ``` > **Company Data** > > ``` > List all vendors with names containing "Tech" > ``` > > ``` > Show me all departments > ``` > > ``` > Get all entities in my organization > ``` > > ``` > Find tags related to "Marketing" > ``` > **Financial Reports** > > ``` > Generate income statement for Q1 2024 > ``` > > ``` > Show me balance sheet for December 2023 > ``` > > ``` > Get cash flow statement for the last 6 months > ``` > > ``` > Create a monthly income statement for 2023 > ``` > **Budgets, Contracts & Aging** > > ``` > Show me all budgets for our main entity > ``` > > ``` > List all active contracts > ``` > > ``` > Get accounts payable aging report > ``` > > ``` > Show me AR aging as of today > ``` > [!NOTE] > > The AI assistant will translate your natural language queries into the appropriate API calls with the correct parameters. Results are automatically scoped to your organization. ## Security & Privacy > [!WARNING] > > Your API token provides full access to your Campfire data. Keep it secure and never share it publicly. * **Authentication**: All requests require a valid API token * **Data scope**: Results are scoped to the organization associated with your API token * **Data privacy**: Your data is only accessed when you explicitly request it through the AI tool * **Secure storage**: AI tools securely store your token locally for future requests ## Troubleshooting > **401 Unauthorized** > > If you receive authentication errors: > > * Verify your API token is correct > * Check that your token hasn't expired > * Ensure the authorization header is properly configured in your MCP settings > **Tools not appearing** > > If Campfire tools don't show up in your AI assistant: > > * Restart your AI tool completely > * Verify the MCP server URL is correct in your configuration > * Check that your API token is valid > **Need help?** > > Contact our support team at [support@campfire.com](mailto:support@campfire.com) for assistance with MCP configuration or troubleshooting. # Extending Campfire with your app Source: https://docs.campfire.ai/guides/app-extensions Add buttons, embedded panels, sidebar pages, a manage link and event subscriptions to Campfire from your OAuth app An [OAuth app](/guides/oauth-apps) can do more than call the API. It can also put itself **inside Campfire**: * **Buttons** on invoice and bill pages that open a link, call your server, or open your page in a drawer. * **Panels**: your page embedded as a tab on a list page, a detail page, or an edit modal. * **Navigation**: a section in Campfire's sidebar with full-width pages from your app. * **A manage link** from the connection page to your app's settings screen. * **Event subscriptions**: signed notifications when records change in any workspace that connected your app. You define all of this once, on the app. It then shows up in every workspace where someone has connected the app, and each workspace's admins can switch individual pieces off. > **[FakeTax sample app](https://github.com/Campfire-eng/campfire_faketax_app)** > > A complete, open-source Flask app that uses every feature on this page. All the screenshots here come from it. > **[App manifest](/guides/app-manifest)** > > Define the whole app, including everything on this page, as one JSON document you keep in your repository. ## The sample app: FakeTax [FakeTax](https://github.com/Campfire-eng/campfire_faketax_app) puts made-up sales tax on invoices. The tax is fake, but the plumbing is real, so it's a working reference for each capability: | Capability | What FakeTax does with it | | - | - | | Webhook button | **Calculate tax** on an invoice reads the invoice, writes tax on every line, and tells Campfire to show a toast and refresh. | | Bulk webhook button | **Calculate FakeTax** on the invoice list does the same for up to 50 selected invoices. | | Iframe button | **Tax breakdown** opens FakeTax in a drawer where you can override the rate and apply it. | | Link button | **View in FakeTax** opens a per-line report in a new tab, after verifying a single-use context token. | | Panels | A **FakeTax** tab on the invoice page and edit modal, and a settings tab on the invoice list. | | Navigation | A **FakeTax** sidebar section with Jurisdictions, Tax codes, and Settings pages. | | Manage link | **Manage in FakeTax** on the connection page opens FakeTax's settings, signed in. | | Events | `Invoice.created` triggers automatic tax calculation when that option is on. | | Install config | Per-workspace settings (default rate, auto-calculate) stored in Campfire. | The repository's README covers local setup. In short: create an app, paste [`manifest.json`](https://github.com/Campfire-eng/campfire_faketax_app/blob/main/manifest.json) into its **Manifest** tab, rotate the signing secret, put the credentials in `.env`, and run `python app.py`. ## Before you start **1. Have extensions turned on** Buttons, panels, navigation and events only appear in, and are only sent to, workspaces that have app extensions turned on. Contact your Campfire support team to turn them on for your workspace and for the workspaces you're building for. You can define everything on your app before that. It just won't show. **2. Add your allowed domains** On your app's page (**Settings > Developer > Apps > Manage**), open the **Security** tab. Every button URL, panel and page URL, and event endpoint must be `https` on one of these hosts. `example.com` matches only that host. `*.example.com` matches its subdomains, but not `example.com` itself. You can add up to 20. Plain `http` is accepted only for `localhost`. ![The Security tab with an allowed domain and the signing secret](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-security.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=8b1e6333fba84844e7238d43805da782) **3. Rotate the signing secret** Campfire signs every webhook call, event delivery and context token with your app's **signing secret** (`whsec_...`). This is separate from your OAuth client secret. A signing secret is created automatically, but its value is never shown, so click **Rotate Secret** to get one you can copy. It's shown once. After a rotation, Campfire signs with **both** the new and the previous secret for 24 hours, so you can deploy the new secret without dropping requests. > [!NOTE] > > Extensions show only in workspaces where at least one person has connected your app. Your own workspace counts. Other workspaces see them only once your app is [published and approved](/guides/oauth-apps#private-vs-published-apps). Disconnecting the last connection in a workspace removes them there. ## Buttons Buttons add actions to Campfire pages. Manage them on your app's **Buttons** tab. ![The Buttons tab listing FakeTax's five invoice buttons](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-buttons.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=396a469adf09c67e19e02c98c51f6c3a) On an invoice, FakeTax's **Calculate tax** is a secondary button in the page header, and its other buttons are grouped under the app's name in the **Actions** menu: ![An invoice page with a Calculate tax button and a FakeTax group in the Actions menu containing Tax breakdown and View in FakeTax](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/invoice-buttons.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=a87fc03b3947d0df333617e38a45137b) Click **Add Button**, or click an existing button, to edit it: ![The Edit Calculate tax sheet with label, key, object, placement, style, action, icon, URL template, timeout, confirmation and visibility rule](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/button-editor.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=9f9c8073e055082748c351296e1310e5) | Field | Notes | | - | - | | **Label** | Up to 60 characters. | | **Key** | A stable identifier, unique within the app. Defaults to a slug of the label. Campfire sends it back to you as `slot_key`. | | **Object** | `invoice`, `bill`, `journal_entry`, or `vendor`. | | **Placement** | `detail_header` (the record's page), `list_header` (the list page, acting on selected rows), or `row_menu` (a list row's menu). | | **Style** | `menu` (default), `secondary`, or `primary`. See [How buttons are styled](#how-buttons-are-styled). | | **Action** | `link`, `webhook` (Call webhook), or `iframe` (Embedded page). | | **Icon** | A [Lucide](https://lucide.dev/icons) icon name in kebab-case, for example `calculator`. | | **URL template** | Where the action goes. See [URL templates](#url-templates). | | **Confirmation** | Optional, up to 200 characters. Campfire asks the person to confirm before running the action. | | **Show only when** | Optional rules that hide the button for records that don't match. See [Visibility rules](#visibility-rules). | An app can have up to 50 buttons. > [!NOTE] > > **Where buttons appear today:** the invoice page header, the invoice list header (with rows selected), and the bill page header. You can define buttons for other objects and placements now. They'll appear as Campfire adds them to more pages. ### Link buttons A link button opens your URL in a new tab, with a signed [context token](#context-tokens) added as `cf_ctx`: ```text theme={null} https://your-app.com/report/18545770?cf_ctx=eyJhbGciOiJIUzI1NiIs... ``` Verify the token before showing anything. FakeTax's **View in FakeTax** opens a report only after the token checks out, and refuses it on reload because the token is single-use: ![The FakeTax report for an invoice, opened from Campfire with a context token](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/button-link-report.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=7e1d3823690fc4e46b766ea83bbd1922) ### Webhook buttons A webhook button calls your server and shows the result without the person leaving Campfire. Optionally, Campfire asks them to confirm first: ![A Calculate tax confirmation dialog asking Overwrite tax on every line?](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/button-confirm.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=249efad2c50a5225fa1b11841a9c6232) Campfire then sends a signed `POST` to your URL: ```http theme={null} POST /slots/calculate HTTP/1.1 Content-Type: application/json Campfire-App-Id: 0ca4c60f-db0a-4bc3-9efa-d2dec4292130 Campfire-Delivery-Kind: slot Campfire-Webhook-Request-Timestamp: 1791990000 Campfire-Webhook-Signature-v1: 5d1c0e... { "kind": "slot.invoked", "slot_key": "calculate", "object_type": "invoice", "object_ids": ["18545770"], "surface": "detail_header", "user": {"id": 31017}, "customer": {"id": 52}, "context_token": "eyJhbGciOiJIUzI1NiIs..." } ``` Check the [signature](#verifying-signatures), do the work (usually by calling the Campfire API with the connection's OAuth token), and reply with up to four **effects**: ```json theme={null} { "effects": [ {"type": "toast", "level": "success", "message": "FakeTax: Tax $174.00 written on 1 invoice"}, {"type": "refresh"} ] } ``` | Effect | Fields | What Campfire does | | - | - | - | | `toast` | `level` (`success`, `info`, `warning`, `error`), `message` (up to 200 characters) | Shows a notification. | | `refresh` | none | Reloads the record or list, so your changes show immediately. | | `open_url` | `url` (on an allowed domain) | Opens the URL in a new tab. | | `open_iframe` | `url` (on an allowed domain), `presentation` (`drawer` or `modal`) | Opens your page inside Campfire, with the same context token. Use this when you need input from the person. | An empty `200` response is fine too. ![The invoice after Calculate tax, with \$174.00 of tax on the hardware line and a success toast](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/button-webhook-toast.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=86bab3dba7c5a33078a6d309b43f788d) Your endpoint has `timeout_ms` to respond: 8,000 ms by default, adjustable from 1,000 to 10,000. Campfire doesn't follow redirects and reads at most 64 KB of the response. If your server returns a non-`2xx` status, invalid JSON, or an unknown effect, the person sees *"\ could not complete this action."* If it times out, they see *"\ did not respond in time."* Either way, the failure is recorded on your app's [Activity](#activity-and-testing) tab. **List header buttons** act on the selected rows. `object_ids` contains up to 50 ids. Reply with one summary toast: ![Two invoices selected on the invoice list with the Actions menu open showing Calculate FakeTax under FAKETAX](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/bulk-menu.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=40e4d1471677977e7b20735bb5e3a5c7) ![A toast reading FakeTax: Tax \$174.00 written on 2 invoices](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/bulk-toast.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=b247e887a500b4e3974a69dc2fee64a6) > [!TIP] > > If your change needs approval in the workspace, the API answers `202` with a draft instead of saving the record. Tell the person it was submitted for approval rather than reporting success. FakeTax does this. ### Iframe buttons An iframe button opens your page in a **drawer** (default) or **modal**, `sm`, `md` (default), or `lg` wide. The frame URL carries a [context token](#context-tokens) as `cf_ctx`, so your server can verify the very first request and [set a cookie](#embedded-pages-and-cookies) for the page. Your page also receives the same token over the [bridge](#the-bridge): ![The Tax breakdown drawer showing FakeTax's per-line breakdown with an Apply to invoice button](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/button-iframe-drawer.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=060086e2db16d0592a9b041756b8d2f3) ### URL templates URL templates can include these placeholders: | Placeholder | Value | | - | - | | `{{record.id}}` | The record's id. Not available on `list_header` buttons; use `object_ids` from the request. | | `{{record.number}}` | The invoice number, bill number, or journal entry reference. | | `{{customer.id}}` | The workspace id. | | `{{install.}}` | A value from the workspace's [install config](#install-config). | Values are URL-encoded. A placeholder at the very **start** of a template, such as `{{install.base_url}}/report`, is inserted as-is, so each workspace can point at its own host. The result must still be on an allowed domain. ### Visibility rules **Show only when** takes up to five rules, all of which must match. Each rule is a `field`, an operator (`eq`, `neq`, `in`, `not_in`), and a value: | Object | Fields you can test | | - | - | | Invoice | `payment_status`, `currency`, `tax_exempt` | | Bill | `payment_status`, `currency`, `bill_type`, `source` | | Journal entry | `type`, `currency`, `created_automatically` | | Vendor | `vendor_type`, `is_1099`, `country` | FakeTax shows **Calculate tax** only on draft and open invoices: ```json theme={null} "visible_when": [{"field": "payment_status", "op": "in", "value": ["draft", "open"]}] ``` Campfire checks the rules again when the button is clicked. On a list, the button shows if any selected row matches, and only the matching rows are sent to you. ### How buttons are styled In your own workspace, buttons get the style you chose. In other workspaces, they start as `menu` items until a workspace admin promotes them. To keep pages tidy, each page area shows at most one `primary` and two `secondary` app buttons. Extras become menu items. If the page already has its own primary button, yours becomes secondary. App buttons are drawn in Campfire's partner color so people can tell them apart from Campfire's own. ### Who sees a button A person sees your button only if: * someone in their workspace has connected your app, * they can view that kind of record, and * a workspace admin hasn't switched the button off or limited it to other roles. Clicks are limited to 30 per minute per person. ## Panels Panels embed one of your pages as a **tab** next to Campfire's own tabs. Manage them on the **Panels** tab. ![The Panels tab with a FakeTax panel on the invoice detail page and edit modal, and one on the list page](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-panels.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=805d90db6bea22945d4a8df06eb5e4d2) | Field | Notes | | - | - | | **Label** | The tab's title, up to 60 characters. | | **Key** | Unique within the app. | | **Object** | `invoice`, `bill`, `journal_entry`, or `vendor`. | | **Placements** | One or more of `list`, `detail`, and `edit`. | | **URL template** | The page to embed. `{{record.*}}` isn't available when `list` is one of the placements. | | **Show only when** | The same [visibility rules](#visibility-rules) as buttons. | An app can have up to 20 panels. > [!NOTE] > > **Where panels appear today:** invoices (list page, invoice page, edit modal) and bills (list page, edit modal). FakeTax's breakdown on an invoice page: ![An invoice page with the FakeTax tab selected, showing the tax breakdown embedded in the page](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/panel-detail.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=7f0ac0943fa8469f6ce2838feaeb6943) And its settings on the invoice list. A list panel's token names no record: ![The invoice list with a FakeTax tab showing default rate and auto-calculate settings](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/panel-list.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=4ba8f40a3724511a5ea71292e480294d) Panels load in a sandboxed iframe (`allow-scripts allow-forms allow-same-origin allow-popups`, no referrer) whose URL carries the context token as `cf_ctx`; see [Embedded pages and cookies](#embedded-pages-and-cookies). They start 480 px tall and can resize themselves between 120 and 2,000 px over the [bridge](#the-bridge). ## Navigation Navigation adds a section to Campfire's main sidebar, after Campfire's own sections. Each page opens full-width inside Campfire, under a header with the page's label and your app's name. Manage it on the **Navigation** tab. ![The Navigation tab with a FakeTax section containing Jurisdictions, Tax codes and Settings pages](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-navigation.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=ff1ece9acc0621bf80b3fb0f8b51c194) ![The FakeTax section expanded in Campfire's sidebar with the Jurisdictions page open, showing nexus states and rates](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/nav-page.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=775c2a31af45c1e7dada8b186f8367e1) * A top-level entry with **no URL** is a section that groups pages. A top-level entry **with** a URL is a page on its own. If it also has pages under it, it shows first as **Overview**. * Pages nest one level deep. An app can have up to 30 entries in total, and keys must be unique across all of them. * Labels are up to 40 characters. Icons are Lucide names, as for buttons. * URL templates can use `{{customer.id}}` and `{{install.}}`, but not `{{record.*}}`. * Pages are framed exactly like panels, start 720 px tall, and receive a context token with `surface: "nav"` (on the URL as `cf_ctx` and over the bridge). Everyone in a connected workspace sees your navigation, unless an admin switches it off. ![The FakeTax Tax codes page embedded full-width in Campfire](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/nav-page-tax-codes.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=e7a64b433b5e56e409ce43956d497ef1) ## The manage link and onboarding ### Manage URL Set **Manage URL** on the app's **Details** tab to give connected workspaces a way into your app's settings. The connection page then shows **Manage in \**: ![The FakeTax connection page with Manage in FakeTax and Disconnect buttons, and switches for each button](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/connection-page.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=9fab33e38accbc7161f006d541f95e94) Clicking it opens your Manage URL in a new tab with a context token (`surface: "manage"`, `object_type: "workspace"`): ```text theme={null} https://your-app.com/manage?cf_ctx=eyJhbGciOiJIUzI1NiIs... ``` Verify the token, then sign the person in to your app for that workspace. FakeTax uses this as its sign-in, so people never need a separate FakeTax account. > [!NOTE] > > Manage URL is part of the app's versioned details, so a change takes effect when you [promote](/guides/oauth-apps#versions-and-approval) it. ### Onboarding after connect When someone clicks **Connect** on your app's connection page, Campfire sends them to your Connect URL with a `return_to` parameter holding the Campfire page they came from: ```text theme={null} https://your-app.com/connect?return_to=https%3A%2F%2Fapp.meetcampfire.com%2Fv2%2Fsettings%2Fconnections%2Fapps%2F... ``` Use that to run your own setup after the OAuth callback, then send the person back. **Only redirect to `return_to` if it starts with Campfire's own origin**, to avoid an open redirect. FakeTax's onboarding asks where the workspace collects tax, then uses its app token to create a `Tax code` custom field on invoice lines, then returns to Campfire: ![FakeTax setup step 1, choosing states with nexus and a default tax code](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/onboarding-nexus.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=6b1a166d1b84bd3f49f589ec60a18ae8) ![FakeTax setup done, with a Return to Campfire button](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/onboarding-done.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=2146e9e8cfc5ad0110fa17d484163b54) ## Install config Your app often needs settings per workspace rather than per person. **Install config** stores a small set of strings on Campfire, one set per app per workspace. Read and write it with any of the workspace's OAuth tokens: ```bash theme={null} curl https://api.meetcampfire.com/ca/api/v1/oauth-app-install/config \ -H "Authorization: Bearer $ACCESS_TOKEN" ``` ```json theme={null} { "customer_id": 52, "customer_name": "Example Co", "user": {"id": 31017, "name": "Jordan Lee", "email": "jordan@example.com"}, "install_config": {"default_rate": "5.00", "auto_calculate": "false"} } ``` `PUT` the same path with `{"install_config": {...}}` to **replace** the whole object. Limits: up to 32 keys, lowercase identifiers, string values only, and 2,048 characters in total. This endpoint only accepts OAuth app tokens. > [!TIP] > > The `GET` response tells you which workspace and person a token belongs to, so it's also a handy "who am I" call right after the token exchange. Values fill `{{install.}}` placeholders in your URL templates. ## Event subscriptions Event subscriptions notify your server when records change in **every** workspace where your app is connected. Manage them on the **Events** tab. ![The Events tab with one subscription to Invoice and CreditMemo topics, with Send Test, Edit and Delete](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-events.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=44635ad59e881d7a16c792814593ae76) Each subscription has an endpoint URL (on an allowed domain; only `{{customer.*}}` and `{{install.*}}` placeholders) and a list of topics. An app can have up to 10 subscriptions. | Topics | Scope your app needs | | - | - | | `Invoice.created`, `.updated`, `.deleted`, `.paid`, `.payment` | `invoices:read` | | `Bill.created`, `.updated`, `.deleted`, `.paid`, `.payment` | `bills:read` | | `CreditMemo.*`, `CreditMemoLine.*` (`created`, `updated`, `deleted`) | `credit_memos:read` | | `DebitMemo.*`, `DebitMemoLine.*` (`created`, `updated`, `deleted`) | `debit_memos:read` | | `JournalEntry.created`, `.updated`, `.deleted` | `journal_entries:read` | | `Contract.created`, `.updated`, `.deleted` | `contracts:read` | Every topic must be covered by your app's permissions. In each workspace, an event is only sent if someone there has granted a scope that covers it. Events are **thin**: they say what changed, not the new values. Re-read the record through the API with that workspace's token: ```http theme={null} POST /events HTTP/1.1 Content-Type: application/json Campfire-App-Id: 0ca4c60f-db0a-4bc3-9efa-d2dec4292130 Campfire-Delivery-Kind: event Campfire-Webhook-Request-Timestamp: 1791990000 Campfire-Webhook-Signature-v1: 9a7f42... { "kind": "event", "topic": "Invoice.updated", "id": 18545770, "changed_fields": ["tax"], "customer": {"id": 52}, "occurred_at": "2026-10-14T18:26:06Z" } ``` `changed_fields` is empty for `.deleted` events. **Send Test** posts an example with `"test": true` and `"id": 0`. **Delivery.** Events are sent after the change is committed, with a 10-second timeout. Timeouts, connection failures, `429` and `5xx` responses are retried up to 5 times, with exponential backoff starting at 1 minute and capped at 1 hour. Other `4xx` responses are not retried. Respond `2xx` quickly and do slow work in the background. > [!WARNING] > > If your app writes to the record it was notified about, that write produces another `.updated` event. Use `changed_fields` (or remember what you just wrote) to avoid loops. ### App events vs. workspace webhooks | | App event subscriptions | [Workspace webhooks](/guides/webhooks) | | - | - | - | | Defined | Once, on the app | Per workspace | | Delivered for | Every connected workspace | The workspace that created it | | Payload | Thin: topic, id, changed fields | The full record, plus changes | | Signed with | The app's signing secret | That webhook's own token | | Ends when | The workspace's last connection is removed | The webhook is deleted | ## Security ### Verifying signatures Every webhook button call and event delivery has these headers: | Header | Value | | - | - | | `Campfire-App-Id` | Your app's id. | | `Campfire-Delivery-Kind` | `slot` (button) or `event`. | | `Campfire-Webhook-Request-Timestamp` | Unix seconds. | | `Campfire-Webhook-Signature-v1` | Hex HMAC-SHA256 of `"{timestamp}:{raw body}"`, keyed with the full signing secret (including `whsec_`). | | `Campfire-Webhook-Signature-v1-Previous` | The same, with the previous secret. Sent for 24 hours after a rotation. | Accept a request when either signature header matches, and reject timestamps more than 5 minutes off. Always compute the HMAC over the **raw** body bytes, before parsing the JSON. ```python Python theme={null} import hashlib, hmac, time def verify(headers, body: bytes, secrets: list[str]) -> bool: ts = headers.get("Campfire-Webhook-Request-Timestamp", "") if not ts.isdigit() or abs(time.time() - int(ts)) > 300: return False sent = [s for s in (headers.get("Campfire-Webhook-Signature-v1"), headers.get("Campfire-Webhook-Signature-v1-Previous")) if s] for secret in secrets: expected = hmac.new(secret.encode(), ts.encode() + b":" + body, hashlib.sha256).hexdigest() if any(hmac.compare_digest(expected, s) for s in sent): return True return False ``` ```javascript Node.js theme={null} import crypto from "node:crypto"; export function verify(headers, rawBody, secrets) { const ts = headers["campfire-webhook-request-timestamp"] ?? ""; if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; const sent = [headers["campfire-webhook-signature-v1"], headers["campfire-webhook-signature-v1-previous"]].filter(Boolean); return secrets.some((secret) => { const expected = crypto.createHmac("sha256", secret).update(`${ts}:`).update(rawBody).digest("hex"); return sent.some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))); }); } ``` ### Context tokens Whenever Campfire sends a person to your app, it includes a **context token**: as `cf_ctx` on the URL of link buttons, the manage link and every embedded page (iframe buttons, panels and navigation pages); as `context_token` in webhook bodies; and to embedded pages over the bridge again. It's an HS256 JWT signed with your [signing secret](#verifying-signatures), valid for **5 minutes**: ```json theme={null} { "iss": "campfire", "aud": "YOUR_CLIENT_ID", "jti": "6f0d8a8e-...", "iat": 1791990000, "exp": 1791990300, "customer_id": 52, "user_id": 31017, "slot_key": "view", "object_type": "invoice", "object_ids": ["18545770"], "surface": "detail_header" } ``` | Opened from | `surface` | `slot_key` | `object_type` / `object_ids` | | - | - | - | - | | A button | `detail_header`, `list_header`, or `row_menu` | The button's key | The record type and ids | | A panel | `panel:list`, `panel:detail`, or `panel:edit` | The panel's key | The record type; ids except on lists | | A navigation page | `nav` | The entry's key | `workspace`, `[]` | | The manage link | `manage` | `manage` | `workspace`, `[]` | To verify one: 1. Check the signature against your current and previous signing secrets. 2. Require `exp`, `iat`, `jti`, `aud`, and `iss`. Check that `aud` is your client ID and `iss` is `campfire`. 3. Check that the record you're about to show is in `object_ids`. 4. Record the `jti` and refuse it if you've seen it before. Campfire doesn't enforce single use for you. An embedded page gets the **same** token on its URL and over the bridge, so treat a repeat of a `jti` you opened a frame session for as that session, not a replay. ```python theme={null} import jwt claims = jwt.decode( token, signing_secret, algorithms=["HS256"], audience=CLIENT_ID, issuer="campfire", options={"require": ["exp", "iat", "jti", "aud", "iss"]}, ) ``` > [!WARNING] > > A context token proves **who** opened your page and **what** they were looking at. It is **not** an API token. Make API calls with the workspace's OAuth access token, which you store when someone connects your app. ### The bridge Pages embedded in drawers, modals, panels and navigation talk to Campfire with `window.postMessage`. Campfire only accepts messages from your frame's origin, and you should only accept messages from Campfire's origin (`https://app.meetcampfire.com`) sent by `window.parent`. Every message from your page has this shape: ```js theme={null} { source: "campfire-app-bridge", version: 1, type: "...", payload: { ... }, requestId: "..." } ``` | `type` | `payload` | What Campfire does | | - | - | - | | `ready` | none (send a `requestId`) | Replies with the context (below). | | `toast` | `{level, message}` | Shows a notification. | | `refresh` | none | Reloads the record or list behind your page. | | `resize` | `{height}` | Sets the frame's height (120 to 2,000 px). | | `close` | none | Closes the drawer or modal. Ignored in panels and pages. | | `open_url` | `{url}` | Opens a URL on your frame's origin in a new tab. | Campfire's reply to `ready`: ```js theme={null} { source: "campfire-host", version: 1, type: "context", requestId: "...", payload: { context_token: "eyJ...", object_type: "invoice", object_ids: ["18545770"], surface: "detail_header", theme: "light" } } ``` Send the `context_token` to your own server to verify it, then load your data. FakeTax's [`static/app-bridge.js`](https://github.com/Campfire-eng/campfire_faketax_app/blob/main/static/app-bridge.js) is a 70-line wrapper you can copy. It provides `ready()`, `toast()`, `refresh()`, `resize()`, `autoResize()`, `close()`, and `openUrl()`. > [!TIP] > > An embedded page usually makes several requests to your server, but the context token is single-use. FakeTax claims the token on the first request and opens a short-lived server-side session for the frame. Later requests use that session, named either by a [cookie](#embedded-pages-and-cookies) or by the token sent again over the bridge. ### Embedded pages and cookies Browsers keep third-party cookies out of iframes, so a page of yours framed inside `app.meetcampfire.com` can't see the cookies someone has from visiting your app directly, and a plain `Set-Cookie` from it is dropped. Campfire handles this the way Stripe's embedded Checkout does: a server-side call creates the session, and its id travels on the frame URL. 1. When a person opens a panel, a navigation page or an iframe button, Campfire's server checks that they may, renders your URL template and mints a context token. The browser never sees your signing secret or builds the URL itself. 2. Campfire frames `https://your-app.com/frame/...?cf_ctx=eyJ...`. That first document request is the one you can verify server-side, before any HTML is sent. 3. Verify the token as above, then answer with a **partitioned** cookie for your own session: ```http theme={null} HTTP/1.1 200 OK Set-Cookie: frame=...; Path=/; Max-Age=300; HttpOnly; Secure; SameSite=None; Partitioned ``` `Partitioned` ([CHIPS](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies)) gives "your app inside Campfire" a cookie jar of its own, keyed by the top-level site, so the browser keeps it and sends it with every later request the page makes. `SameSite=None` and `Secure` are required alongside it. 4. The page's own requests (fetches, form posts, links to other pages of yours) carry the cookie, so you don't need to thread the token through each one. The page still receives the same token over the bridge in reply to `ready`, so a page that prefers not to use cookies can keep sending `context_token` with each request, as FakeTax's pages do. Both name the same `jti`. ```python Python (Flask) theme={null} @app.get("/frame/breakdown/") def frame_breakdown(invoice_id): claims = verify_context_token(request.args.get("cf_ctx", "")) # signature, aud, iss, exp, jti if str(invoice_id) not in claims["object_ids"]: abort(403) response = make_response(render_template("breakdown.html")) response.set_cookie( "frame", sign(claims["jti"]), max_age=claims["exp"] - int(time.time()), httponly=True, secure=True, samesite="None", partitioned=True, ) return response ``` ```js Node (Express) theme={null} app.get("/frame/breakdown/:invoiceId", (req, res) => { const claims = verifyContextToken(req.query.cf_ctx); // signature, aud, iss, exp, jti if (!claims.object_ids.includes(req.params.invoiceId)) return res.sendStatus(403); res.cookie("frame", sign(claims.jti), { maxAge: (claims.exp - Math.floor(Date.now() / 1000)) * 1000, httpOnly: true, secure: true, sameSite: "none", partitioned: true, }); res.render("breakdown"); }); ``` > [!WARNING] > > The token is in the frame URL, so it reaches your access logs. Treat `cf_ctx` as you would any bearer value: don't log query strings on these routes, and keep your own cookie short-lived (the token expires after 5 minutes; the session behind your cookie needn't). ## What workspace admins control On the connection page (**Settings > Connections**, then your app), a workspace admin can switch off each button, panel, navigation entry and subscription, and change a button's style for their workspace. These settings survive changes to your app, because they're matched by key (and by endpoint URL for subscriptions). ![The connection page's Panels, Navigation and Subscriptions switches and the connection activity log](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/connection-page-settings.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=b0c0ecaabfc7e8b2e5d064e9d8ea04ca) ## Activity and testing The **Activity** tab on your app's page lists the latest 100 button clicks and event deliveries across every workspace, with status, HTTP code and response time. Use it to debug failures: ![The Activity tab listing recent calculate, view, breakdown and calculate-bulk button clicks with status, HTTP code and timing](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-activity.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=f375a8afd958c01e8773314a97fa6ce2) To test without real records, use **Send Test** on a subscription. > [!NOTE] > > Extensions are **not versioned**. Allowed domains, the signing secret, buttons, panels, navigation and event subscriptions take effect in every connected workspace as soon as you save. Only the app's details and permissions go through [versions](/guides/oauth-apps#versions-and-approval). Test changes in your own workspace with a separate development app before you change the one your customers use. ## Limits | Item | Limit | | - | - | | Buttons per app | 50 | | Panels per app | 20 | | Navigation entries per app | 30 (one level of nesting) | | Event subscriptions per app | 10 | | Allowed domains | 20 | | Webhook button timeout | 1,000 to 10,000 ms (default 8,000) | | Webhook response size | 64 KB | | Effects per response | 4 | | Rows per list-header click | 50 | | Clicks and panel opens | 30 per minute per person | | Context token lifetime | 5 minutes | | Install config | 32 keys, 2,048 characters, string values | # App manifest Source: https://docs.campfire.ai/guides/app-manifest Define your whole OAuth app, from details and permissions to buttons, panels, navigation and events, as one JSON document A **manifest** is your app's complete definition as one JSON document: its details and permissions, allowed domains, [buttons, panels, navigation, and event subscriptions](/guides/app-extensions). Keep it in your repository next to your code, review changes like any other change, and apply it to Campfire in one step. > **[FakeTax manifest.json](https://github.com/Campfire-eng/campfire_faketax_app/blob/main/manifest.json)** > > The sample app's manifest: five buttons, two panels, a sidebar section, and event subscriptions. > **[Extending Campfire](/guides/app-extensions)** > > What each extension does and how your server handles it. ## Applying a manifest ### Creating a new app On [Settings > Developer > Apps](https://app.meetcampfire.com/v2/settings/apps), click **From Manifest** (or **Create from Manifest** if you have no apps yet), paste your manifest, and click **Create App**. ![The Create app from manifest dialog with a JSON text area](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/from-manifest-dialog.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=eba37fdd4f8771efb3d0d703804eed9f) The `app` section becomes **version 1** in production straight away, and the extensions are created with it. Campfire then shows the client secret once, as when you [create an app by hand](/guides/oauth-apps#part-1-register-your-app). `app.allowed_scopes` is required when creating from a manifest. Use `[]` for an app with no permissions. ### Updating an existing app Open the app's **Manifest** tab. It shows the app's current manifest, which you can copy into your repository. Paste the new version and click **Save Manifest**. ![The Manifest tab showing FakeTax's manifest as JSON with a Save Manifest button](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-manifest.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=c16198e9eff3e9905cdb3a5747b8abcb) Saving is **all or nothing**. If any part is invalid, nothing changes and you get an error naming the part (see [Errors](#errors)). When it succeeds: * **The `app` section is versioned.** Fields that differ from the version you're editing go to the app's development version, which goes live only when you [promote it](/guides/oauth-apps#versions-and-approval). If nothing in `app` changed, no draft is opened. * **Everything else takes effect immediately**, in every workspace where your app is connected: allowed domains, buttons, panels, navigation, and event subscriptions. * **The manifest is the full list.** Buttons, panels, and navigation entries are matched by `key`, and subscriptions by `endpoint_url`. Anything that isn't in the manifest is **deleted**. * **Workspace settings survive.** Because items are matched by key, a workspace admin's switches and style choices stay in place when you re-apply. Changing a key creates a new item, which loses them. * **Allowed domains are applied first**, so one manifest can add a domain and the button that uses it. > [!WARNING] > > Leaving out `slots`, `panels`, `navigation`, or `event_subscriptions` is the same as sending an empty list: everything in that section is deleted. Leaving out `app` or `allowed_domains` leaves them unchanged. ### Over the API The same operations are available to a workspace admin's session at `https://api.meetcampfire.com`: | Method and path | Does | | - | - | | `GET /ca/api/v1/oauth-apps//manifest` | Export the manifest. The `app` section shows the development version if there is one. | | `PUT /ca/api/v1/oauth-apps//manifest` | Apply a manifest. Returns the manifest as saved. | | `POST /ca/api/v1/oauth-apps/from-manifest` | Create an app. Returns the app, its `client_secret` (shown once), and its `manifest`. | | `GET /ca/api/v1/oauth-apps/extension-catalog` | Object types, the fields each can test in `visible_when`, and the event topics. | > [!NOTE] > > App management endpoints are never available to OAuth app tokens. ## Reference A manifest is a JSON object with up to six sections: ```json theme={null} { "app": { }, "allowed_domains": [], "slots": [], "panels": [], "navigation": [], "event_subscriptions": [] } ``` ### `app` The app's versioned details. Only these keys are allowed: | Key | Type | Notes | | - | - | - | | `name` | string | Required. | | `tagline` | string | Up to 120 characters. | | `category` | string | Where the app is listed on the Connections page: `ap`, `ar`, `banking`, `crm`, `data_upload`, `payroll`, `tax`, or `""` for the generic **Apps** section. | | `description` | string | Up to 2,000 characters. | | `icon_url` | string or `null` | Must be an icon already uploaded to Campfire. Upload one on the **Details** tab, then export to get its URL. | | `redirect_uris` | string\[] | Up to 20. See [redirect URL rules](/guides/oauth-apps#part-1-register-your-app). | | `connect_url` | string | Where **Connect** on the connection page sends people. | | `manage_url` | string | Where **Manage in \** sends people. See [Manage URL](/guides/app-extensions#manage-url). | | `allowed_scopes` | string\[] | The app's permission ceiling, using [scope names](/guides/oauth-apps#scopes-reference) such as `invoices:write`. Add `openid`, `email` and `profile` for [Sign in with Campfire](/guides/oauth-apps#sign-in-with-campfire-openid-connect). | ### `allowed_domains` Up to 20 host names. `example.com` matches only that host. `*.example.com` matches its subdomains, but not `example.com`. Every URL in the sections below must be on one of these hosts. ### `slots` (buttons) | Key | Type | Notes | | - | - | - | | `key` | string | Unique within the app. Up to 64 characters, slug format. | | `label` | string | Up to 60 characters. | | `icon` | string | A [Lucide](https://lucide.dev/icons) icon name, for example `calculator`. | | `object_type` | string | `invoice`, `bill`, `journal_entry`, or `vendor`. | | `surface` | string | `detail_header`, `list_header`, or `row_menu`. | | `requested_variant` | string | `menu` (default), `secondary`, or `primary`. | | `action_type` | string | `link`, `webhook`, or `iframe`. | | `action_config` | object | Depends on `action_type`. See below. | | `visible_when` | object\[] | Up to 5 rules: `{"field", "op", "value"}`, with `op` one of `eq`, `neq`, `in`, `not_in`. | | `confirm_text` | string | Up to 200 characters. Empty for no confirmation. | | `order` | integer | Sort order within the same placement. | | `is_active` | boolean | `false` hides the button everywhere. Must be a real boolean. | `action_config` by action type: | `action_type` | `action_config` | | - | - | | `link` | `{"url_template"}` | | `webhook` | `{"url_template", "timeout_ms"}`. `timeout_ms` is 1000 to 10000 (default 8000). | | `iframe` | `{"url_template", "presentation", "width"}`. `presentation` is `drawer` (default) or `modal`. `width` is `sm`, `md` (default), or `lg`. | URL templates can be up to 1,024 characters and use `{{record.id}}`, `{{record.number}}`, `{{customer.id}}`, and `{{install.}}`. `{{record.*}}` isn't allowed on `list_header`. ### `panels` | Key | Type | Notes | | - | - | - | | `key` | string | Unique within the app. | | `label` | string | The tab title. Up to 60 characters. | | `icon` | string | Lucide icon name. | | `object_type` | string | `invoice`, `bill`, `journal_entry`, or `vendor`. | | `placements` | string\[] | One or more of `list`, `detail`, `edit`. | | `url_template` | string | `{{record.*}}` isn't allowed when `list` is a placement. | | `visible_when` | object\[] | As for buttons. | | `order` | integer | Sort order. | | `is_active` | boolean | | ### `navigation` A list of top-level entries. Each entry can hold one level of `items`: | Key | Type | Notes | | - | - | - | | `key` | string | Unique across all entries and items. | | `label` | string | Up to 40 characters. | | `icon` | string | Lucide icon name. | | `url_template` | string | Empty for a section that only groups items. Required on items. Only `{{customer.*}}` and `{{install.*}}`. | | `order` | integer | Optional. Defaults to the entry's position in the list. | | `is_active` | boolean | | | `items` | object\[] | Top-level entries only. Items have the same keys, without `items`. | At most 30 entries in total, counting items. ### `event_subscriptions` | Key | Type | Notes | | - | - | - | | `endpoint_url` | string | Where events are posted. Only `{{customer.*}}` and `{{install.*}}`. Identifies the subscription when you re-apply. | | `topics` | string\[] | Non-empty. Each must be covered by `app.allowed_scopes`. See [topics](/guides/app-extensions#event-subscriptions). | | `is_active` | boolean | | ## Errors Saving an invalid manifest returns `400` with a `detail` that says where the problem is: | Example `detail` | Fix | | - | - | | `app: not part of the manifest: client_id` | Remove keys that aren't listed under [`app`](#app). | | `slots[2]: visible_when: payment_status cannot be tested on vendor; use country, is_1099, vendor_type` | Use a field from the [visibility table](/guides/app-extensions#visibility-rules). | | `Slot keys must be unique.` | Give every button its own `key`. Panels and navigation work the same way. | | `Too many slots, panels, navigation entries or subscriptions.` | Stay within the [limits](/guides/app-extensions#limits). | | `slots, panels, navigation and event_subscriptions must be lists.` | Use `[]`, not `{}` or `null`. | | `allowed_domains: ...` | Fix the host name. | A URL that isn't on an allowed domain, a topic your scopes don't cover, or a `{{record.*}}` placeholder where it isn't allowed is reported against the item it's in. ## Example: FakeTax This is FakeTax's complete [`manifest.json`](https://github.com/Campfire-eng/campfire_faketax_app/blob/main/manifest.json). It runs on `localhost`, so every URL uses `http://localhost:3999`. In production, use your own `https` host. > **manifest.json** > > ```json manifest.json theme={null} > { > "app": { > "name": "FakeTax", > "tagline": "Made-up sales tax on invoices", > "category": "tax", > "description": "Sales tax for invoices and credit memos by jurisdiction, with tax codes on lines. The tax is fake; the plumbing is real.", > "icon_url": null, > "redirect_uris": [ > "http://localhost:3999/callback" > ], > "connect_url": "http://localhost:3999/connect", > "allowed_scopes": [ > "invoices:read", > "invoices:write", > "credit_memos:write", > "custom_fields:write", > "vendors:read" > ], > "manage_url": "http://localhost:3999/manage" > }, > "allowed_domains": [ > "localhost" > ], > "slots": [ > { > "key": "view", > "label": "View in FakeTax", > "icon": "external-link", > "object_type": "invoice", > "surface": "detail_header", > "requested_variant": "menu", > "action_type": "link", > "action_config": { > "url_template": "http://localhost:3999/report/{{record.id}}" > }, > "visible_when": [], > "confirm_text": "", > "order": 2, > "is_active": true > }, > { > "key": "calculate", > "label": "Calculate tax", > "icon": "calculator", > "object_type": "invoice", > "surface": "detail_header", > "requested_variant": "secondary", > "action_type": "webhook", > "action_config": { > "url_template": "http://localhost:3999/slots/calculate", > "timeout_ms": 8000 > }, > "visible_when": [ > { > "field": "payment_status", > "op": "in", > "value": [ > "draft", > "open" > ] > } > ], > "confirm_text": "Overwrite tax on every line?", > "order": 0, > "is_active": true > }, > { > "key": "calculate-bulk", > "label": "Calculate FakeTax", > "icon": "calculator", > "object_type": "invoice", > "surface": "list_header", > "requested_variant": "menu", > "action_type": "webhook", > "action_config": { > "url_template": "http://localhost:3999/slots/calculate", > "timeout_ms": 8000 > }, > "visible_when": [], > "confirm_text": "", > "order": 0, > "is_active": true > }, > { > "key": "open-row", > "label": "FakeTax report", > "icon": "external-link", > "object_type": "invoice", > "surface": "row_menu", > "requested_variant": "menu", > "action_type": "link", > "action_config": { > "url_template": "http://localhost:3999/report/{{record.id}}" > }, > "visible_when": [], > "confirm_text": "", > "order": 0, > "is_active": true > }, > { > "key": "breakdown", > "label": "Tax breakdown", > "icon": "table", > "object_type": "invoice", > "surface": "detail_header", > "requested_variant": "menu", > "action_type": "iframe", > "action_config": { > "url_template": "http://localhost:3999/frame/breakdown/{{record.id}}", > "presentation": "drawer", > "width": "lg" > }, > "visible_when": [], > "confirm_text": "", > "order": 1, > "is_active": true > } > ], > "panels": [ > { > "key": "breakdown-tab", > "label": "FakeTax", > "icon": "table", > "object_type": "invoice", > "placements": [ > "detail", > "edit" > ], > "url_template": "http://localhost:3999/frame/breakdown/{{record.id}}", > "visible_when": [], > "order": 0, > "is_active": true > }, > { > "key": "settings", > "label": "FakeTax", > "icon": "settings", > "object_type": "invoice", > "placements": [ > "list" > ], > "url_template": "http://localhost:3999/frame/settings", > "visible_when": [], > "order": 0, > "is_active": true > } > ], > "navigation": [ > { > "key": "faketax", > "label": "FakeTax", > "icon": "calculator", > "url_template": "", > "is_active": true, > "items": [ > { > "key": "jurisdictions", > "label": "Jurisdictions", > "icon": "map-pin", > "url_template": "http://localhost:3999/frame/manage", > "is_active": true > }, > { > "key": "tax-codes", > "label": "Tax codes", > "icon": "tag", > "url_template": "http://localhost:3999/frame/codes", > "is_active": true > }, > { > "key": "settings", > "label": "Settings", > "icon": "settings", > "url_template": "http://localhost:3999/frame/settings", > "is_active": true > } > ] > } > ], > "event_subscriptions": [ > { > "topics": [ > "Invoice.created", > "Invoice.updated", > "Invoice.deleted", > "CreditMemo.created", > "CreditMemo.updated" > ], > "endpoint_url": "http://localhost:3999/events", > "is_active": true > } > ] > } > ``` It defines: * **Five buttons** on invoices: **Calculate tax** (a secondary webhook button on draft and open invoices, with a confirmation), **Calculate FakeTax** (the same webhook for selected rows on the list), **Tax breakdown** (a large drawer), **View in FakeTax** (a link), and **FakeTax report** (a link in the row menu). * **Two panels**: the breakdown on the invoice page and edit modal, and settings on the invoice list. * **A sidebar section** with three pages. * **One subscription** for invoice and credit memo changes. # Creating Journal Entries Source: https://docs.campfire.ai/guides/journal-entries How to create single, and intercompany journal entries in Campfire > [!NOTE] > > All requests in this flow assume you have a valid access token attached in your request headers. See our [authentication guide](/quickstart) for more information. ## Creating a Journal Entry This section will guide you through the process of creating a single entity journal entry in Campfire. **1. Fetch related data** We'll need to grab some object references for related objects to create our journal. We'll need to pass in the id's of the related objects where applicable in the journal creation request. Linked here are the filter endpoints for the applicable objects. These include: * [Accounts (Required)](/api-reference/company-objects/list-chart-accounts) * [Entities (Required)](/api-reference/settings/list-chart-entities) * [Vendors (Optional)](/api-reference/company-objects/list-vendors) * [Departments (Optional)](/api-reference/company-objects/list-departments) * [Custom Dimension Fields (Optional)](/api-reference/company-objects/list-custom-dimensions) **2. Assemble the request** We can now create our request body by filling in the related fields. Here are the required fields: | Field | Description | Example | | - | - | - | | `date` | Journal entry date in YYYY-MM-DD format | `"2025-08-01"` | | `type` | Journal entry type | `"journal_entry"` | | `transactions` | Array of transaction items for the journal | See transaction fields below | | `memo` | Journal entry memo | `"Journal Memo"` | | `reversal_date` | Reversal date in YYYY-MM-DD format, will post a reversing journal if provided (optional) | `"2025-08-02"` | | `entity` | ID from entity | `"54"` | | `currency` | ISO Currency code of the journal | `"USD"` | | `exchange_rate_book` | Exchange rate between transactional and entity currency (auto-computed if not provided) | `1.23` | | `exchange_rate` | Exchange rate between entity and consolidation currency (auto-computed if not provided) | `1.23` | **Transaction Fields:** | Field | Description | Example | | - | - | - | | `tags` | Array of custom dimension field IDs (optional) | `[{"id": "7737"}]` | | `account` | ID from accounts | `"180564"` | | `debit_amount_native` | Debit amount in native currency (required) | `1000` | | `debit_amount_book` | Debit amount in book currency (optional: auto-computed if not provided) | `1000` | | `debit_amount` | Debit amount in consolidation currency (optional: auto-computed if not provided) | `1000` | | `credit_amount_native` | Credit amount in native currency (required) | `1000` | | `credit_amount_book` | Credit amount in book currency (optional: auto-computed if not provided) | `1000` | | `credit_amount` | Credit amount in consolidation currency (optional: auto-computed if not provided) | `1000` | | `bank_description` | Transaction description | `"Line 1 Desc"` | | `vendor` | ID from vendor (optional) | `"34182"` | | `department` | ID from department (optional) | `"3613"` | > [!NOTE] > > Each transaction can only have either it's debit (debit\_amount\_native, debit\_amount\_book, debit\_amount) or credit (credit\_amount\_native, credit\_amount\_book, credit\_amount) amount set. But not both. Example request body: ```json theme={null} { "date": "2025-08-01", "type": "journal_entry", "transactions": [ { "tags": [ { "id": "7737" } ], "account": "180564", "debit_amount_native": 1000, "debit_amount_book": 1000, "debit_amount": 1000, "bank_description": "Line 1 Desc", "vendor": "34182", "department": "3613" }, { "tags": [ { "id": "8330" } ], "account": "8856", "credit_amount_native": 1000, "credit_amount_book": 1000, "credit_amount": 1000, "bank_description": "Line 2 Desc", "vendor": "111883", "department": "3436" } ], "memo": "Journal Memo", "reversal_date": "2025-08-02", "entity": "54", "currency": "USD", "exchange_rate_book": 1, "exchange_rate": 1 } ``` **3. Post the journal entry** Now that we have the request we can post it via the [Create Journal Entry](/api-reference/core-accounting/create-journal-entry) endpoint. Congrats! You've created your first journal entry! ## Creating an Intercompany Journal Entry This section will guide you through the process of creating an intercompany journal entry in Campfire. It is largely the same as a regular journal, with a few distinct differences. **1. Fetch related data** We'll need to grab some object references for related objects to create our journal. We'll need to pass in the id's of the related objects where applicable in the journal creation request. Linked here are the filter endpoints for the applicable objects. These include: * [Accounts (Required)](/api-reference/company-objects/list-chart-accounts) * [Entities (Required)](/api-reference/settings/list-chart-entities) * [Vendors (Optional)](/api-reference/company-objects/list-vendors) * [Departments (Optional)](/api-reference/company-objects/list-departments) * [Custom Dimension Fields (Optional)](/api-reference/company-objects/list-custom-dimensions) **2. Assemble the request** We can now create our intercompany request body by filling in the related fields. Here are the required fields: > [!WARNING] > > For intercompany journals, you must specify an `entity` for each transaction AND include an `entities` section with exchange rates for each entity involved. | Field | Description | Example | | - | - | - | | `date` | Journal entry date in YYYY-MM-DD format | `"2025-07-01"` | | `type` | Journal entry type | `"journal_entry"` | | `transactions` | Array of transaction items for the journal | See transaction fields below | | `memo` | Journal entry memo | `"Interco Journal Desc"` | | `currency` | ISO Currency code of the journal | `"USD"` | | `reversal_date` | Reversal date in YYYY-MM-DD format (optional) | `"2025-07-02"` | | `entities` | **Required for intercompany**: Object with exchange rates for each entity | See entities section below | **Transaction Fields:** | Field | Description | Example | | - | - | - | | `entity` | **Required for intercompany**: ID from entity for this transaction | `54` | | `tags` | Array of custom dimension field IDs (optional) | `[{"id": "8330"}]` | | `account` | ID from accounts | `"180564"` | | `debit_amount_native` | Debit amount in native currency (required) | `1000` | | `debit_amount_book` | Debit amount in book currency (optional: auto-computed if not provided) | `1000` | | `debit_amount` | Debit amount in consolidation currency (optional: auto-computed if not provided) | `1000` | | `credit_amount_native` | Credit amount in native currency (required) | `1000` | | `credit_amount_book` | Credit amount in book currency (optional: auto-computed if not provided) | `728.33` | | `credit_amount` | Credit amount in consolidation currency (optional: auto-computed if not provided) | `1000` | | `bank_description` | Transaction description | `"Line 1 Desc"` | | `vendor` | ID from vendor (optional) | `"111883"` | | `department` | ID from department (optional) | `"3046"` | **Entities Section:** | Field | Description | Example | | - | - | - | | `id` | Entity ID | `5` | | `exchange_rate` | Exchange rate between entity and consolidation currency | `1.373` | | `exchange_rate_book` | Exchange rate between transactional and entity currency | `0.728332` | > [!NOTE] > > Each transaction can only have either its debit (debit\_amount\_native, debit\_amount\_book, debit\_amount) or credit (credit\_amount\_native, credit\_amount\_book, credit\_amount) amount set. But not both. Example request body: ```json theme={null} { "date": "2025-07-01", "type": "journal_entry", "transactions": [ { "tags": [ { "id": "8330" } ], "entity": 54, "account": "180564", "debit_amount_native": 1000, "debit_amount_book": 1000, "debit_amount": 1000, "bank_description": "Line 1 Desc", "vendor": "111883", "department": "3046" }, { "tags": [ { "id": "8211" } ], "entity": 5, "account": "7409", "credit_amount_native": 1000, "credit_amount_book": 728.33, "credit_amount": 1000, "bank_description": "Line 2 Desc", "vendor": "22327", "department": "3436" }, { "entity": 5, "tags": [], "debit_amount_native": 1000, "debit_amount_book": 728.33, "debit_amount": 1000, "account": "7405", "bank_description": "Line 3 Desc" }, { "entity": 54, "tags": [], "credit_amount_native": 1000, "credit_amount_book": 1000, "credit_amount": 1000, "account": "8856", "bank_description": "Line 4 Desc" } ], "memo": "Interco Journal Desc", "currency": "USD", "reversal_date": "2025-07-02", "entities": { "5": { "id": 5, "exchange_rate": 1.373, "exchange_rate_book": 0.728332 }, "54": { "id": 54, "exchange_rate": 1, "exchange_rate_book": 1 } } } ``` **3. Post the intercompany journal entry** Now that we have the request we can post it via the [Create Intercompany Journal Entry](/api-reference/core-accounting/create-intercompany-journal-entry) endpoint. Congrats! You've created your first intercompany journal entry! # OAuth Apps Source: https://docs.campfire.ai/guides/oauth-apps Let people connect your software to Campfire with OAuth 2.0 instead of sharing API keys OAuth apps let your own software, or a third-party tool, act in Campfire **on behalf of a real person** without anyone sharing a password or an API key. Each person who connects your app sees exactly what it is asking for, picks the workspace it acts in, and can disconnect it at any time. Every request the app makes shows up in a per-connection activity log. Campfire implements the standard OAuth 2.0 **authorization code** flow with refresh tokens and optional PKCE, so any OAuth 2.0 client library will work. It is also an [OpenID Connect](#sign-in-with-campfire-openid-connect) provider, so you can use it for "Sign in with Campfire". > **[API keys](/quickstart)** > > A single key for a dedicated API user in your own workspace. Best for internal scripts and back-office jobs. > **OAuth apps** > > Each person authorizes your app themselves, with scoped, revocable, audited access. Best for integrations that other people connect to. Once connected, an app can also add its own [buttons, panels, sidebar pages and event subscriptions](/guides/app-extensions) to Campfire. You can define the whole app in a [manifest](/guides/app-manifest) that you keep in your repository. > **[Sample app: FakeTax](https://github.com/Campfire-eng/campfire_faketax_app)** > > An open-source Flask app that implements the full OAuth flow with Sign in with Campfire (OpenID Connect), onboarding, buttons, panels, navigation and events. Clone it to see a working integration end to end. ## How it works **1. An admin registers the app** A workspace admin creates the app in Campfire, picks the most it may ever access (its **scopes**), and gets a **client ID** and **client secret**. **2. A person authorizes it** Your app sends the person to Campfire's authorize URL. They sign in, review what the app is asking for, choose a workspace, and click **Authorize**. **3. Your app exchanges the code for tokens** Campfire redirects back to your app with a one-time `code`. Your server exchanges it, along with the client secret, for an **access token** (valid for 1 hour) and a **refresh token** (valid for 30 days). **4. Your app calls the API** Your app sends `Authorization: Bearer ` on API requests. Campfire treats each request as that person in the chosen workspace, limited to the scopes they granted. > [!NOTE] > > Creating and managing OAuth apps requires a Campfire **admin**. Anyone in a workspace can **authorize** an app, but the app can never do more than that person is already allowed to do. ## Part 1: Register your app **1. Open the Apps page** Go to [Settings > Developer > Apps](https://app.meetcampfire.com/v2/settings/apps). If you haven't created an app yet, you'll see the empty state. Click **Create App**. Once you have at least one app, the button is **New App** in the top right. If you already have a [manifest](/guides/app-manifest), click **Create from Manifest** (**From Manifest** once you have apps) and paste it instead. That sets up the details, permissions and extensions in one step. ![The Apps on Campfire page with no apps and a Create App button](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/apps-empty.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=480846d8eaf110f47bf0cb6f7ce02e6b) > [!NOTE] > > If you don't see **Apps** under **Developer**, contact your Campfire support team to have OAuth apps turned on for your workspace. **2. Fill in the app details** The **Details** tab describes your app to the people who will authorize it. ![The Details tab of the Create app dialog](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/create-app-details.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=5920a31993b3d2551b1910f481db3034) | Field | Required | What it's for | | - | - | - | | **Name** | Yes | Shown on the consent screen, the Connections page, and the activity log. | | **Tagline** | No | One line (up to 120 characters) shown under the name on the app card and the consent screen. | | **Category** | No | Where the app is listed on the Connections page: Accounts Payable, Accounts Receivable, Banking, CRM, Data, Payroll, or Tax. Leave it as **Other** to list the app under **Apps**. | | **Description** | No | Up to 2,000 characters that help your colleagues recognize what the app does. Shown on the connection's detail page. | | **List of allowed redirection URLs** | To authorize | Where Campfire sends people back after they approve or deny access. Add up to 20 with **Add new URL**. People can't authorize the app until at least one is added. | | **Connect URL** | No | Where the **Connect** button on Campfire's Connections page sends people. See [Starting from Campfire](#starting-the-flow-from-campfire). | | **Manage URL** | No | Where the **Manage in \** button on the connection page sends people, with a signed context token. See [Manage URL](/guides/app-extensions#manage-url). | | **App icon** | No | PNG, JPG, GIF, or WEBP, up to 1 MB. Shown on the consent screen and the Connections page. | | **Published** | No | Off by default. See [Private vs. published apps](#private-vs-published-apps). | ![The rest of the Details tab, showing the Connect URL, App icon, and Published toggle](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/create-app-details-bottom.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=3ae117d0736da93ff383c1b1fd2c5da1) > [!WARNING] > > Redirect URLs, the Connect URL, and the Manage URL must use `https`. Plain `http` is accepted only for `localhost`, `127.0.0.1`, and `[::1]`, so you can develop locally. URLs can't contain a `#fragment` or embedded credentials. At authorization time the `redirect_uri` must **exactly** match one of the registered URLs, except that loopback addresses (`127.0.0.1`, `[::1]`) may use any port. **3. Choose the app's permissions** Switch to the **Permissions** tab and check the access your app needs. These scopes are the **ceiling**: the most the app can ever request. People connecting the app are still limited to their own permissions in the workspace they choose. ![The Permissions tab with Read, Draft, Write, and Approve columns for each Accounting resource](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/create-app-permissions.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=23d312b3d6784bfc4073b2a704d87f7f) Permissions are grouped by module (Accounting, Revenue, Reports, Cash Management, Close Management, Organization, Ember AI). Each row is a resource, and each column is an access tier: | Tier | Grants | | - | - | | **Read** | View the resource. | | **Draft** | Propose changes that go through Campfire's approval workflow. The app's writes are saved as drafts for someone to approve. | | **Write** | Create, edit, and delete the resource. | | **Approve** | Approve proposed changes to the resource. This is separate from the other tiers and only granted on its own. | A higher tier includes the lower ones. For example, checking **Write** on Invoice Payments also checks **Read** and **Draft**. Only check what your integration actually uses. You can widen the scopes later, through a [new version](#versions-and-approval), without affecting existing connections. > [!TIP] > > You can create an app with **no** permissions. It can then only confirm who signed in and which workspace they chose. For "Sign in with Campfire", also add the `openid`, `email`, and `profile` scopes; see [OpenID Connect](#sign-in-with-campfire-openid-connect). **4. Save and copy your credentials** Click **Create App**. Campfire shows the app's credentials: ![The App credentials dialog showing Client ID, Client Secret, Auth URL, Access Token URL, and Refresh Token URL](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/app-credentials.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=ab3f4cc5ac2247dd9ed4cec7fed7161e) | Credential | Use | | - | - | | **Client ID** | Public identifier for your app. Safe to include in URLs. | | **Client Secret** | Proves your server is the app. Keep it in a secret store and never ship it to a browser or mobile app. | | **Auth URL** | A ready-made authorize URL for your first redirect URL. Add `state`, `scope`, and PKCE parameters as shown below. | | **Access Token URL** / **Refresh Token URL** | `https://api.meetcampfire.com/ca/oauth/token`. The same endpoint handles both grants. | > [!WARNING] > > **The client secret is shown only once.** Copy it before you click **Done**. If you lose it, rotate it to get a new one (see [Rotating the client secret](#rotating-the-client-secret)). Your app now appears on the Apps page with its scope count and its production version. Click **Manage** to open it. ![The Apps page listing FakeTax with 4 scopes and a v1 Production badge, and a Manage button](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/apps-list.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=3636184b35caa0f88ead4e0f2fd6d784) ## Part 2: Implement the authorization flow The examples below use these endpoints: | Purpose | Method and URL | | - | - | | Authorize | `GET https://api.meetcampfire.com/ca/oauth/authorize` | | Exchange a code or refresh a token | `POST https://api.meetcampfire.com/ca/oauth/token` | | Call the API | Any supported endpoint on `https://api.meetcampfire.com`, with `Authorization: Bearer ` | ### Step 1: Send the person to Campfire Generate a random `state` value and a PKCE verifier, store both in the person's session, then redirect them to the authorize endpoint: ```text theme={null} https://api.meetcampfire.com/ca/oauth/authorize ?client_id=YOUR_CLIENT_ID &redirect_uri=https%3A%2F%2Fyour-app.com%2Foauth%2Fcallback &response_type=code &scope=invoices%3Aread%20invoice_payments%3Awrite%20vendors%3Aread &state=RANDOM_STATE &code_challenge=BASE64URL_SHA256_OF_VERIFIER &code_challenge_method=S256 ``` | Parameter | Required | Notes | | - | - | - | | `client_id` | Yes | From the credentials dialog. | | `redirect_uri` | Yes | Must exactly match a registered redirect URL. | | `response_type` | Yes | Always `code`. | | `state` | Strongly recommended | An unguessable value (up to 4,096 characters) that you check on the way back to prevent CSRF. | | `scope` | No | Space-separated scopes. Must be within the app's permissions. If omitted, Campfire requests all of the app's permissions. | | `code_challenge` | Recommended | Base64url-encoded SHA-256 of your `code_verifier`, without padding (43 characters). | | `code_challenge_method` | With `code_challenge` | Must be `S256`. `plain` is not supported. | | `nonce` | With `openid` | An unguessable value that Campfire copies into the ID token. See [OpenID Connect](#sign-in-with-campfire-openid-connect). | > [!TIP] > > PKCE is optional for apps that authenticate with a client secret, but we recommend always using it. If you send a `code_challenge`, you must send the matching `code_verifier` when you exchange the code. Here is how to generate the PKCE pair: ```python Python theme={null} import base64, hashlib, secrets code_verifier = secrets.token_urlsafe(48) # 43-128 characters code_challenge = base64.urlsafe_b64encode( hashlib.sha256(code_verifier.encode()).digest() ).rstrip(b"=").decode() state = secrets.token_urlsafe(24) ``` ```javascript Node.js theme={null} import crypto from "node:crypto"; const codeVerifier = crypto.randomBytes(48).toString("base64url"); // 43-128 characters const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest("base64url"); const state = crypto.randomBytes(24).toString("base64url"); ``` ### Step 2: The person approves access If the person isn't signed in, Campfire asks them to sign in first. They then see the consent screen, which shows your app's icon, name, tagline, and a plain-language list of what it will be able to do: ![The Authorize Acme Collections consent screen listing the requested permissions and the workspace](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/consent-screen.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=3fbaec8a208ee4810afedeab3fa983b6) * **Workspace.** For a private app, the workspace is fixed to the one that created the app. For a published and approved app, the person picks one of the workspaces they belong to. * **Authorize** redirects to your `redirect_uri` with `code` and `state`: ```text theme={null} https://your-app.com/oauth/callback?code=I9feIWu7cmfy...&state=RANDOM_STATE ``` * **Cancel** redirects to your `redirect_uri` with an error: ```text theme={null} https://your-app.com/oauth/callback?error=access_denied&error_description=The+user+declined+to+authorize+the+app.&state=RANDOM_STATE ``` Before doing anything else in your callback, **check that `state` matches the value you stored.** If it doesn't, discard the code. ### Step 3: Exchange the code for tokens From your server, `POST` the code to the token endpoint within **5 minutes**. Each code can be used only once. Authenticate with your client ID and secret, either with HTTP Basic auth (shown) or as `client_id` and `client_secret` form fields: ```bash theme={null} curl -X POST https://api.meetcampfire.com/ca/oauth/token \ -u "$CAMPFIRE_CLIENT_ID:$CAMPFIRE_CLIENT_SECRET" \ -d grant_type=authorization_code \ -d code="$CODE" \ -d redirect_uri="https://your-app.com/oauth/callback" \ -d code_verifier="$CODE_VERIFIER" ``` ```json theme={null} { "access_token": "cfa_YOUR_ACCESS_TOKEN", "token_type": "Bearer", "expires_in": 3600, "scope": "invoice_payments:write invoices:read vendors:read", "refresh_token": "cfr_YOUR_REFRESH_TOKEN" } ``` Access tokens start with `cfa_` and refresh tokens start with `cfr_`. Store both securely on your server, keyed to the person who connected. The `scope` field lists exactly what was granted. If the person granted `openid`, the response also contains an `id_token`. ### Step 4: Call the API Send the access token as a bearer token: ```bash theme={null} curl https://api.meetcampfire.com/coa/api/v1/invoice/ \ -H "Authorization: Bearer $ACCESS_TOKEN" ``` To find out who connected and which workspace they chose, call the permissions endpoint. This works for every app, including apps with no scopes: ```bash theme={null} curl https://api.meetcampfire.com/users/api/get-user-permissions \ -H "Authorization: Bearer $ACCESS_TOKEN" ``` ```json theme={null} { "id": 45460, "name": "Jordan Lee", "email": "jordan@example.com", "approval_required": false, "can_edit": false, "tenant": { "id": 53, "name": "Example Co", "type": "PRODUCTION", "logo_url": null }, "app": { "client_id": "fg2-mFFHRkQmqiVvXMXdbEBfDfZp4Evh", "scopes": ["invoice_payments:write", "invoices:read", "vendors:read"] }, "permissions": { "chart_of_accounts.accountinginvoice": "read", "chart_of_accounts.accountingbill": "none" } } ``` The `permissions` map is the effective access for this token: the person's own permissions intersected with the granted scopes. The response above is shortened. **What a request can do.** Each request runs as the person who authorized the app, in the workspace they chose. It can do only what **both** that person's role and the granted scopes allow. An app never inherits admin privileges, even when an admin authorizes it. **When a scope is missing,** Campfire returns `403` and tells you which scope you need in the `WWW-Authenticate` header: ```http theme={null} HTTP/1.1 403 Forbidden WWW-Authenticate: Bearer realm="api", error="insufficient_scope", scope="bills:read" {"detail": "You do not have permission to perform this action."} ``` > [!NOTE] > > Some endpoints are not available to OAuth apps and return `403` with `"This endpoint is not available to OAuth apps."` Account and credential management (API keys, OAuth app management, connections) is never available to app tokens. **Rate limits.** Each connection can make up to **10 requests per second**. The limit is counted per connection, so one busy connection does not slow down your app's other connections, and it does not count against the person's own use of Campfire. Requests over the limit return `429 Too Many Requests` with a `Retry-After` header giving the number of seconds to wait. ### Step 5: Refresh the access token Access tokens expire after **1 hour**. Use the refresh token to get a new pair: ```bash theme={null} curl -X POST https://api.meetcampfire.com/ca/oauth/token \ -u "$CAMPFIRE_CLIENT_ID:$CAMPFIRE_CLIENT_SECRET" \ -d grant_type=refresh_token \ -d refresh_token="$REFRESH_TOKEN" ``` The response has the same shape as the code exchange and contains a **new** refresh token. > [!WARNING] > > **Refresh tokens rotate and can be used only once.** Each refresh revokes the old pair, so save the new refresh token before you use the new access token. If an old refresh token is ever reused, Campfire assumes it was stolen and revokes **every** token for that connection: > > ```json theme={null} > {"error": "invalid_grant", "error_description": "Refresh token was already used; re-authorize the app."} > ``` > > The person must then authorize the app again. If several workers share a connection, make sure only one of them refreshes at a time. Refresh tokens expire after **30 days**. Refreshing regularly keeps a connection alive indefinitely, but if a connection goes unused for longer than that, the person needs to reconnect. ### Starting the flow from Campfire If you set a **Connect URL**, people can also start from Campfire. Clicking **Connect** on your app's page under **Settings > Connections** sends them to your Connect URL. Campfire doesn't start the OAuth flow itself, because your app has to own the `state` and PKCE values. Your Connect URL should do exactly what Step 1 does: generate `state` and a verifier, store them, and redirect to the authorize URL. Campfire adds a `return_to` parameter with the page the person came from. After the callback, and any setup of your own, you can send them back there. Only redirect if `return_to` starts with Campfire's own origin. See [Onboarding after connect](/guides/app-extensions#onboarding-after-connect). ```python theme={null} @app.get("/campfire/connect") def connect(): verifier, challenge = pkce_pair() state = secrets.token_urlsafe(24) session["oauth"] = {"state": state, "verifier": verifier} return redirect(AUTHORIZE_URL + "?" + urlencode({ "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "response_type": "code", "state": state, "code_challenge": challenge, "code_challenge_method": "S256", })) ``` ### A complete example This minimal Flask app implements the whole flow: connect, callback, calling the API, and refreshing. ```python app.py theme={null} import base64, hashlib, os, secrets from urllib.parse import urlencode import requests from flask import Flask, redirect, request, session, url_for CAMPFIRE_API = "https://api.meetcampfire.com" CLIENT_ID = os.environ["CAMPFIRE_CLIENT_ID"] CLIENT_SECRET = os.environ["CAMPFIRE_CLIENT_SECRET"] REDIRECT_URI = os.environ.get("REDIRECT_URI", "http://localhost:3999/callback") app = Flask(__name__) app.secret_key = os.environ["FLASK_SECRET"] def pkce_pair(): verifier = secrets.token_urlsafe(48) challenge = base64.urlsafe_b64encode( hashlib.sha256(verifier.encode()).digest() ).rstrip(b"=").decode() return verifier, challenge @app.get("/connect") def connect(): verifier, challenge = pkce_pair() state = secrets.token_urlsafe(24) session["oauth"] = {"state": state, "verifier": verifier} query = { "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "response_type": "code", "scope": "invoices:read invoice_payments:write vendors:read", "state": state, "code_challenge": challenge, "code_challenge_method": "S256", } return redirect(f"{CAMPFIRE_API}/ca/oauth/authorize?{urlencode(query)}") @app.get("/callback") def callback(): pending = session.pop("oauth", None) if request.args.get("error"): return f"Campfire returned {request.args['error']}", 400 if not pending or request.args.get("state") != pending["state"]: return "State mismatch", 400 r = requests.post( f"{CAMPFIRE_API}/ca/oauth/token", auth=(CLIENT_ID, CLIENT_SECRET), data={ "grant_type": "authorization_code", "code": request.args["code"], "redirect_uri": REDIRECT_URI, "code_verifier": pending["verifier"], }, timeout=10, ) r.raise_for_status() session["tokens"] = r.json() # In production, store server-side, encrypted. return redirect(url_for("home")) @app.get("/") def home(): tokens = session.get("tokens") if not tokens: return 'Connect to Campfire' r = requests.get( f"{CAMPFIRE_API}/users/api/get-user-permissions", headers={"Authorization": f"Bearer {tokens['access_token']}"}, timeout=10, ) if r.status_code == 401: return redirect(url_for("refresh")) return f"
{r.text}
" @app.get("/refresh") def refresh(): tokens = session.get("tokens") r = requests.post( f"{CAMPFIRE_API}/ca/oauth/token", auth=(CLIENT_ID, CLIENT_SECRET), data={"grant_type": "refresh_token", "refresh_token": tokens["refresh_token"]}, timeout=10, ) if r.status_code != 200: session.pop("tokens", None) # Connection is gone; the person must reconnect. return redirect(url_for("connect")) session["tokens"] = r.json() return redirect(url_for("home")) ``` ## Sign in with Campfire (OpenID Connect) Campfire is an OpenID Connect provider on top of the same authorization code flow. Request the `openid` scope and the token response includes an **ID token**: a signed JWT that says who authorized your app. Use it to sign people in to your own product with their Campfire account. **1. Add the identity scopes to your app** Add `openid`, plus `email` and/or `profile` if you want those claims, to the app's `allowed_scopes` in its [manifest](/guides/app-manifest) or through the API, then promote the version. They grant no access to Campfire data. **2. Request them with a nonce** Include the scopes in `scope` and send a random `nonce`, stored in the session with `state`: ```text theme={null} https://api.meetcampfire.com/ca/oauth/authorize ?client_id=YOUR_CLIENT_ID &redirect_uri=https%3A%2F%2Fyour-app.com%2Foauth%2Fcallback &response_type=code &scope=openid%20email%20profile%20invoices%3Aread &state=RANDOM_STATE &nonce=RANDOM_NONCE &code_challenge=BASE64URL_SHA256_OF_VERIFIER &code_challenge_method=S256 ``` **3. Verify the ID token** Exchange the code as usual. The response now has an `id_token` alongside the access token. Before trusting it, verify it: * The signature, with algorithm `RS256` and the key named by the token's `kid` header, from `https://api.meetcampfire.com/.well-known/jwks.json`. * `iss` is `https://api.meetcampfire.com`. * `aud` is your client ID. * `exp` is in the future. * `nonce` equals the value you stored. ```python theme={null} import jwt jwks = jwt.PyJWKClient("https://api.meetcampfire.com/.well-known/jwks.json") def verify_id_token(id_token: str, nonce: str) -> dict: key = jwks.get_signing_key_from_jwt(id_token).key claims = jwt.decode( id_token, key, algorithms=["RS256"], audience=CLIENT_ID, issuer="https://api.meetcampfire.com", options={"require": ["sub", "exp", "iat", "nonce"]}, ) if claims["nonce"] != nonce: raise ValueError("nonce mismatch") return claims ``` ### ID token claims | Claim | Scope | Description | | - | - | - | | `sub` | `openid` | A stable identifier for the person. It is the same in every workspace they belong to, so use it, not email, as your account key. | | `iss` | `openid` | `https://api.meetcampfire.com` | | `aud`, `azp` | `openid` | Your client ID. | | `iat`, `exp` | `openid` | Issued-at and expiry. ID tokens are valid for 1 hour. | | `nonce` | `openid` | The `nonce` you sent. Absent on tokens from a refresh. | | `at_hash` | `openid` | Hash of the access token issued with it. | | `email` | `email` | The person's sign-in email. | | `name` | `profile` | The person's name in the workspace they chose. | An ID token describes the **person**, not the workspace. To learn which workspace they chose, call the [permissions endpoint](#step-4-call-the-api) with the access token. Refreshing a connection that holds `openid` returns a fresh ID token too, without a `nonce`. The `client_credentials` grant never returns one. ### UserInfo endpoint You can also read the same claims with the access token: ```bash theme={null} curl https://api.meetcampfire.com/auth/userinfo \ -H "Authorization: Bearer $ACCESS_TOKEN" ``` ```json theme={null} {"sub": "31017", "email": "jordan@example.com", "name": "Jordan Lee"} ``` It returns `401` with `WWW-Authenticate: Bearer error="invalid_token"` for an expired or revoked token, and `403` with `error="insufficient_scope"` if the connection was not granted `openid`. ### Discovery OpenID Connect libraries can configure themselves from `https://api.meetcampfire.com/.well-known/openid-configuration`, which lists the issuer, endpoints, `jwks_uri`, `userinfo_endpoint`, and supported algorithms. Campfire signs ID tokens with `RS256` and uses public subject identifiers. Cache the JWKS, and re-fetch it when a token names a `kid` you don't have. ## Part 3: Manage connections ### Viewing connected apps Apps connected to your account are listed under [Settings > Connections](https://app.meetcampfire.com/v2/settings/connections). On the **All Connections** tab, an app with a category appears in that category's section (and on the category's tab) alongside Campfire's built-in integrations; an app without one appears in the **Apps** section. The **Active** tab lists every connected app under **Apps**, with the last time each one was used. ![The Connections page, Active tab, showing Acme Collections under Apps](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/connections-apps.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=58e0fb145d046e237e5e527ae1e40794) Click an app to see its description, the scopes you granted, and its **Activity** log. The log records every connection, token issue, refresh, revocation, and API request the app makes, including the method, path, and response status. ![The Acme Collections connection page with Description, Access, and an Activity table of API requests and token events](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/connection-detail.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=9906229e922f16011d41bb3300a35437) People see their own activity. Workspace admins see the activity of everyone in the workspace. If the app has a [Manage URL](/guides/app-extensions#manage-url), the page also shows **Manage in \**. If it adds [buttons, panels, navigation or event subscriptions](/guides/app-extensions), workspace admins can switch each one on or off here. ### Disconnecting an app Click **Disconnect** on the app's connection page and confirm. The app's tokens stop working **immediately**, and it has to be authorized again to reconnect. ![The Disconnect Acme Collections confirmation dialog](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/disconnect-dialog.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=a4d9ca08504f7aa1892279509528cbfa) After a disconnect, API calls with the old token return `401`: ```json theme={null} {"detail": "OAuth app token is invalid or has expired."} ``` Your app should treat a `401` on a refresh, or on a request made right after a refresh, as a lost connection and prompt the person to reconnect. ### When access ends automatically Besides an explicit disconnect, Campfire revokes a connection's tokens when: | Event | Effect | | - | - | | The client secret is rotated | All tokens for **every** connection to the app are revoked. | | The app is deleted | All connections are removed. | | A version with narrower permissions is promoted | Each connection is trimmed to the new permissions and its tokens are revoked. A connection left with no permissions is disconnected. | | A published app is unpublished, or loses Campfire's approval | Connections from other workspaces are disconnected. | | The person resets their password | All of that person's app connections are removed. | | The person is deactivated in a workspace | Their app connections in that workspace are removed. | | The person authorizes the app again | The previous tokens are replaced. | | A refresh token is reused | All tokens for that connection are revoked. | Widening an app's permissions never changes existing connections. People keep what they originally granted until they authorize again. ## Part 4: Manage your app On **Settings > Developer > Apps**, click **Manage** on an app's card to open its page. The tabs are: | Tab | What's on it | | - | - | | **Details** | Name, tagline, category, description, icon, redirect URLs, Connect URL, Manage URL, and publishing. | | **Permissions** | The app's scopes. | | **Security** | Allowed domains and the signing secret. See [Before you start](/guides/app-extensions#before-you-start). | | **Buttons**, **Panels**, **Navigation**, **Events** | Your app's [extensions](/guides/app-extensions). | | **Manifest** | The whole app as JSON. See [App manifest](/guides/app-manifest). | | **Activity** | Recent button clicks and event deliveries across every workspace. | ![The FakeTax app page on the Details tab, with a v1 Production badge and an Actions menu](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/app-details.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=e84cebb91c8971694dcb23e368ffd2a8) The **Actions** menu has **View credentials**, **Discard draft** (when there is a development version), and **Delete app**. ### Versions and approval An app's **details and permissions are versioned**, so you can change them without affecting the people who already use your app. The versioned fields are: name, tagline, category, description, icon, redirect URLs, Connect URL, Manage URL, and permissions. * **Production** is the version people authorize, and it's what the app uses in every workspace. * **Development** is your draft. There's at most one. The first time you save a change on the **Details** or **Permissions** tab (or in the manifest's `app` section), Campfire copies production into a new development version and saves your change there. Later saves update the same draft. The app's header and its card on the Apps page show both versions: ![The FakeTax app page with v1 Production and v2 Development badges, a Promote v2 button, and the note Editing development version 2. Promote it to go live.](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/version-draft.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=9fe21759e742da899b034e7f6558337a) ![The FakeTax card on the Apps page showing v1 Production and v2 Development badges](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/apps-list-draft.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=b1ae386fc830e4e982e79e9607b7828b) #### Testing a development version You can authorize the development version before it goes live. Add a redirect URL that only the draft has, for example your staging callback, and start the flow with that `redirect_uri`. Campfire picks the version from the redirect URL: * If **production** registers the `redirect_uri`, the person authorizes production. Production always wins when both match. * If only the **development** version registers it, the person authorizes the draft, with the draft's name, details and permissions. Development authorizations are limited to your own workspace. * If neither does, the request is rejected. Narrowing the draft's permissions immediately narrows any connections made on the draft. Discarding the draft disconnects them. #### Promoting Click **Promote vN** to make the draft live. ![The Promote version 2 to production dialog explaining what happens to existing connections](https://mintcdn.com/campfire/EZaYuU9NXAcXYXMc/images/oauth-apps/version-promote-dialog.png?fit=max\&auto=format\&n=EZaYuU9NXAcXYXMc\&q=85\&s=9a0abb7df5e84ba9824104278f3ee947) * **Private apps** are promoted immediately. * **Published or approved apps** are submitted to Campfire for review. The button becomes **Submit for approval**, and the badge shows **vN · Pending approval**. You can keep testing the draft while it waits. Saving another change withdraws it from review, so you'll need to submit again. * If Campfire **approves** it, the draft becomes production. * If Campfire **requests changes**, the badge shows **vN · Changes requested**, and the app page shows a banner with the reviewer's message. Edit the draft and submit it again. When a version is promoted, the previous production version is archived and every connection moves to the new version: | Permission change | Effect on existing connections | | - | - | | Widened | None. People keep what they granted until they authorize again. | | Narrowed | Each connection keeps what's still allowed, and its tokens are revoked. The person reconnects to continue. | | Narrowed to nothing a connection had | That connection is disconnected. | > [!NOTE] > > **Not versioned:** allowed domains, the signing secret, buttons, panels, navigation, event subscriptions, and the **Published** toggle. These take effect as soon as you save. ### Rotating the client secret Choose **Actions > View credentials**. After the first time, the secret is hidden. Click **Rotate secret** to generate a new one, which is shown once. ![The App credentials dialog with the secret hidden and a Rotate secret button](https://mintcdn.com/campfire/yxlw_AI4SzcnTkZz/images/oauth-apps/app-credentials-rotate.png?fit=max\&auto=format\&n=yxlw_AI4SzcnTkZz\&q=85\&s=19ab6be56de92c0617dc79288560cf5e) > [!WARNING] > > Rotating keeps the same client ID, but **immediately revokes every access and refresh token issued to the app**, across every connection. Everyone who connected will need to authorize again. Deploy the new secret right away. The client secret is separate from the **signing secret** on the **Security** tab, which signs webhooks, events and context tokens. Rotating the signing secret doesn't revoke any tokens. ### Deleting **Actions > Delete app** asks for confirmation. The app's credentials stop working immediately and every connection is removed. This cannot be undone. ### Private vs. published apps | | Private (default) | Published and approved | | - | - | - | | Who can authorize | People in the workspace that created the app | Anyone with a Campfire account | | Workspace at consent | Fixed to the creating workspace | The person picks any workspace they belong to | | Extensions shown in | The creating workspace | Every workspace with a connection | | Promoting a new version | Immediate | Reviewed by Campfire | Publishing is a two-step process. Turn on **Published** on the **Details** tab, then contact your Campfire support team to request a review. Until Campfire approves the app, it behaves like a private app. Turning **Published** off, or losing approval, disconnects every workspace other than your own. ## Scopes reference Scopes have the form `:`, for example `invoices:read` or `bills:write`. Request them space-separated in the `scope` parameter. A higher tier includes lower tiers (`write` includes `draft` and `read`). `approve` is separate and only covers itself. > [!TIP] > > The live catalog, with a human-readable description for every scope, is available from `GET https://api.meetcampfire.com/ca/api/v1/oauth-apps/scopes` using any access token. > **Accounting** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Amortizations | `amortizations` | `read`, `draft`, `write`, `approve` | > | Bill Payments | `bill_payments` | `read`, `draft`, `write`, `approve` | > | Bills | `bills` | `read`, `draft`, `write`, `approve` | > | Check Printing | `check_payments` | `read`, `write` | > | Credit Memo Payments | `credit_memo_payments` | `read`, `write` | > | Credit Memos | `credit_memos` | `read`, `draft`, `write`, `approve` | > | Debit Memo Payments | `debit_memo_payments` | `read`, `write` | > | Debit Memos | `debit_memos` | `read`, `draft`, `write`, `approve` | > | Fixed Assets, Disposals, Transfers, and Impairments | `fixed_assets` | `read`, `draft`, `write`, `approve` | > | General Ledger Transactions | `transactions` | `read`, `draft`, `write`, `approve` | > | Intercompany Journal Entries | `intercompany_journal_entries` | `read`, `draft`, `write`, `approve` | > | Invoice Payments | `invoice_payments` | `read`, `draft`, `write`, `approve` | > | Invoice Reminder Templates | `invoice_reminder_templates` | `read`, `write` | > | Invoice Reminders | `invoice_reminders` | `read`, `write` | > | Invoices | `invoices` | `read`, `draft`, `write`, `approve` | > | Journal Entries | `journal_entries` | `read`, `draft`, `write`, `approve` | > | Leases | `leases` | `read`, `draft`, `write`, `approve` | > **Revenue** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Contract Milestones | `contract_milestones` | `read`, `draft`, `write`, `approve` | > | Contract Prepaid Commits | `contract_prepaid_commits` | `read`, `draft`, `write`, `approve` | > | Contract Subscriptions | `contract_subscriptions` | `read`, `draft`, `write`, `approve` | > | Contract Usages | `contract_usages` | `read`, `draft`, `write`, `approve` | > | Contracts | `contracts` | `read`, `draft`, `write`, `approve` | > | Revenue Dashboard and Transactions | `revenue_transactions` | `read`, `draft`, `write`, `approve` | > **Reports** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Custom Reports | `custom_reports` | `read`, `write` | > | Financial Statements | `reports` | `read` | > **Cash Management** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Bank Accounts | `bank_accounts` | `read`, `write` | > | Cash Management Transactions | `bank_transactions` | `read`, `draft`, `write`, `approve` | > **Close Management** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Bank Reconciliation | `reconciliations` | `read`, `draft`, `write`, `approve` | > | Close Checklist | `close_checklist` | `read`, `write` | > **Organization** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Audit Logs | `audit_logs` | `read` | > | Auto Categorization Rules | `auto_categorization_rules` | `read`, `draft`, `write`, `approve` | > | Chart of Accounts | `accounts` | `read`, `write` | > | Contact Titles | `contact_titles` | `read`, `write` | > | Contract Templates | `contract_templates` | `read`, `write` | > | Cost Allocations | `cost_allocations` | `read`, `write` | > | Custom Fields | `custom_fields` | `read`, `write` | > | Departments | `departments` | `read`, `write` | > | Entities | `entities` | `read`, `write` | > | Fixed Asset Automation Rules | `fixed_asset_automation_rules` | `read`, `write` | > | Fixed Asset Classes | `fixed_asset_classes` | `read`, `write` | > | Invoice Reminder Settings | `invoice_reminder_settings` | `read`, `write` | > | Invoice Settings | `invoice_settings` | `read`, `write` | > | Lock Periods | `lock_periods` | `read`, `write` | > | Payment Terms | `payment_terms` | `read`, `write` | > | Product Bundles | `product_bundles` | `read`, `write` | > | Products and Services | `products` | `read`, `write` | > | Recurring Journal Entries | `recurring_journal_entries` | `read`, `write` | > | Statistical Accounts | `statistical_accounts` | `read`, `write` | > | Tags | `tags` | `read`, `write` | > | Tax Rates | `tax_rates` | `read`, `write` | > | Users | `users` | `read`, `write` | > | Validation Rules | `validation_rules` | `read`, `write` | > | Vendors and Payees | `vendors` | `read`, `write` | > | Webhooks | `webhooks` | `read`, `write` | > **Ember AI** > > | Resource | Scope prefix | Tiers | > | - | - | - | > | Ember AI | `ember_ai` | `read` | > **Identity (OpenID Connect)** > > These scopes have no tiers and grant no access to Campfire data. They only control what the [ID token and UserInfo endpoint](#sign-in-with-campfire-openid-connect) return. > > | Scope | Releases | > | - | - | > | `openid` | An ID token with the person's `sub`. Required for the other two. | > | `email` | `email` | > | `profile` | `name` | ## Errors and troubleshooting ### Authorize endpoint If the `client_id` or `redirect_uri` is invalid, Campfire can't safely redirect back to you. It responds with `400` and a JSON `detail` instead: | `detail` | Fix | | - | - | | `Unknown or inactive client.` | Check the client ID. The app may have been deleted. | | `redirect_uri is not registered for this app.` | Add the exact URL (scheme, host, port, and path) to the app's redirect URLs. | | `Authorization parameters are too long.` | Shorten `state` (4,096 characters max) or the other parameters. | All other problems redirect back to your `redirect_uri` with `error`, `error_description`, and your `state`: | `error` | Cause | | - | - | | `access_denied` | The person clicked **Cancel**. | | `invalid_request` | A malformed PKCE challenge, or a `code_challenge_method` other than `S256`. | | `invalid_scope` | An unknown scope, or one outside the app's permissions. | | `unsupported_response_type` | `response_type` was not `code`. | The consent screen itself can also show **Authorization unavailable**. This happens if the request expired (the person took more than 10 minutes), was already used, or the person doesn't belong to the workspace a private app is locked to. Start the flow again from your app. ### Token endpoint Errors follow the OAuth 2.0 format: `{"error": "...", "error_description": "..."}`. | Status | `error` | Common causes | | - | - | - | | 401 | `invalid_client` | Wrong client ID or secret, or the secret was rotated. | | 400 | `invalid_grant` | The code expired (5 minutes), was already used, or was issued to a different client. The `redirect_uri` or `code_verifier` doesn't match. The refresh token is expired, revoked, or was already used. | | 400 | `unsupported_grant_type` | Only `authorization_code` and `refresh_token` are supported. | > [!WARNING] > > Reusing an authorization code, like reusing a refresh token, revokes the tokens already issued from it. ### API requests | Status | Response | Meaning | | - | - | - | | 401 | `OAuth app token is invalid or has expired.` | Refresh the token. If refreshing fails, the person must reconnect. | | 401 | `OAuth app not recognized or inactive.` | The app was deleted or deactivated. | | 401 | `Your access to the selected workspace has been removed.` | The person no longer belongs to the workspace they chose. | | 401 | `This app is no longer available in the selected workspace.` | A published app was unpublished or lost approval. | | 403 | `WWW-Authenticate: ... error="insufficient_scope", scope="..."` | The token lacks the scope named in the header. Add it to the app and have the person reconnect. | | 403 | `This endpoint is not available to OAuth apps.` | Use an API key for this endpoint instead. | | 403 | `You do not have permission to perform this action.` (no `insufficient_scope`) | The person's own role doesn't allow the action. | | 429 | `Request was throttled. Expected available in N seconds.` | The connection went over 10 requests per second. Wait for the `Retry-After` seconds, then retry. | ## Security checklist * Keep the client secret on your server. Never put it in front-end code, mobile apps, or source control. * Always send and verify `state`. * Use PKCE (`S256`) on every authorization. * When you use OpenID Connect, send a `nonce`, verify every ID token before trusting it, and key accounts on `sub`, not email. * Request the fewest scopes you need. Prefer `draft` over `write` when a human should review changes. * Store tokens encrypted, and save each new refresh token before using the new access token. * Handle `401` by refreshing once, then prompting the person to reconnect. * Rotate the secret immediately if it may have leaked. This also revokes every existing token. > [!NOTE] > > **Need help?** Contact your Campfire support team and we're happy to help you build your integration. # Webhooks Source: https://docs.campfire.ai/guides/webhooks Receive real-time notifications when data changes in Campfire Webhooks let Campfire notify your systems in real time when data changes — for example when an invoice is paid, a bill is created, or a journal entry is updated. Instead of polling the API, you register an HTTPS endpoint, subscribe it to the topics you care about, and Campfire sends a signed `POST` request to that endpoint every time a matching event occurs. > [!NOTE] > > Managing webhooks — in the app or via the API — requires an **admin** user. Non-admin API keys receive a `403` from the webhook endpoints. ## Setting up a webhook You can create a webhook in the Campfire app or via the API. ### In the app **1. Go to the Webhooks page** Go to [Settings > Developer > Webhooks](https://app.meetcampfire.com/v2/settings/webhooks) in your Campfire instance. **2. Create the webhook** Click **New Webhook**, enter the HTTPS URL of your endpoint, check **Active**, and select the topics you want to subscribe to. Topics are grouped by object (Invoices, Bills, Journal Entries, etc.) — you can select a whole group or individual topics. **3. Copy your signing secret** After saving, the webhook card shows an **HMAC-SHA256 Secret**. Click **Show** to reveal it and store it in your application's secret store. You'll use it to [verify signatures](#verifying-the-signature) on incoming deliveries. ### Via the API Create a webhook with a `POST` to the webhook endpoint. See our [authentication guide](/quickstart) for how to get an API key. ```bash theme={null} curl -X POST https://api.meetcampfire.com/integrations/api/v1/webhook \ -H "Authorization: Token $CAMPFIRE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/campfire/webhook", "active": true, "topics": [ {"name": "Invoice.paid"}, {"name": "Bill.created"} ] }' ``` The response includes your signing secret (`token`) and the webhook's `uuid`: ```json theme={null} { "id": 12, "uuid": "3c88df19-1c1f-4b1c-b4a7-768793055a60", "url": "https://example.com/campfire/webhook", "token": "your-50-character-signing-secret", "topics": [ {"id": 5, "name": "Invoice.paid"}, {"id": 18, "name": "Bill.created"} ], "active": true, "created_at": "2026-08-04T12:00:00+0000", "last_modified_at": "2026-08-04T12:00:00+0000" } ``` > [!NOTE] > > The signing secret is generated by Campfire and cannot be set or changed. To rotate it, delete the webhook and create a new one. ## Topics A webhook only receives events for the topics it is subscribed to. Topic names are exact strings — subscribe using the values below. | Object | Topics | | - | - | | Invoices | `Invoice.created`, `Invoice.updated`, `Invoice.deleted`, `Invoice.payment`, `Invoice.paid` | | Bills | `Bill.created`, `Bill.updated`, `Bill.deleted`, `Bill.payment`, `Bill.paid` | | Credit Memos | `CreditMemo.created`, `CreditMemo.updated`, `CreditMemo.deleted` | | Credit Memo Lines | `CreditMemoLine.created`, `CreditMemoLine.updated`, `CreditMemoLine.deleted` | | Debit Memos | `DebitMemo.created`, `DebitMemo.updated`, `DebitMemo.deleted` | | Debit Memo Lines | `DebitMemoLine.created`, `DebitMemoLine.updated`, `DebitMemoLine.deleted` | | Journal Entries | `JournalEntry.created`, `JournalEntry.updated`, `JournalEntry.deleted` | | Contracts | `Contract.created`, `Contract.updated`, `Contract.deleted` | **Payment topics** have special semantics for invoices and bills: * `Invoice.payment` / `Bill.payment` fires whenever the amount paid increases — including partial payments. * `Invoice.paid` / `Bill.paid` fires when the document transitions to fully paid. When that happens, **both** the `.paid` and `.payment` topics fire (as two separate deliveries), and no `.updated` event is sent for that change. ## Payload Every delivery is a `POST` with a JSON body containing four fields: | Field | Type | Description | | - | - | - | | `webhook_uuid` | string | UUID of the webhook subscription that received this event. Matches the `Campfire-Webhook-UUID` header. | | `topic` | string | The topic that fired, e.g. `"Invoice.paid"`. | | `data` | object | The full serialized object, in the same shape as the corresponding `GET` endpoint in the [API reference](/api-reference). For `*.deleted` topics, `data` contains only the object's id: `{"id": 12345}`. | | `changes` | object or null | Field-level diff of what changed, keyed by field name with `old` and `new` values. `null` for `*.deleted` topics. On `*.created` topics, every field is listed with `"old": null`. | Example delivery for `Invoice.paid`: ```json theme={null} { "webhook_uuid": "3c88df19-1c1f-4b1c-b4a7-768793055a60", "topic": "Invoice.paid", "data": { "id": 12345, "invoice_number": "INV-1042", "payment_status": "paid", "amount_paid": 1500.0 // ...full invoice object, same shape as the Invoices API }, "changes": { "payment_status": {"old": "open", "new": "paid"}, "amount_paid": {"old": 500.0, "new": 1500.0} } } ``` ### Request headers | Header | Description | | - | - | | `Content-Type` | Always `application/json`. | | `Campfire-Webhook-Request-Timestamp` | Unix timestamp (seconds) of when the request was signed, e.g. `1770000000`. | | `Campfire-Webhook-Signature-v1` | Hex-encoded HMAC-SHA256 signature of the request. See below. | | `Campfire-Webhook-UUID` | UUID of the webhook subscription. Constant across all deliveries to that webhook. | ## Verifying the signature Every delivery is signed with your webhook's secret so you can verify it genuinely came from Campfire. The signed message is the delivery timestamp and the raw request body, joined by a single `:` character: ``` {timestamp}:{raw request body} ``` where `timestamp` is the value of the `Campfire-Webhook-Request-Timestamp` header. Campfire computes an HMAC-SHA256 digest of this message using your signing secret as the key, hex-encodes it, and sends it in the `Campfire-Webhook-Signature-v1` header. > [!WARNING] > > Compute the signature over the **raw request body exactly as received** — read it before your framework parses it, and never re-serialize the parsed JSON. Re-serializing can change whitespace and key order, which changes the signature. To verify a delivery: 1. Read the `Campfire-Webhook-Request-Timestamp` and `Campfire-Webhook-Signature-v1` headers and the raw request body. 2. Reject the delivery if the timestamp is too old — we recommend a tolerance of 5 minutes. This protects against replay attacks. (Retried deliveries are re-signed with a fresh timestamp, so a tolerance check will not reject legitimate retries.) 3. Compute `HMAC-SHA256` over `"{timestamp}:{raw body}"` using your signing secret, hex-encode it, and compare it to the signature header using a constant-time comparison. ```python Python theme={null} import hashlib import hmac import time def verify_campfire_signature(raw_body: bytes, headers: dict, secret: str, tolerance_seconds: int = 300) -> bool: timestamp = headers["Campfire-Webhook-Request-Timestamp"] signature = headers["Campfire-Webhook-Signature-v1"] if abs(time.time() - int(timestamp)) > tolerance_seconds: return False signed_payload = f"{timestamp}:".encode() + raw_body expected = hmac.new(secret.encode(), signed_payload, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature) ``` ```javascript Node.js theme={null} const crypto = require("crypto"); function verifyCampfireSignature(rawBody, headers, secret, toleranceSeconds = 300) { const timestamp = headers["campfire-webhook-request-timestamp"]; const signature = headers["campfire-webhook-signature-v1"]; if (Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) { return false; } const expected = crypto .createHmac("sha256", secret) .update(`${timestamp}:${rawBody}`) .digest("hex"); return ( expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature)) ); } ``` > [!NOTE] > > In Express, use `express.raw({ type: "application/json" })` (or capture `req.rawBody`) on your webhook route so the body is available unparsed. In Django/Flask/FastAPI, use `request.body` / `request.get_data()` / `await request.body()` respectively. You can confirm your implementation against real deliveries: the [delivery log](#delivery-and-retries) for each event includes the exact request headers and body Campfire sent, including the computed signature. ## Delivery and retries * Deliveries are `POST` requests. Respond with a **2xx** status code to acknowledge receipt. Any 4xx or 5xx response is treated as a failure. * Failed deliveries are retried up to **5 times**, roughly one minute apart. A `404` response is not retried. * Each retry is re-signed with a fresh timestamp and signature. * Respond quickly — acknowledge the delivery first and process the event asynchronously if your handling is slow. * Deliveries are not guaranteed to arrive in order, and retries mean your endpoint may occasionally receive the same event more than once. Make your handler idempotent — for example, treat the payload's `data` as the latest state of the object rather than applying `changes` incrementally. ### Delivery logs Recent delivery attempts appear under **Recent Events** on the Webhooks settings page, where you can inspect each request and response. The same data is available via the API (most recent 25 events): ```bash theme={null} curl https://api.meetcampfire.com/integrations/api/v1/webhook/12/events \ -H "Authorization: Token $CAMPFIRE_API_KEY" ``` Each event includes the delivery `status` (`PENDING`, `SUCCESS`, or `FAILURE`), the `topic`, and an `http` object with the full request and response — URL, headers, body, and response status code. ## Managing webhooks via the API | Method | Endpoint | Description | | - | - | - | | `GET` | `/integrations/api/v1/webhook` | List your webhooks | | `POST` | `/integrations/api/v1/webhook` | Create a webhook | | `GET` | `/integrations/api/v1/webhook/{id}` | Retrieve a webhook | | `PUT` / `PATCH` | `/integrations/api/v1/webhook/{id}` | Update a webhook | | `DELETE` | `/integrations/api/v1/webhook/{id}` | Delete a webhook | | `GET` | `/integrations/api/v1/webhook/{id}/events` | List recent deliveries | Notes: * `{id}` is the integer `id` field from the webhook object, not its `uuid`. * `url` and `active` are required on create and update. * `topics` is a list of `{"name": ""}` objects. Topic names must match the values in the [topics table](#topics) exactly. * Updating `topics` **replaces** the full set — include every topic the webhook should be subscribed to, not just new ones. * `token` (the signing secret) is read-only and returned on every read. To rotate it, delete the webhook and create a new one. * To pause deliveries without deleting the webhook, set `"active": false`. > [!NOTE] > > **Need help?** Contact your Campfire support team and we're happy to help you build your best Campfire workflow! # Introduction Source: https://docs.campfire.ai/index Welcome to the Campfire developer documentation ## Setting up Everything you need to get started developing against our APIs > **[Quickstart](/quickstart)** > > Follow our API onboarding and authorization guide. ## Build with us! Use our APIs to create the workflows you need to get Campfire working best for your organization. > **[API documentation](/api-reference/cash-management/list-bank-accounts)** > > Explore the full collection of Campfire APIs > **[Manage Accounts Payable](/guides/accounts-payable)** > > A guide to creating, voiding, and paying bills. > **[Manage Accounts Receivable](/guides/accounts-receivable)** > > A guide to creating, voiding, and paying invoices. > **[Manage Journal Entries](/guides/journal-entries)** > > How to post any journal, including FX and intercompany journal entries. > **[AI Integration with MCP](/guides/ai-integration)** > > Connect Campfire to your favorite AI tools using Model Context Protocol. > **[OAuth Apps](/guides/oauth-apps)** > > Let people connect your software to Campfire with OAuth 2.0. # Quickstart Source: https://docs.campfire.ai/quickstart How to get started using our APIs ## Getting Authenticated You need API tokens to be able to make requests to our APIs. Follow this guide for how to mint these tokens. > [!NOTE] > > You must have an active Campfire account and login to be able to create Auth tokens. > [!TIP] > > Building an integration that other people will connect to their own Campfire account? Use an [OAuth app](/guides/oauth-apps) instead of sharing API keys. **1. Login and go to the API Tokens page** Go to the [API Tokens](https://app.meetcampfire.com/v2/settings/api-keys) (Settings > API Keys) page in your Campfire instance. . **2. Create an API User** Click the "Create User" button to create a new user. Fill in the name, email, and role for the API user. The role will determine the actions and APIs you'll be able to access. Options: * `admin`: All APIs * `clerk`: Ability to view all APIs and post draft entries * `view only`: Ability to call only GET APIs **3. Create an API Key** Click the "Create API Key" button on the user. Copy the key and store it somewhere safe. You can only see the key once. **4. Use it in requests** Add the `Authorization: Token YOUR_API_KEY` header to your requests. ## Rate limits Each API user can make up to **10 requests per second**, shared across all endpoints. Requests over the limit return `429 Too Many Requests`. Wait the number of seconds in the `Retry-After` response header, then retry. To stay under the limit, page through large lists instead of fetching records one at a time, and cap how many requests your integration runs in parallel. ## Next steps Now that you have your keys, explore using them with these key features: > **[API documentation](/api-reference/cash-management/list-bank-accounts)** > > Explore the full collection of Campfire APIs > **[Manage Accounts Payable](/guides/accounts-payable)** > > A guide to creating, voiding, and paying bills. > **[Manage Accounts Receivable](/guides/accounts-receivable)** > > A guide to creating, voiding, and paying invoices. > **[Manage Journal Entries](/guides/journal-entries)** > > How to post any journal, including FX and intercompany journal entries. > **[Webhooks](/guides/webhooks)** > > Receive real-time notifications when data changes in Campfire. > **[OAuth Apps](/guides/oauth-apps)** > > Let people connect your software to Campfire with OAuth 2.0. > [!NOTE] > > **Need help?** Contact your Campfire support team and we're happy to help you build your best Campfire workflow!