API Documentation

Build powerful integrations with our comprehensive REST API. Manage invoices, customers, payments, and more programmatically.

Authentication

All API requests require authentication using an API key. Include your API key in the Authorization header as a Bearer token:

curl "https://invoicematic.com/api/v1/api/me" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

The base URL for all API endpoints is: https://invoicematic.com/api/v1/api

API Keys

API keys can be created in Settings > API Keys. Each key has specific scopes that determine what resources it can access and what actions it can perform.

Keep your API keys secure

Never share your API keys in publicly accessible areas such as GitHub, client-side code, etc.

Key Format

API keys are prefixed with is_key_ for easy identification. Keys can optionally have an expiration date and an IP allowlist.

Available Scopes

Scopes control what an API key can access. A :read scope allows listing and viewing resources. A :write scope allows creating, updating, and deleting.

invoices:read
invoices:write
estimates:read
estimates:write
customers:read
customers:write
payments:read
payments:write
expenses:read
expenses:write
items:read
items:write
reports:read
settings:read
settings:write

API Endpoints

Base URL: https://invoicematic.com/api/v1

GET /health

Check API health status. No scope required.

Response

{
  "status": "healthy",
  "timestamp": "2026-02-07T10:30:00Z",
  "version": "2.2.0"
}
GET /api/me

Get information about the authenticated company and API key. No scope required.

Response

{
  "company": {
    "id": 1,
    "name": "Acme Corp",
    "slug": "acme-corp",
    "address": {
      "address_street_1": "123 Main St",
      "city": "New York",
      "state": "NY",
      "zip": "10001",
      "country_id": 231,
      "phone": "+1 555-0100"
    },
    "logo": null
  },
  "api_key": {
    "name": "Production Key",
    "scopes": ["invoices:read", "invoices:write", "customers:read"],
    "expires_at": "2027-01-15T00:00:00+00:00",
    "last_used_at": "2026-02-07T10:30:00+00:00"
  }
}

Invoices

GET /api/invoices invoices:read

List all invoices. Supports pagination and filtering.

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerResults per page (default: 10)
statusstringFilter by status: DRAFT, SENT, VIEWED, OVERDUE, COMPLETED
customer_idintegerFilter by customer

Example Request

curl "https://invoicematic.com/api/v1/api/invoices?page=1&limit=5" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "invoice_date": "2026-02-01",
      "due_date": "2026-03-01",
      "invoice_number": "INV-000001",
      "reference_number": "REF-100",
      "status": "SENT",
      "paid_status": "UNPAID",
      "discount_type": "fixed",
      "discount": 0,
      "discount_val": 0,
      "sub_total": 50000,
      "total": 50000,
      "tax": 0,
      "due_amount": 50000,
      "currency_id": 1,
      "exchange_rate": 1,
      "customer_id": 1,
      "template_name": "invoice1",
      "creator_id": 1,
      "unique_hash": "abc123...",
      "customer": {
        "id": 1,
        "name": "John Doe",
        "email": "[email protected]"
      },
      "items": [
        {
          "id": 1,
          "name": "Web Design",
          "description": "Homepage redesign",
          "quantity": 1,
          "price": 50000,
          "total": 50000
        }
      ]
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=3", "prev": null, "next": "...?page=2" },
  "meta": { "current_page": 1, "last_page": 3, "per_page": 5, "total": 12 }
}
POST /api/invoices invoices:write

Create a new invoice. All monetary values are in cents (e.g. 10000 = $100.00).

Required Fields

FieldTypeDescription
invoice_datestringInvoice date (YYYY-MM-DD)
due_datestringDue date (YYYY-MM-DD, optional)
customer_idintegerCustomer ID
invoice_numberstringUnique invoice number
discountnumberDiscount percentage or fixed amount
discount_valintegerDiscount value in cents
sub_totalnumberSubtotal in cents
totalnumberTotal in cents
taxnumberTax amount in cents
template_namestringPDF template (e.g. "invoice1")
itemsarrayLine items (see below)
items.*.namestringItem name
items.*.quantitynumberQuantity
items.*.pricenumberUnit price in cents

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/invoices" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice_date": "2026-02-07",
    "due_date": "2026-03-07",
    "customer_id": 1,
    "invoice_number": "INV-000042",
    "discount": 0,
    "discount_val": 0,
    "sub_total": 150000,
    "total": 150000,
    "tax": 0,
    "template_name": "invoice1",
    "items": [
      {
        "name": "Web Development",
        "description": "Frontend implementation",
        "quantity": 10,
        "price": 15000
      }
    ]
  }'

