Agree.com Invoices API
Create, send, and track payment requests to your customers. ## Overview Invoices are the core of Agree's payment system. An invoice represents a request for payment that you send to a customer. When created, Agree generates a secure payment link that your customer can use to pay via their preferred method. **Key concepts:** - Invoices are sent to contacts (customers in your address book) - Each invoice supports multiple payment methods: ACH bank transfer, credit card, or wire transfer - Invoices can be one-time or recurring on a schedule - Automatic email delivery sends the payment link to your customer - Webhooks notify you in real-time when payment status changes ## Common Use Cases ### Bill a Client for a Completed Project Send a one-time invoice after completing work: ```bash curl -X POST https://api.agree.com/api/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": { "email": "client@company.com", "name": "Sarah Johnson", "company": "Johnson & Co" }, "amount": {"amount": 500000, "currency": "USD"}, "payment_methods": ["card", "ach", "wire"], "due_at": "2025-02-01T00:00:00Z", "memo": "Website redesign project - Final payment" } }' ``` The client receives an email with a payment link. You'll get a webhook when they pay. ### Set Up Monthly Retainer Billing Create a recurring invoice that bills automatically each month: ```bash curl -X POST https://api.agree.com/api/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": { "email": "accounting@bigcorp.com", "name": "Accounts Payable", "company": "BigCorp Inc" }, "amount": {"amount": 250000, "currency": "USD"}, "payment_methods": ["ach"], "memo": "Monthly consulting retainer", "recurring_options": { "schedule": "custom", "repeat_frequency": 1, "repeat_unit": "month", "repeat_on_type": "day_of_month", "repeat_on_day": 1, "recurring_end_type": "never", "reminder_schedule": "weekly" } } }' ``` Agree automatically generates and sends invoices on the 1st of each month. ### Track Outstanding Invoices Find all unpaid invoices that are past due: ```bash curl "https://api.agree.com/api/v1/invoices?statuses=sent,due&date_type=due_at&date_end=2025-01-17" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Handle Failed Payments When a payment fails, you receive an `invoice.failed` webhook. The invoice status changes to `failed`, but the customer can retry payment using the same link. To check failed invoices: ```bash curl "https://api.agree.com/api/v1/invoices?statuses=failed" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Generate a Revenue Report Get all paid invoices for a specific month: ```bash curl "https://api.agree.com/api/v1/invoices?statuses=paid&date_type=paid_at&date_start=2025-01-01&date_end=2025-01-31" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Creating an Invoice Here's a basic invoice creation: ```bash curl -X POST https://api.agree.com/api/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": { "email": "customer@example.com", "name": "John Doe", "company": "Acme Corp" }, "amount": {"amount": 15000, "currency": "USD"}, "payment_methods": ["card", "ach"], "due_at": "2025-02-15T00:00:00Z", "scheduled_at": "2025-02-01T00:00:00Z", "memo": "Website development - Phase 1" } }' ``` **Note:** When using the `create` endpoint, `due_at` and `scheduled_at` are required fields. The invoice issue date (`inserted_at`) is automatically set when the invoice is created. All dates should be in ISO8601 format (UTC). **Response:** ```json { "data": { "id": "4a755746-ba45-4226-a669-aebc7ad3719c", "status": "sent", "amount": {"amount": 15000, "currency": "USD"}, "billing_contact": { "email": "customer@example.com", "name": "John Doe", "company": "Acme Corp", "title": null }, "payment_link": "https://agree.com/pay/abc123token", "payment_methods": ["card", "ach"], "due_at": "2025-02-15T00:00:00Z", "scheduled_at": "2025-02-01T00:00:00Z", "memo": "Website development - Phase 1", "inserted_at": "2025-01-15T10:30:00Z" } } ``` The `payment_link` is a secure URL you can share with your customer. When `automatic_delivery` is enabled (the default), Agree emails this link to the billing contact automatically. ### Create and Send in One Step For convenience, you can create and send an invoice in a single API call: ```bash curl -X POST https://api.agree.com/api/v1/invoices/create_and_send \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": { "email": "customer@example.com", "name": "John Doe" }, "amount": {"amount": 15000, "currency": "USD"}, "payment_methods": ["card", "ach"], "memo": "Website development - Phase 1" } }' ``` **Note:** When using `create_and_send`, `scheduled_at` is always set to the current UTC time (to send immediately), regardless of any value you provide. If `due_at` is not provided, it will default to the current UTC time. The invoice issue date (`inserted_at`) is automatically set when the invoice is created. You can optionally specify a custom `due_at`: ```bash curl -X POST https://api.agree.com/api/v1/invoices/create_and_send \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": { "email": "customer@example.com", "name": "John Doe" }, "amount": {"amount": 15000, "currency": "USD"}, "payment_methods": ["card", "ach"], "due_at": "2025-02-15T00:00:00Z", "memo": "Website development - Phase 1" } }' ``` Note that `scheduled_at` is always set to the current UTC time when using `create_and_send`, so it's not necessary (and will be ignored) if provided. **Response:** ```json { "data": { "id": "4a755746-ba45-4226-a669-aebc7ad3719c", "status": "sending", "amount": {"amount": 15000, "currency": "USD"}, ... } } ``` The response includes `status: "sending"` to indicate the invoice is being sent asynchronously. The invoice will transition to `sent` once the email is delivered. **When to use `create_and_send`:** - You want to create and send an invoice immediately in one request - You don't need to review or modify the invoice before sending - You want to simplify your integration by combining two operations **When to use `create` + `send` separately:** - You need to review the invoice before sending - You want to add additional information after creation - You're creating invoices in bulk and want to send them later ### Amounts Amounts are specified in the smallest currency unit. For USD, this means cents: | You want to charge | Send this amount | |--------------------|------------------| | $100.00 | `10000` | | $1,500.50 | `150050` | | $0.99 | `99` | ```json { "amount": { "amount": 10000, "currency": "USD" } } ``` ### Specifying the Customer You can specify who receives the invoice in two ways: **Using `billing_contact`** (recommended for new customers): ```json { "invoice": { "billing_contact": { "email": "customer@example.com", "name": "John Doe" } } } ``` This creates or updates a contact automatically. **Using `contact_id`** (for existing contacts): ```json { "invoice": { "contact_id": "550e8400-e29b-41d4-a716-446655440000" } } ``` You cannot use both in the same request. ## Invoice Lifecycle Every invoice progresses through a series of statuses: ``` ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ created │ ──► │ sent │ ──► │ due │ ──► │ paid │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ ├──► processing ──► paid │ │ │ └──► failed │ └──► canceled ``` | Status | Description | |--------|-------------| | `created` | Invoice created but not yet sent to customer | | `sending` | Invoice is being sent (temporary status returned by API) | | `sent` | Invoice emailed to customer, awaiting payment | | `due` | Invoice is past the scheduled send date | | `processing` | Payment initiated, waiting for confirmation | | `paid` | Payment completed successfully | | `failed` | Payment attempt failed (customer can retry) | | `canceled` | Invoice was canceled (no payment expected) | | `refunded` | Payment was refunded after completion | | `draft` | Template-only, not yet converted to invoice | **Note:** The `sending` status is a temporary status returned by the API when you use `create_and_send` or `send` endpoints. It indicates the invoice is being sent asynchronously. When you query the invoice later, it will show `sent` (or `due` if sent immediately with a past due date). ## Recurring Invoices Set up automatic recurring invoices by providing `recurring_options`: ```bash curl -X POST https://api.agree.com/api/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "billing_contact": {"email": "customer@example.com"}, "amount": {"amount": 99900, "currency": "USD"}, "payment_methods": ["card"], "recurring_options": { "schedule": "custom", "repeat_frequency": 1, "repeat_unit": "month", "recurring_end_type": "never", "reminder_schedule": "weekly" } } }' ``` ### Recurring Options | Field | Type | Description | |-------|------|-------------| | `schedule` | string | `none` (one-time) or `custom` (recurring) | | `repeat_frequency` | integer | How often to repeat (e.g., `1` = every period, `2` = every other) | | `repeat_unit` | string | `week` or `month` | | `repeat_on_weekday` | string | For weekly: `monday`, `tuesday`, etc. | | `repeat_on_type` | string | For monthly: `day_of_month` or `day_of_week` | | `repeat_on_day` | integer | Day of month (1-31) | | `repeat_on_week` | integer | Week of month (1-5, where 5 = last) | | `recurring_end_type` | string | `never`, `date`, or `count` | | `recurring_end_date` | datetime | End date (when type is `date`) | | `recurring_end_count` | integer | Number of occurrences (when type is `count`) | | `reminder_schedule` | string | `none`, `daily`, `weekly`, or `monthly` | | `forward_payment_enabled` | boolean | Allow paying future invoices early | | `pass_on_fees_enabled` | boolean | Pass processing fees to the payer at checkout (default: false) | ### Examples **Monthly on the 15th, forever:** ```json { "schedule": "custom", "repeat_frequency": 1, "repeat_unit": "month", "repeat_on_type": "day_of_month", "repeat_on_day": 15, "recurring_end_type": "never" } ``` **Every 2 weeks on Monday, for 6 occurrences:** ```json { "schedule": "custom", "repeat_frequency": 2, "repeat_unit": "week", "repeat_on_weekday": "monday", "recurring_end_type": "count", "recurring_end_count": 6 } ``` ## Listing and Filtering Invoices Retrieve invoices with powerful filtering options: ```bash # Get all invoices curl https://api.agree.com/api/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" # Filter by status curl "https://api.agree.com/api/v1/invoices?statuses=sent,due" \ -H "Authorization: Bearer YOUR_API_KEY" # Filter by date range (invoices due in January 2025) curl "https://api.agree.com/api/v1/invoices?date_type=due_at&date_start=2025-01-01&date_end=2025-01-31" \ -H "Authorization: Bearer YOUR_API_KEY" # Filter by amount range ($100-$500) curl "https://api.agree.com/api/v1/invoices?amount_min=100&amount_max=500" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Query Parameters | Parameter | Type | Description | |-----------|------|-------------| | `page` | integer | Page number (default: 1) | | `page_size` | integer | Items per page (default: 10, max: 100) | | `statuses` | string | Comma-separated status filter | | `date_start` | string | Start date (YYYY-MM-DD) | | `date_end` | string | End date (YYYY-MM-DD) | | `date_type` | string | Which date to filter: `paid_at`, `due_at`, `scheduled_at` | | `date_timezone` | string | Timezone for dates (default: `Etc/UTC`) | | `amount_min` | number | Minimum amount in dollars | | `amount_max` | number | Maximum amount in dollars | | `customer` | string | Filter by customer/company name | | `include_drafts` | boolean | Include draft invoices | ## Sending an Invoice If you created an invoice without sending it (or want to resend), you can send it explicitly: ```bash curl -X POST https://api.agree.com/api/v1/invoices/4a755746-ba45-4226-a669-aebc7ad3719c/send \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response:** ```json { "data": { "id": "4a755746-ba45-4226-a669-aebc7ad3719c", "status": "sending", ... } } ``` The response includes `status: "sending"` to indicate the invoice is being sent asynchronously. The invoice will transition to `sent` once the email is delivered. **Note:** You can only send invoices that are in `created` status. Invoices that are already `sent`, `due`, or `paid` cannot be resent using this endpoint. ## Updating an Invoice Update invoice details before payment: ```bash curl -X PUT https://api.agree.com/api/v1/invoices/4a755746-ba45-4226-a669-aebc7ad3719c \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoice": { "memo": "Updated memo - Website development Phase 1", "due_at": "2025-02-28T00:00:00Z" } }' ``` **Note:** Some fields cannot be changed after certain status transitions (e.g., you can't change the amount after payment processing begins). ## Downloading invoice and receipt PDFs These endpoints return a **presigned S3 URL** in JSON (not the raw PDF bytes). The URL is valid for **one hour** (`expires_in: 3600`). Use a GET to the returned `url` to download the file (e.g. redirect the user or fetch server-side). ### Invoice PDF ```bash curl "https://api.agree.com/api/v1/invoices/INVOICE_ID/pdf" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response (200):** ```json { "data": { "url": "https://...", "expires_in": 3600 } } ``` If the PDF is not in storage yet, the API waits a **short time** (default **5 seconds** of server-side polling, configurable via `invoice_pdf_api_inline_wait_ms`) for the file to appear—first in case another client already started generation, then after enqueueing generation if needed. If it is still not ready, you receive **202 Accepted** with a **`Retry-After`** header (default **3** seconds, `invoice_pdf_api_retry_after_seconds`) and a JSON body such as `data: { "status": "pending", "retry_after_seconds": 3, ... }`. **Repeat the same GET** until you get **200** with `data.url`. This avoids holding many long-lived HTTP connections when PDFs are slow or the render queue is busy. ### Receipt PDF Only available when the invoice status is **`paid`**. Otherwise the API returns **422**. ```bash curl "https://api.agree.com/api/v1/invoices/INVOICE_ID/receipt_pdf" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response (200):** Same shape as invoice PDF (`data.url`, `data.expires_in`). If the invoice is paid but the receipt file is not available yet, the API returns **404**. ## Canceling an Invoice Cancel an unpaid invoice: ```bash curl -X DELETE https://api.agree.com/api/v1/invoices/4a755746-ba45-4226-a669-aebc7ad3719c \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Fields Reference ### Core Fields | Field | Type | Description | |-------|------|-------------| | `id` | UUID | Unique invoice identifier | | `name` | string | Invoice display name | | `status` | string | Current status (see lifecycle) | | `amount` | object | Amount with `amount` (cents) and `currency` | | `memo` | string | Notes visible to customer (max 255 chars) | | `organization_id` | UUID | Your organization's ID | | `agreement_id` | UUID | Associated agreement (if any) | ### Customer Fields | Field | Type | Description | |-------|------|-------------| | `billing_contact` | object | Customer info: `email`, `name`, `company`, `title` | | `payment_link` | string | URL where customer can pay | ### Payment Fields | Field | Type | Description | |-------|------|-------------| | `payment_methods` | array | Accepted methods: `ach`, `card`, `wire` | | `payment_type` | string | `invoice`, `payment`, or `subscription` | | `used_payment_method` | string | Method used for successful payment | | `sales_tax_percentage` | number | Tax percentage applied | ### Date Fields | Field | Type | Description | |-------|------|-------------| | `scheduled_at` | datetime | When invoice will be/was sent | | `sent_at` | datetime | When invoice was emailed | | `due_at` | datetime | Payment due date | | `paid_at` | datetime | When payment completed | | `processing_at` | datetime | When processing started | | `authorized_at` | datetime | When payment was authorized | | `inserted_at` | datetime | When invoice was created | ### Delivery Fields | Field | Type | Description | |-------|------|-------------| | `delivery_method` | string | How invoice is delivered (`email`) | | `automatic_delivery` | boolean | Auto-send when created | ### Recurring Fields | Field | Type | Description | |-------|------|-------------| | `recurring_options` | object | Recurring schedule configuration | | `recurring_sequence` | integer | Position in recurring series (1, 2, 3...) | ### Reminder Fields | Field | Type | Description | |-------|------|-------------| | `reminder_scheduled_at` | datetime | Next reminder date | | `last_reminder_sent_at` | datetime | Last reminder sent | ### External Reference Fields | Field | Type | Description | |-------|------|-------------| | `external_id` | string | Your external invoice ID | | `external_customer_id` | string | Your external customer ID | | `destination_organization_id` | UUID | For B2B: receiving organization |