GraphQL Mutations
This document provides a comprehensive reference of all GraphQL mutations available in Crane Ledger's API. Mutations modify data and include create, update, delete, and specialized operations.
Account Mutations
createAccount
Create a new account in the chart of accounts.
mutation CreateAccount($code: String!, $name: String!, $accountType: AccountType!, $description: String) {
createAccount(
code: $code
name: $name
accountType: $accountType
description: $description
) {
id
code
name
accountType
status
createdAt
}
}
Parameters:
code: String!- Account code (e.g., "1001", "2001")name: String!- Account display nameaccountType: AccountType!- Account type (ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE)description: String- Optional account description
Return Type: AccountNode
Authentication: Required
Credits: 1
Example:
mutation CreateCashAccount {
createAccount(
code: "1001"
name: "Operating Checking Account"
accountType: ASSET
description: "Primary business checking account at Bank of America"
) {
id
code
name
accountType
status
}
}
Response:
{
"data": {
"createAccount": {
"id": "act_1234567890abcdef",
"code": "1001",
"name": "Operating Checking Account",
"accountType": "ASSET",
"status": "ACTIVE"
}
}
}
updateAccount
Update an existing account's information.
mutation UpdateAccount(
$id: ID!
$code: String
$name: String
$description: String
) {
updateAccount(
id: $id
code: $code
name: $name
description: $description
) {
id
code
name
description
updatedAt
}
}
Parameters:
id: ID!- Account ID to updatecode: String- New account code (optional)name: String- New account name (optional)description: String- New description (optional)
Return Type: AccountNode
Authentication: Required
Credits: 1
Example:
mutation UpdateAccountName {
updateAccount(
id: "act_1234567890abcdef"
name: "Primary Operating Account"
description: "Updated account description"
) {
id
name
description
updatedAt
}
}
deleteAccount
Delete an account (only if it has no transactions).
mutation DeleteAccount($id: ID!) {
deleteAccount(id: $id)
}
Parameters:
id: ID!- Account ID to delete
Return Type: Boolean
Authentication: Required
Credits: 1
Example:
mutation RemoveUnusedAccount {
deleteAccount(id: "act_1234567890abcdef")
}
Response:
{
"data": {
"deleteAccount": true
}
}
Transaction Mutations
createTransaction
Create a new journal entry transaction.
mutation CreateTransaction(
$description: String!
$date: DateTime!
$entries: [LedgerEntryInput!]!
) {
createTransaction(
description: $description
date: $date
entries: $entries
) {
id
description
date
status
amount
entries {
id
accountId
entryType
amount
description
}
createdAt
}
}
Parameters:
description: String!- Transaction descriptiondate: DateTime!- Transaction dateentries: [LedgerEntryInput!]!- Journal entries (must balance)
Return Type: TransactionNode
Authentication: Required
Credits: 2
Example:
mutation RecordCashSale {
createTransaction(
description: "Cash sale to customer"
date: "2024-01-15T00:00:00Z"
entries: [
{
accountId: "act_1001"
entryType: DEBIT
amount: 250.00
description: "Cash received"
}
{
accountId: "act_4001"
entryType: CREDIT
amount: 250.00
description: "Revenue earned"
}
]
) {
id
description
status
amount
}
}
LedgerEntryInput Structure:
input LedgerEntryInput {
accountId: ID! # Account to affect
entryType: EntryType! # DEBIT or CREDIT
amount: Decimal! # Entry amount
description: String # Optional description
reference: String # Optional reference
}
Contact Mutations
createContact
Create a new business contact (customer, vendor, etc.).
mutation CreateContact(
$name: String!
$contactType: ContactType!
$email: String
$phone: String
$taxId: String
) {
createContact(
name: $name
contactType: $contactType
email: $email
phone: $phone
taxId: $taxId
) {
id
name
contactType
email
phone
taxId
createdAt
}
}
Parameters:
name: String!- Contact full namecontactType: ContactType!- Contact type (CUSTOMER, VENDOR, EMPLOYEE, OTHER)email: String- Email addressphone: String- Phone numbertaxId: String- Tax ID or VAT number
Return Type: ContactNode
Authentication: Required
Credits: 1 (worker-queued)
Example:
mutation AddNewCustomer {
createContact(
name: "Acme Corporation"
contactType: CUSTOMER
email: "billing@acme.com"
phone: "+1-555-0123"
taxId: "US123456789"
) {
id
name
contactType
email
}
}
updateContact
Update an existing contact's information.
mutation UpdateContact(
$id: ID!
$name: String
$email: String
$phone: String
$taxId: String
) {
updateContact(
id: $id
name: $name
email: $email
phone: $phone
taxId: $taxId
) {
id
name
email
phone
taxId
updatedAt
}
}
Parameters:
id: ID!- Contact ID to updatename: String- New contact nameemail: String- New email addressphone: String- New phone numbertaxId: String- New tax ID
Return Type: ContactNode
Authentication: Required
Credits: 1 (worker-queued)
deleteContact
Delete a contact.
mutation DeleteContact($id: ID!) {
deleteContact(id: $id)
}
Parameters:
id: ID!- Contact ID to delete
Return Type: Boolean
Authentication: Required
Credits: 1 (worker-queued)
Document Mutations
createInvoice
Create a new sales invoice.
mutation CreateInvoice(
$contactId: ID!
$invoiceDate: DateTime!
$dueDate: DateTime!
$items: [InvoiceItemInput!]!
$notes: String
) {
createInvoice(
contactId: $contactId
invoiceDate: $invoiceDate
dueDate: $dueDate
items: $items
notes: $notes
) {
id
invoiceNumber
contactId
invoiceDate
dueDate
status
subtotal
taxAmount
total
items {
description
quantity
unitPrice
lineTotal
}
createdAt
}
}
Parameters:
contactId: ID!- Customer contact IDinvoiceDate: DateTime!- Invoice creation datedueDate: DateTime!- Payment due dateitems: [InvoiceItemInput!]!- Invoice line itemsnotes: String- Optional invoice notes
Return Type: InvoiceNode
Authentication: Required
Credits: 5 (worker-queued)
Example:
mutation CreateSalesInvoice {
createInvoice(
contactId: "con_1234567890abcdef"
invoiceDate: "2024-01-15T00:00:00Z"
dueDate: "2024-02-15T00:00:00Z"
items: [
{
description: "Web Development Services"
quantity: 40.0
unitPrice: 125.00
}
{
description: "Hosting Setup"
quantity: 1.0
unitPrice: 500.00
}
]
notes: "Thank you for your business!"
) {
id
invoiceNumber
total
status
}
}
InvoiceItemInput Structure:
input InvoiceItemInput {
description: String! # Item description
quantity: Decimal! # Quantity ordered
unitPrice: Decimal! # Price per unit
itemId: ID # Optional catalog item reference
}
createBill
Create a new purchase bill from a vendor.
mutation CreateBill(
$contactId: ID!
$billDate: DateTime!
$dueDate: DateTime!
$items: [BillItemInput!]!
$notes: String
) {
createBill(
contactId: $contactId
billDate: $billDate
dueDate: $dueDate
items: $items
notes: $notes
) {
id
billNumber
contactId
billDate
dueDate
status
subtotal
taxAmount
total
items {
description
quantity
unitPrice
lineTotal
}
createdAt
}
}
Parameters:
contactId: ID!- Vendor contact IDbillDate: DateTime!- Bill datedueDate: DateTime!- Payment due dateitems: [BillItemInput!]!- Bill line itemsnotes: String- Optional bill notes
Return Type: BillNode
Authentication: Required
Credits: 5 (worker-queued)
BillItemInput Structure:
input BillItemInput {
description: String! # Item description
quantity: Decimal! # Quantity received
unitPrice: Decimal! # Price per unit
itemId: ID # Optional catalog item reference
}
recordInvoicePayment
Record a payment against an existing invoice.
mutation RecordInvoicePayment(
$invoiceId: ID!
$amount: Decimal!
$paymentDate: DateTime!
$paymentMethod: String!
$reference: String
$notes: String
) {
recordInvoicePayment(
invoiceId: $invoiceId
amount: $amount
paymentDate: $paymentDate
paymentMethod: $paymentMethod
reference: $reference
notes: $notes
) {
id
invoiceId
amount
paymentDate
paymentMethod
reference
notes
createdAt
}
}
Parameters:
invoiceId: ID!- Invoice ID to record payment againstamount: Decimal!- Payment amountpaymentDate: DateTime!- When payment was receivedpaymentMethod: String!- Payment method (check, wire, card, etc.)reference: String- Reference number (check #, transaction ID)notes: String- Optional payment notes
Return Type: PaymentNode
Authentication: Required
Credits: 2
Example:
mutation RecordPayment {
recordInvoicePayment(
invoiceId: "inv_1234567890abcdef"
amount: 1250.00
paymentDate: "2024-01-20T00:00:00Z"
paymentMethod: "Check"
reference: "Check #1234"
notes: "Payment received via mail"
) {
id
amount
paymentMethod
reference
}
}
recordBillPayment
Record a payment against an existing bill.
mutation RecordBillPayment(
$billId: ID!
$amount: Decimal!
$paymentDate: DateTime!
$paymentMethod: String!
$reference: String
$notes: String
) {
recordBillPayment(
billId: $billId
amount: $amount
paymentDate: $paymentDate
paymentMethod: $paymentMethod
reference: $reference
notes: $notes
) {
id
billId
amount
paymentDate
paymentMethod
reference
notes
createdAt
}
}
Parameters:
billId: ID!- Bill ID to record payment againstamount: Decimal!- Payment amountpaymentDate: DateTime!- When payment was madepaymentMethod: String!- Payment methodreference: String- Reference numbernotes: String- Optional payment notes
Return Type: PaymentNode
Authentication: Required
Credits: 2 (worker-queued)
Billing Mutations
purchaseCredits
Purchase additional credits for your organization.
mutation PurchaseCredits(
$creditAmount: Int!
$successUrl: String
$cancelUrl: String
) {
purchaseCredits(
creditAmount: $creditAmount
successUrl: $successUrl
cancelUrl: $cancelUrl
) {
checkoutUrl
creditsToAdd
priceCents
expiresAt
}
}
Parameters:
creditAmount: Int!- Number of credits to purchasesuccessUrl: String- Redirect URL after successful paymentcancelUrl: String- Redirect URL if payment is cancelled
Return Type: CreditPurchaseNode
Authentication: Required
Credits: 0 (billing operation)
Example:
mutation BuyMoreCredits {
purchaseCredits(
creditAmount: 5000
successUrl: "https://myapp.com/billing/success"
cancelUrl: "https://myapp.com/billing/cancel"
) {
checkoutUrl
creditsToAdd
priceCents
}
}
Response:
{
"data": {
"purchaseCredits": {
"checkoutUrl": "https://checkout.stripe.com/...",
"creditsToAdd": 5000,
"priceCents": 50000,
"expiresAt": "2024-01-15T11:00:00Z"
}
}
}
Complex Mutation Examples
Complete Business Workflow
Create a customer, invoice, and record payment in sequence:
mutation CompleteSalesWorkflow {
# 1. Create customer contact
createContact: createContact(
name: "TechStart Inc."
contactType: CUSTOMER
email: "billing@techstart.com"
taxId: "US987654321"
) {
id
name
}
# Note: In GraphQL, you can't use the result of one mutation
# as input to another in the same operation.
# You'd need separate operations or use the returned ID.
}
# Separate operation using the contact ID
mutation CreateInvoiceAndPayment($contactId: ID!) {
# 2. Create invoice for the customer
createInvoice: createInvoice(
contactId: $contactId
invoiceDate: "2024-01-15T00:00:00Z"
dueDate: "2024-02-15T00:00:00Z"
items: [
{
description: "Software Development"
quantity: 80.0
unitPrice: 150.00
}
]
) {
id
invoiceNumber
total
}
}
# Separate operation using the invoice ID
mutation RecordCustomerPayment($invoiceId: ID!) {
# 3. Record payment
recordPayment: recordInvoicePayment(
invoiceId: $invoiceId
amount: 12000.00
paymentDate: "2024-01-20T00:00:00Z"
paymentMethod: "Wire Transfer"
reference: "TXN-2024-001"
) {
id
amount
paymentMethod
}
}
Bulk Account Creation
Create multiple accounts in a single operation (using aliases):
mutation CreateChartOfAccounts {
cashAccount: createAccount(
code: "1001"
name: "Operating Cash"
accountType: ASSET
description: "Primary checking account"
) {
id
code
name
}
arAccount: createAccount(
code: "1101"
name: "Accounts Receivable"
accountType: ASSET
description: "Money owed by customers"
) {
id
code
name
}
salesAccount: createAccount(
code: "4001"
name: "Sales Revenue"
accountType: REVENUE
description: "Revenue from product sales"
) {
id
code
name
}
expenseAccount: createAccount(
code: "5101"
name: "Office Rent"
accountType: EXPENSE
description: "Monthly office rent expense"
) {
id
code
name
}
}
Complex Transaction with Multiple Entries
Record a payroll transaction with multiple deductions:
mutation RecordPayrollTransaction {
createTransaction(
description: "Monthly payroll - January 2024"
date: "2024-01-31T00:00:00Z"
entries: [
# Gross salary expense
{
accountId: "act_5101"
entryType: DEBIT
amount: 5000.00
description: "Gross salary expense"
}
# Employee taxes withheld
{
accountId: "act_2201"
entryType: DEBIT
amount: 750.00
description: "Employee tax withholdings"
}
# Employer taxes
{
accountId: "act_2202"
entryType: DEBIT
amount: 612.50
description: "Employer payroll taxes"
}
# Cash payment (net pay)
{
accountId: "act_1001"
entryType: CREDIT
amount: 3750.00
description: "Net salary payment"
reference: "Check #1001"
}
# Taxes payable (to be remitted)
{
accountId: "act_2210"
entryType: CREDIT
amount: 1362.50
description: "Payroll taxes payable"
}
]
) {
id
description
amount
status
entries {
accountId
entryType
amount
description
}
}
}
Error Handling
Business Logic Errors
{
"errors": [
{
"message": "Transaction does not balance: debits (150.00) != credits (100.00)",
"extensions": {
"code": "BUSINESS_RULE_VIOLATION"
}
}
]
}
Validation Errors
{
"errors": [
{
"message": "Account code '1001' already exists",
"extensions": {
"code": "VALIDATION_ERROR"
}
}
]
}
Authentication Errors
{
"errors": [
{
"message": "API key is disabled",
"extensions": {
"code": "FORBIDDEN"
}
}
]
}
Insufficient Credits
{
"errors": [
{
"message": "Insufficient credits remaining (required: 2, available: 1)",
"extensions": {
"code": "CREDIT_LIMIT_EXCEEDED"
}
}
]
}
Best Practices
Input Validation
Always validate inputs before mutations:
// Client-side validation
function validateTransaction(entries) {
const totalDebits = entries
.filter(e => e.entryType === 'DEBIT')
.reduce((sum, e) => sum + parseFloat(e.amount), 0);
const totalCredits = entries
.filter(e => e.entryType === 'CREDIT')
.reduce((sum, e) => sum + parseFloat(e.amount), 0);
if (totalDebits !== totalCredits) {
throw new Error(`Transaction does not balance: ${totalDebits} ≠ ${totalCredits}`);
}
}
Error Recovery
Handle errors gracefully:
async function safeMutation(mutation, variables) {
try {
const result = await client.mutate({
mutation,
variables
});
return result.data;
} catch (error) {
if (error.graphQLErrors) {
// Handle GraphQL errors
const businessError = error.graphQLErrors.find(
e => e.extensions?.code === 'BUSINESS_RULE_VIOLATION'
);
if (businessError) {
// Show user-friendly message
alert('Transaction must balance (debits = credits)');
return;
}
}
if (error.networkError) {
// Handle network errors
console.error('Network error:', error.networkError);
}
throw error;
}
}
Batch Operations
Group related mutations when possible:
// Instead of multiple separate calls
await createAccount(account1);
await createAccount(account2);
await createAccount(account3);
// Use aliases in single mutation
const result = await client.mutate({
mutation: gql`
mutation CreateMultipleAccounts {
account1: createAccount(code: "1001", name: "Cash", accountType: ASSET) { id }
account2: createAccount(code: "1101", name: "AR", accountType: ASSET) { id }
account3: createAccount(code: "4001", name: "Sales", accountType: REVENUE) { id }
}
`
});
Credit Management
Monitor credit usage in mutations:
// Check credits before expensive operations
async function checkCredits(minimumRequired) {
const { data } = await client.query({
query: gql`query { organization { creditsRemaining } }`
});
if (data.organization.creditsRemaining < minimumRequired) {
throw new Error(`Insufficient credits. Required: ${minimumRequired}, Available: ${data.organization.creditsRemaining}`);
}
}
// Use before complex operations
await checkCredits(5); // For invoice creation
const invoice = await createInvoice(invoiceData);
Performance Considerations
Mutation Costs
| Operation | Credits | Notes |
|---|---|---|
| createAccount | 1 | Simple entity creation |
| updateAccount | 1 | Metadata updates only |
| createTransaction | 2 | Journal entry validation |
| createContact | 1 | Worker-queued |
| createInvoice | 5 | Complex document + PDF generation |
| recordInvoicePayment | 2 | Transaction creation |
| purchaseCredits | 0 | Billing operation |
Optimizing Mutations
- Batch Related Operations:
mutation BulkAccountCreation {
assets: createAccount(code: "1000", name: "Assets", accountType: ASSET) { id }
liabilities: createAccount(code: "2000", name: "Liabilities", accountType: LIABILITY) { id }
equity: createAccount(code: "3000", name: "Equity", accountType: EQUITY) { id }
}
- Minimize Return Data:
# ✅ Efficient - only return what you need
mutation CreateAccount {
createAccount(code: "1001", name: "Cash", accountType: ASSET) {
id # Just the ID
}
}
# ❌ Inefficient - returns everything
mutation CreateAccountVerbose {
createAccount(code: "1001", name: "Cash", accountType: ASSET) {
id
code
name
accountType
status
createdAt
updatedAt
# ... all fields
}
}
- Use Appropriate Return Fields:
mutation CreateInvoice {
createInvoice(...) {
id
invoiceNumber
total
status
# Don't return large nested objects unless needed
}
}
GraphQL mutations in Crane Ledger provide powerful, type-safe operations for managing your accounting data. Each mutation includes comprehensive validation, error handling, and credit cost transparency to ensure reliable financial operations.
Need help?
Create a free account to access our support portal. Once signed in, use the Support tab in your dashboard to submit a support ticket — our team typically responds within 24 hours.
- ✨ For LLMs/AI assistants: Read our structured API reference