Example Response

{
  "data": {
    "id": 42,
    "invoice_date": "2026-02-07",
    "due_date": "2026-03-07",
    "invoice_number": "INV-000042",
    "status": "DRAFT",
    "paid_status": "UNPAID",
    "sub_total": 150000,
    "total": 150000,
    "tax": 0,
    "due_amount": 150000,
    "discount": 0,
    "discount_val": 0,
    "customer_id": 1,
    "currency_id": 1,
    "exchange_rate": 1,
    "template_name": "invoice1",
    "creator_id": 1,
    "unique_hash": "xyz789...",
    "items": [
      {
        "id": 100,
        "name": "Web Development",
        "description": "Frontend implementation",
        "quantity": 10,
        "price": 15000,
        "total": 150000
      }
    ]
  }
}
GET /api/invoices/{'{id}'} Get a single invoice invoices:read
PUT /api/invoices/{'{id}'} Update an invoice invoices:write
DELETE /api/invoices/{'{id}'} Delete an invoice invoices:write

Customers

GET /api/customers customers:read

List all customers. Supports pagination and filtering.

Example Request

curl "https://invoicematic.com/api/v1/api/customers?limit=10" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]",
      "phone": "+1 555-0100",
      "contact_name": "John",
      "company_name": "Doe Industries",
      "website": "https://doe.example.com",
      "currency_id": 1,
      "prefix": "Mr",
      "created_at": "2026-01-15T08:00:00.000000Z",
      "billing": {
        "name": "John Doe",
        "address_street_1": "123 Main St",
        "city": "New York",
        "state": "NY",
        "zip": "10001",
        "country_id": 231,
        "phone": "+1 555-0100"
      },
      "shipping": null
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 1 }
}
POST /api/customers customers:write

Create a new customer.

Required Fields

FieldTypeDescription
namestringRequired. Customer name
emailstringEmail address (unique per company)
phonestringPhone number
contact_namestringContact person name
company_namestringCompany name
websitestringWebsite URL
currency_idintegerCurrency ID
billingobjectBilling address (name, address_street_1, city, state, zip, country_id, phone)
shippingobjectShipping address (same fields as billing)

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/customers" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Smith",
    "email": "[email protected]",
    "phone": "+1 555-0200",
    "company_name": "Smith Co",
    "currency_id": 1,
    "billing": {
      "name": "Jane Smith",
      "address_street_1": "456 Oak Ave",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102",
      "country_id": 231
    }
  }'

Example Response

{
  "data": {
    "id": 5,
    "name": "Jane Smith",
    "email": "[email protected]",
    "phone": "+1 555-0200",
    "company_name": "Smith Co",
    "currency_id": 1,
    "company_id": 1,
    "creator_id": 1,
    "created_at": "2026-02-07T12:00:00.000000Z",
    "billing": {
      "name": "Jane Smith",
      "address_street_1": "456 Oak Ave",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102",
      "country_id": 231
    }
  }
}
GET /api/customers/{'{id}'} Get a single customer customers:read
PUT /api/customers/{'{id}'} Update a customer customers:write

Payments

GET /api/payments payments:read

List all payments. Supports pagination and filtering.

Example Request

curl "https://invoicematic.com/api/v1/api/payments" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "payment_number": "PAY-000001",
      "payment_date": "2026-02-05",
      "amount": 50000,
      "notes": "Payment received via bank transfer",
      "customer_id": 1,
      "invoice_id": 1,
      "payment_method_id": 1,
      "currency_id": 1,
      "exchange_rate": 1,
      "base_amount": 50000,
      "creator_id": 1,
      "customer": {
        "id": 1,
        "name": "John Doe"
      },
      "payment_method": {
        "id": 1,
        "name": "Bank Transfer"
      }
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 1 }
}
POST /api/payments payments:write

Record a new payment. Monetary values are in cents.

Required Fields

FieldTypeDescription
payment_datestringRequired. Payment date (YYYY-MM-DD)
customer_idintegerRequired. Customer ID
amountintegerRequired. Amount in cents
payment_numberstringRequired. Unique payment number
invoice_idintegerInvoice to apply payment to
payment_method_idintegerPayment method ID
notesstringPayment notes

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/payments" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_date": "2026-02-07",
    "customer_id": 1,
    "amount": 50000,
    "payment_number": "PAY-000010",
    "invoice_id": 1,
    "payment_method_id": 1,
    "notes": "Wire transfer received"
  }'

Example Response

