Accounts & Integrations
Core Concepts

Core Concepts

This page documents the shared concepts used across all Agile Receivables API endpoints: authentication, response envelopes, errors, pagination, and rate limits.

Authentication

All requests to the Agile Receivables external API must include an API key in the X-Api-Key header:

curl --request GET \
  --url https://api.agilereceivables.com/api/v1/external/customers \
  --header 'X-Api-Key: sk_live_xxxxxxxxxxxxxxxxxxxx'
  • Keys are managed from the Integrations / API Keys section of the dashboard.
  • Supported scopes are:
    • accounts:read, accounts:write
    • customers:read, customers:write
    • campaigns:read, campaigns:write
    • disputes:read, disputes:write
    • ledgers:read, ledgers:write
    • statements:read, statements:write
    • sync:write
  • An API key with an empty scope list has full access (no restriction).
  • Restriction applies only when scopes are explicitly set.

Only X-Api-Key is required. No additional tenant header is needed; workspace/company context is derived from the API key.

Response envelope

All endpoints return a consistent JSON envelope:

{
  "success": true,
  "status_code": 200,
  "message": "...",
  "data": { },
  "meta": { }
}
  • success: boolean flag indicating whether the operation completed successfully.
  • status_code: HTTP-style numeric code mirrored in the HTTP status.
  • message: human-readable description of the outcome.
  • data: payload for the current resource (for example, a customer or account object, or a list).
  • meta: metadata, including pagination information for list endpoints.

Errors

Auth failures return simple detail payloads:

{ "detail": "Invalid or expired API key" }
  • 401 Unauthorized: missing, invalid, revoked, or expired API key.
{ "detail": "API key lacks required scope: <scope_name>" }
  • 403 Forbidden: API key does not include the required scope.

General API failures use a consistent error envelope:

{
  "success": false,
  "status_code": 400,
  "message": "User-facing error message",
  "errors": [
    {
      "field": "amount",
      "error": "Payment amount cannot exceed outstanding amount"
    }
  ],
  "meta": {}
}

Common HTTP status codes:

StatusNameDescription
400Bad RequestValidation error in the request body or parameters.
401UnauthorizedMissing, invalid, revoked, or expired API key.
403ForbiddenAPI key lacks the required scope.
404Not FoundResource does not exist for your tenant.
422UnprocessableJSON is valid but fields fail validation.
429Too ManyRate limit exceeded for this API key.
500Server ErrorUnexpected internal server error.

errors uses field and error. There is no machine-readable error_code field.

Pagination

Paginated endpoints (such as list customers, list accounts, and list disputes) use a standard meta object:

{
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  }
}
  • total: total number of records matching the current filters. Always present (defaults to 0 when empty).
  • total_pages: total number of pages for the current per_page.
  • page: 1-based page index.
  • per_page: number of records returned per page.
  • Pagination is page-based only (cursor pagination is not supported).

Typical query parameters for list endpoints:

  • page: page number (default: 1, min: 1).
  • per_page: results per page (default: 20, min: 1, max: 100).

Some endpoints define additional filters, for example:

  • Customers: search, tags.
  • Accounts: search, status, customer_id, overdue_only, amount_min, amount_max.
  • Campaigns: search, status, type.
  • Disputes: status, customer_id.
  • Ledgers: customer_id, customer_external_id, from_date, to_date, transaction_type (per-page max 200).
  • Statements: customer_id, customer_external_id, status, from_date, to_date.

Rate limiting

For platform middleware overall, rate limiting is configured by RATE_LIMIT_PER_MINUTE over a 60-second window and is applied per user ID or IP.

Headers:

  • X-RateLimit-Limit
  • X-RateLimit-Window

For the external API (/api/v1/external/*), this middleware is currently excluded. There is no separate test-vs-live key rate limit behavior, and no per-tenant/per-key limit.

Sandbox/live behavior is controlled by record-level is_sandbox flags, not by API key type. Sandbox accounts cannot be enrolled in campaigns. Sandbox keys are also blocked from enrolling statements into Statement-Acknowledgement campaigns — these endpoints return 400 for sk_test_* keys. The sandbox data-purge endpoint (/sandbox/data) clears ledger entries alongside customers and invoices.

Typical integration flow

The following high-level flow is common when integrating with Agile Receivables:

  1. Create or sync customers
    Use the Customers endpoints to create or update customer records. Ensure that each customer has at least one contact point (email or phone) and enough identifying information for your agents.

  2. Create or sync accounts
    Use the Accounts endpoints to create invoices with amounts, currency, issue dates, and due dates. Optional fields (such as external_invoice_id, payment_terms, or description) can help with reporting.

  3. Assign accounts to campaigns
    Use the Campaigns endpoints to place accounts into one or more collection campaigns, individually or in bulk.

  4. Record payments and reconcile
    Use the Payments endpoints to record payments and track outstanding balances, then use your own systems to reconcile these with bank or processor statements.

Ledger-driven integrations (Sikka-style)

When the source system pushes raw transaction-level data instead of pre-built invoices, the flow is:

  1. Push customers with the Customers endpoints.
  2. Push ledger entries with the Ledgers endpoints (POST /ledgers/bulk). The server upserts each entry and immediately runs the statement aggregator — one monthly statement per (customer, calendar month) is created or updated, with payments allocated across statements oldest-first.
  3. Read back statements with the Statements endpoints to confirm what was materialized.
  4. Enroll statements into a Statement-Acknowledgement campaign with POST /statements/{id}/campaign (or the bulk variant). SA campaigns must be created in-app.

The combined-sync endpoint POST /api/v1/external/sync also accepts ledger_entries in addition to customers and invoices. The aggregator runs at the end of the pipeline whenever ledger_entries are included.