Skip to main content

One-Off Invoices

One-off invoices are standalone invoices for one-time charges that aren’t tied to a recurring subscription. Use them for setup fees, professional services, custom work, or any other ad-hoc billing needs.

Use Cases

Use CaseExample
Setup feesImplementation, onboarding charges
Professional servicesConsulting, training, custom development
OveragesUsage beyond subscription limits
Hardware/EquipmentPhysical products or devices
Ad-hoc chargesOne-time adjustments, corrections
Project workFixed-price project billing

Create via Dashboard

1

From the Invoices section click on New Invoice

Start by navigating to the Invoices section and click on the New Invoice button.
2

Select or create a customer

On the new invoice page, select an existing customer or create a new one if needed.
3

Select a due date and fill out the invoice memo

Choose the invoice due date and add any additional details or comments in the memo section.
4

Add line items from your product catalog

Add the line items by selecting products from your catalog. Enter the quantity, and review the totals for accuracy.
5

Review the invoice before issuing

Review the entire invoice for correctness, including totals, taxes, and line items. Click the Save Invoice button to continue.
6

Approve and send the invoice to customers

Once you have reviewed the invoice, click the Issue Invoice button to send the invoice to your customer.

Create via API

Basic One-Off Invoice

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  dueDate: '2024-02-15',
  lineItems: [
    {
      description: 'Implementation Services',
      quantity: 1,
      unitPrice: '2500.00',
      currency: 'USD',
    },
  ],
});

// Issue the invoice to send to customer
await alguna.invoices.issue(invoice.id);

With Product Catalog Items

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  dueDate: '2024-02-15',
  lineItems: [
    {
      productId: 'prod_setup_fee',
      quantity: 1,
    },
    {
      productId: 'prod_training',
      quantity: 8, // 8 hours of training
    },
  ],
});

With Custom Line Items

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  dueDate: '2024-02-15',
  lineItems: [
    {
      description: 'Custom Integration Development',
      quantity: 1,
      unitPrice: '5000.00',
      currency: 'USD',
      taxCategory: 'services',
    },
    {
      description: 'API Documentation Review',
      quantity: 4,
      unitPrice: '150.00',
      currency: 'USD',
      taxCategory: 'services',
    },
  ],
  memo: 'Custom development work per SOW dated Jan 10, 2024',
});

cURL Example

curl -X POST https://api.alguna.io/invoices \
  -H "Authorization: Bearer $ALGUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "acc_xyz789",
    "type": "one_off",
    "due_date": "2024-02-15",
    "line_items": [
      {
        "description": "Professional Services",
        "quantity": 1,
        "unit_price": "1500.00",
        "currency": "USD"
      }
    ],
    "memo": "Consulting engagement - January 2024"
  }'

Invoice Statuses

StatusDescription
draftInvoice created but not finalized
issuedInvoice sent to customer
paidPayment received in full
partially_paidPartial payment received
past_duePast due date, unpaid
voidInvoice canceled
uncollectibleMarked as uncollectible

Status Transitions


Line Item Configuration

Custom Line Item

{
  description: 'Custom Development Work',
  quantity: 1,
  unitPrice: '2500.00',
  currency: 'USD',
  taxCategory: 'services',
  metadata: {
    projectId: 'proj_123',
    hoursWorked: 25
  }
}

From Product Catalog

{
  productId: 'prod_consulting',
  quantity: 10,
  // Price comes from product catalog
  // Can override with unitPrice if needed
}

With Discount

{
  description: 'Annual Support Package',
  quantity: 1,
  unitPrice: '12000.00',
  discount: {
    type: 'percentage',
    value: 10, // 10% off
    reason: 'Multi-year commitment'
  }
}

Tax-Exempt Line Item

{
  description: 'Tax-Exempt Service',
  quantity: 1,
  unitPrice: '500.00',
  taxBehavior: 'exempt',
  taxExemptReason: 'Resale for export'
}

Invoice Options

Payment Terms

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  paymentTerms: 'net_30', // net_7, net_15, net_30, net_45, net_60, due_on_receipt
  // or specific due date
  dueDate: '2024-03-01',
  lineItems: [...],
});

Auto-Collection

Enable automatic payment collection:
const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  autoCollect: true, // Charge saved payment method on issue
  lineItems: [...],
});

Currency

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  currency: 'EUR', // Override customer's default currency
  lineItems: [
    {
      description: 'Service Fee',
      quantity: 1,
      unitPrice: '1000.00',
      currency: 'EUR',
    },
  ],
});

Memo and Notes

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  memo: 'Public memo visible to customer',
  internalNotes: 'Internal note for your team only',
  footer: 'Thank you for your business!',
  lineItems: [...],
});

Managing Draft Invoices

Update Line Items

// Add line item
await alguna.invoices.addLineItem('inv_abc123', {
  description: 'Additional Hours',
  quantity: 5,
  unitPrice: '150.00',
});

// Update line item
await alguna.invoices.updateLineItem('inv_abc123', 'li_xyz789', {
  quantity: 10,
});

// Remove line item
await alguna.invoices.deleteLineItem('inv_abc123', 'li_xyz789');

Update Invoice Details

await alguna.invoices.update('inv_abc123', {
  dueDate: '2024-03-01',
  memo: 'Updated payment terms',
});

Delete Draft Invoice

await alguna.invoices.delete('inv_abc123');
// Only works for draft invoices

Issue and Send

Issue Invoice

const invoice = await alguna.invoices.issue('inv_abc123', {
  sendEmail: true,
  emailTo: ['[email protected]', '[email protected]'],
});