{
  "data": {
    "id": 10,
    "payment_number": "PAY-000010",
    "payment_date": "2026-02-07",
    "amount": 50000,
    "notes": "Wire transfer received",
    "customer_id": 1,
    "invoice_id": 1,
    "payment_method_id": 1,
    "currency_id": 1,
    "exchange_rate": 1,
    "base_amount": 50000,
    "creator_id": 1
  }
}
GET /api/payments/{'{id}'} Get a single payment payments:read
PUT /api/payments/{'{id}'} Update a payment payments:write

Estimates

GET /api/estimates estimates:read

List all estimates. Supports pagination and filtering.

Example Request

curl "https://invoicematic.com/api/v1/api/estimates" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "estimate_date": "2026-02-01",
      "expiry_date": "2026-03-01",
      "estimate_number": "EST-000001",
      "status": "DRAFT",
      "discount_type": "fixed",
      "discount": 0,
      "discount_val": 0,
      "sub_total": 75000,
      "total": 75000,
      "tax": 0,
      "currency_id": 1,
      "exchange_rate": 1,
      "customer_id": 1,
      "template_name": "estimate1",
      "creator_id": 1,
      "customer": {
        "id": 1,
        "name": "John Doe"
      },
      "items": [
        {
          "id": 1,
          "name": "Consulting",
          "quantity": 5,
          "price": 15000,
          "total": 75000
        }
      ]
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 1 }
}
POST /api/estimates estimates:write

Create a new estimate. Accepts the same item structure as invoices.

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/estimates" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "estimate_date": "2026-02-07",
    "expiry_date": "2026-03-07",
    "customer_id": 1,
    "estimate_number": "EST-000005",
    "discount": 0,
    "discount_val": 0,
    "sub_total": 200000,
    "total": 200000,
    "tax": 0,
    "template_name": "estimate1",
    "items": [
      {
        "name": "Strategy Consulting",
        "description": "Market analysis and growth strategy",
        "quantity": 20,
        "price": 10000
      }
    ]
  }'
GET /api/estimates/{'{id}'} Get a single estimate estimates:read
PUT /api/estimates/{'{id}'} Update an estimate estimates:write
DELETE /api/estimates/{'{id}'} Delete an estimate estimates:write

Expenses

GET /api/expenses expenses:read

List all expenses. Supports pagination and filtering.

Example Request

curl "https://invoicematic.com/api/v1/api/expenses" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "expense_date": "2026-02-03",
      "expense_number": "EXP-000001",
      "amount": 12500,
      "notes": "Office supplies purchase",
      "customer_id": null,
      "expense_category_id": 2,
      "currency_id": 1,
      "exchange_rate": 1,
      "base_amount": 12500,
      "payment_method_id": 1,
      "creator_id": 1,
      "expense_category": {
        "id": 2,
        "name": "Office Supplies"
      }
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 1 }
}
POST /api/expenses expenses:write

Create a new expense.

Required Fields

FieldTypeDescription
expense_datestringRequired. Expense date (YYYY-MM-DD)
expense_category_idintegerRequired. Expense category ID
amountintegerRequired. Amount in cents
currency_idintegerRequired. Currency ID
customer_idintegerAssociated customer
payment_method_idintegerPayment method used
notesstringNotes about the expense

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/expenses" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "expense_date": "2026-02-07",
    "expense_category_id": 2,
    "amount": 4500,
    "currency_id": 1,
    "notes": "Team lunch"
  }'
GET /api/expenses/{'{id}'} Get a single expense expenses:read
PUT /api/expenses/{'{id}'} Update an expense expenses:write
DELETE /api/expenses/{'{id}'} Delete an expense expenses:write

Items

GET /api/items items:read

List all items in the product/service catalog.

Example Request

curl "https://invoicematic.com/api/v1/api/items" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json"

Example Response

{
  "data": [
    {
      "id": 1,
      "name": "Web Development",
      "description": "Full-stack web development services",
      "price": 15000,
      "unit_id": 1,
      "company_id": 1,
      "creator_id": 1,
      "currency_id": 1,
      "tax_per_item": "NO",
      "created_at": "2026-01-10T08:00:00.000000Z",
      "unit": {
        "id": 1,
        "name": "hour"
      }
    },
    {
      "id": 2,
      "name": "Logo Design",
      "description": "Custom logo and brand identity",
      "price": 250000,
      "unit_id": null,
      "company_id": 1,
      "creator_id": 1,
      "currency_id": 1,
      "tax_per_item": "NO",
      "created_at": "2026-01-12T10:00:00.000000Z"
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 10, "total": 2 }
}
POST /api/items items:write

Create a new item in the product/service catalog.

Required Fields

FieldTypeDescription
namestringRequired. Item name
priceintegerRequired. Price in cents
descriptionstringItem description
unit_idintegerUnit of measure ID

Example Request

curl -X POST "https://invoicematic.com/api/v1/api/items" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "SEO Audit",
    "description": "Comprehensive SEO analysis and recommendations",
    "price": 75000
  }'

Example Response

{
  "data": {
    "id": 3,
    "name": "SEO Audit",
    "description": "Comprehensive SEO analysis and recommendations",
    "price": 75000,
    "unit_id": null,
    "company_id": 1,
    "creator_id": 1,
    "currency_id": 1,
    "tax_per_item": null,
    "created_at": "2026-02-07T12:00:00.000000Z",
    "updated_at": "2026-02-07T12:00:00.000000Z"
  }
}
GET /api/items/{'{id}'} Get a single item items:read
PUT /api/items/{'{id}'} Update an item items:write
DELETE /api/items/{'{id}'} Delete an item items:write

Pagination

All list endpoints return paginated results. Control pagination with the page and limit query parameters.

GET /api/v1/api/invoices?page=2&limit=25

Paginated responses include links and meta objects:

{
  "data": [ ... ],
  "links": {
    "first": "...?page=1",
    "last": "...?page=5",
    "prev": "...?page=1",
    "next": "...?page=3"
  },
  "meta": {
    "current_page": 2,
    "from": 26,
    "last_page": 5,
    "per_page": 25,
    "to": 50,
    "total": 120
  }
}

Webhooks

Webhooks allow you to receive real-time notifications when events occur in your account. Configure webhooks in Settings > Webhooks.

Available Events

invoice.created
invoice.updated
invoice.deleted
invoice.sent
invoice.viewed
invoice.paid
invoice.overdue
estimate.created
estimate.updated
estimate.deleted
estimate.sent
estimate.accepted
estimate.rejected
customer.created
customer.updated
customer.deleted
payment.received
payment.deleted
expense.created
expense.updated
expense.deleted

Webhook Payload

Each webhook delivery includes the following headers:

HeaderDescription
X-Webhook-SignatureHMAC-SHA256 signature of the payload
X-Webhook-EventThe event name (e.g. invoice.created)
X-Webhook-Delivery-IdUnique delivery ID
X-Webhook-TimestampUnix timestamp of the delivery
{
  "event": "invoice.created",
  "timestamp": "2026-02-07T10:30:00Z",
  "data": {
    "id": 42,
    "invoice_number": "INV-000042",
    "status": "DRAFT",
    "total": 150000,
    "customer_id": 1,
    ...
  }
}

Signature Verification

Verify webhook signatures to ensure deliveries came from Invoicematic. Compare the X-Webhook-Signature header against an HMAC-SHA256 hash of the raw request body using your webhook secret.

// PHP
$signature = hash_hmac('sha256', $payload, $webhookSecret);
$isValid = hash_equals($signature, $requestSignature);

// Node.js
const crypto = require('crypto');
const signature = crypto.createHmac('sha256', webhookSecret).update(payload).digest('hex');
const isValid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(requestSignature));

Idempotency

For POST and PUT requests, include an Idempotency-Key header to ensure the operation is only performed once, even if the request is retried.

curl -X POST "https://invoicematic.com/api/v1/api/invoices" \
  -H "Authorization: Bearer is_key_your_api_key_here" \
  -H "Idempotency-Key: unique-request-id-123" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"customer_id": 1, ...}'

Idempotency keys expire after 24 hours. If you retry a request with the same key within that window, you'll receive the same response without the operation being performed again.

Error Handling

The API uses standard HTTP status codes. Error responses include a JSON body with details.

Validation Error (422)

{
  "message": "The given data was invalid.",
  "errors": {
    "customer_id": ["The customer id field is required."],
    "invoice_number": ["The invoice number has already been taken."]
  }
}

Authentication Error (401)

{
  "error": "unauthorized",
  "message": "Invalid API key."
}

Scope Error (403)

{
  "error": "forbidden",
  "message": "Your API key does not have the required scope(s): invoices:write"
}

HTTP Status Codes

200 Success
401 Unauthorized - Invalid or missing API key
403 Forbidden - API key lacks the required scope
404 Not Found - Resource doesn't exist or belongs to another company
422 Validation Error - Check the errors object for field-level details
429 Rate Limited - Too many requests (limit: 180/minute)
500 Server Error - Something went wrong on our end