console.log('Invoice number:', invoice.invoiceNumber);
console.log('Issued at:', invoice.issuedAt);

Issue Without Email

const invoice = await alguna.invoices.issue('inv_abc123', {
  sendEmail: false,
});

Resend Invoice

await alguna.invoices.resend('inv_abc123', {
  emailTo: ['[email protected]'],
  message: 'Please find your invoice attached.',
});

Bulk Invoice Creation

Create multiple invoices at once:
const results = await alguna.invoices.createBulk([
  {
    accountId: 'acc_customer1',
    type: 'one_off',
    dueDate: '2024-02-15',
    lineItems: [
      { productId: 'prod_setup', quantity: 1 },
    ],
  },
  {
    accountId: 'acc_customer2',
    type: 'one_off',
    dueDate: '2024-02-15',
    lineItems: [
      { productId: 'prod_setup', quantity: 1 },
    ],
  },
]);

console.log('Created:', results.created.length);
console.log('Failed:', results.failed.length);

Issue Multiple Invoices

await alguna.invoices.issueBulk({
  invoiceIds: ['inv_1', 'inv_2', 'inv_3'],
  sendEmail: true,
});

Invoice Templates

Create from Template

const invoice = await alguna.invoices.createFromTemplate({
  templateId: 'tmpl_services',
  accountId: 'acc_xyz789',
  variables: {
    projectName: 'Website Redesign',
    hours: 40,
  },
});

Define Template

const template = await alguna.invoiceTemplates.create({
  name: 'Professional Services',
  lineItems: [
    {
      description: 'Consulting - {{projectName}}',
      unitPrice: '150.00',
      quantityVariable: 'hours',
    },
  ],
  paymentTerms: 'net_30',
  memo: 'Thank you for choosing our services.',
});

Webhooks

EventDescription
invoice.createdInvoice created
invoice.issuedInvoice issued and sent
invoice.paidInvoice fully paid
invoice.payment_failedPayment attempt failed
invoice.past_dueInvoice became past due
invoice.voidedInvoice voided

Example Handler

app.post('/webhooks/alguna', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'invoice.created':
      console.log('New invoice:', event.data.id);
      break;

    case 'invoice.issued':
      const { id, invoiceNumber, total, accountId } = event.data;
      console.log(`Invoice ${invoiceNumber} issued for $${total}`);
      // Update your CRM, send Slack notification, etc.
      break;

    case 'invoice.paid':
      console.log('Invoice paid:', event.data.id);
      // Trigger fulfillment, grant access, etc.
      break;

    case 'invoice.past_due':
      console.log('Invoice past due:', event.data.id);
      // Trigger collection workflow
      break;
  }

  res.sendStatus(200);
});

PDF Generation

Get Invoice PDF

const pdf = await alguna.invoices.getPdf('inv_abc123');

// Returns URL to download PDF
console.log('PDF URL:', pdf.url);
console.log('Expires:', pdf.expiresAt);

Bulk PDF Generation

const result = await alguna.invoices.generatePdfs({
  invoiceIds: ['inv_1', 'inv_2', 'inv_3'],
});

// Returns ZIP file with all PDFs
console.log('Download URL:', result.zipUrl);

Custom PDF Settings

const pdf = await alguna.invoices.getPdf('inv_abc123', {
  language: 'de', // German
  includeTerms: true,
  logoPosition: 'right',
});

Common Scenarios

Setup Fee Invoice

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  dueDate: 'on_receipt',
  lineItems: [
    {
      productId: 'prod_setup_fee',
      quantity: 1,
    },
  ],
  autoCollect: true, // Charge immediately
});

await alguna.invoices.issue(invoice.id);

Consulting Invoice

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  paymentTerms: 'net_30',
  lineItems: [
    {
      description: 'Strategy Consulting - January 2024',
      quantity: 20, // hours
      unitPrice: '200.00',
    },
    {
      description: 'Travel Expenses',
      quantity: 1,
      unitPrice: '450.00',
      taxBehavior: 'exempt',
    },
  ],
  memo: 'Payment due within 30 days. Late payments subject to 1.5% monthly interest.',
});

Project Milestone Invoice

const invoice = await alguna.invoices.create({
  accountId: 'acc_xyz789',
  type: 'one_off',
  dueDate: '2024-02-15',
  lineItems: [
    {
      description: 'Project Alpha - Milestone 2: Design Complete',
      quantity: 1,
      unitPrice: '15000.00',
    },
  ],
  metadata: {
    projectId: 'proj_alpha',
    milestone: 2,
    totalMilestones: 5,
  },
});

Voiding Invoices

Void an Invoice

await alguna.invoices.void('inv_abc123', {
  reason: 'Customer requested cancellation',
});

Void Restrictions

  • Draft invoices can be deleted
  • Issued/unpaid invoices can be voided
  • Paid invoices cannot be voided (use credit notes instead)

Best Practices

Use Descriptive Line Items

Clear descriptions help customers understand what they’re paying for.

Set Clear Due Dates

Use consistent payment terms across your organization.

Enable Auto-Collection

For customers with saved payment methods, collect automatically.

Include Memos

Add context about projects or agreements in the memo field.

Troubleshooting

Invoice Won’t Issue

  1. Check that all required fields are complete
  2. Verify line items have valid prices
  3. Ensure customer has a valid billing address

Payment Not Processing

  1. Verify customer has a valid payment method
  2. Check auto-collect settings
  3. Review payment gateway logs

PDF Generation Fails

  1. Check invoice has been issued
  2. Verify branding settings are configured
  3. Contact support if issue persists

Next Steps