Finero public API

A versioned, tenant-scoped REST API for Finero — invoices, payment links, confirmed payments, ERP sync, and automation history. Built for external systems, automation platforms, and AI agents. All requests and responses are JSON. Timestamps are ISO 8601 UTC. Decimal money amounts are exact strings (never floats); *_minor amounts are integers in the currency's minor unit with an explicit ISO 4217 currency.

Base URL

https://api.getfinero.com/functions/v1/api

Your first call

A workspace admin creates an API key in Settings → API (the full key is shown once — store it safely). Then confirm it works — this read is safe for both key types and returns your workspace context:

curl "https://api.getfinero.com/functions/v1/api/v1/me" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Versioning. All paths live under /v1. Changes within v1 are additive and backward-compatible (new fields, new operations). A breaking change would ship as /v2 — existing v1 behavior is never silently changed. The machine-readable spec lives at https://api.getfinero.com/functions/v1/api/openapi.json.

Authentication

Every request needs a Finero API key, created by a workspace admin in Settings → API. Keys are tenant-owned: all data access is scoped to the key's workspace, and nothing in a request can address another workspace. Send the key as a bearer token:

curl "https://api.getfinero.com/functions/v1/api/v1/me" \
  -H "Authorization: Bearer fnr_0123456789abcdef_your43charSecretPart..."
  • Keep keys in a secrets manager. Never commit them, never put them in URLs, client code, or logs.
  • The full key is shown exactly once at creation and can never be retrieved.
  • To rotate: create a new key, switch your integration, then revoke the old key (revocation is immediate).
  • Authentication failures return a generic 401 — the API never confirms whether a key identifier exists.

Permissions

A key has exactly one permission, chosen at creation:

  • Read-only — may call only operations guaranteed to have no side effects (marked Admin or Read-only key below). It can never create, change, trigger, or send anything.
  • Admin — everything Read-only can, plus the small set of deliberately exposed mutations (marked Admin key required): creating and deactivating payment links. An Admin key does not get write access to other resources — invoices, installments, payments, connections, sync runs, and workflow history stay read-only for every key.

Enforcement is per-operation (each operation is classified in the spec via x-permission), not by HTTP method. Calling an admin-only operation with a read-only key returns 403 permission_denied.

Pagination, filtering & sorting

List endpoints return { data: [...], pagination: { next_cursor, has_more, limit } }. Pass ?limit= (1–100, default 25) and follow pagination.next_cursor via ?cursor= until has_more is false. Cursors are opaque — don't parse or construct them. Results are ordered by creation time (newest first by default; ?order=asc for oldest first).

Filters are per-endpoint allowlists (documented on each endpoint) applied as exact matches or since-timestamps. Unknown query parameters are rejected with 400 validation_failed — there is no generic column filtering.

Idempotency

Operations marked Idempotency-Key required must send a unique Idempotency-Key header (1–255 printable ASCII characters, e.g. a UUID). Retrying with the same key and same body returns the original result (with Idempotency-Replayed: true) instead of executing again — safe for network retries. Reusing a key with a different body returns 409 idempotency_conflict. Keys expire after 24 hours. Retry guidance for agents: on a timeout or 5xx, retry the identical request with the identical key; on 4xx, fix the request and use a fresh key.

Rate limits

  • 120 requests/minute per API key
  • 600 requests/minute per workspace (all its keys)
  • Repeated failed authentication is limited per source address

Exceeding a limit returns 429 rate_limit_exceeded with a Retry-After header (seconds). Request bodies are capped at 64 KiB (413 payload_too_large).

End-to-end examples

A common flow: find a collectible invoice, read its installments, create a payment link for one installment, then poll its status. All data is fictional; replace $FINERO_API_KEY and the ids with real values from earlier responses.

1. List invoices (Admin or Read-only key, no side effects)

List invoices (add ?collection_ready=true to find collectible ones).

curl "https://api.getfinero.com/functions/v1/api/v1/invoices" \
  -H "Authorization: Bearer $FINERO_API_KEY"

2. Get an invoice with its installments (Admin or Read-only key, no side effects)

Read one invoice with its installments; take a collectible installment's id for the next step.

curl "https://api.getfinero.com/functions/v1/api/v1/invoices/<invoiceId>" \
  -H "Authorization: Bearer $FINERO_API_KEY"

3. Create a payment link for an installment (Admin key, has side effects)

Create a hosted payment link for that installment. The response's url is the customer-facing checkout page.

curl -X POST "https://api.getfinero.com/functions/v1/api/v1/payment-links" \
  -H "Authorization: Bearer $FINERO_API_KEY" \
  -H "Idempotency-Key: <unique-key>" \
  -H "Content-Type: application/json" \
  -d '{"invoice_id":"8f14e45f-ceea-4a5b-9d2c-167ce7de1a10","installment_id":"a3c9d2e1-55b4-4c8e-9f01-2b3c4d5e6f70"}'

4. Get a payment link (Admin or Read-only key, no side effects)

Poll the link until its status is paid.

curl "https://api.getfinero.com/functions/v1/api/v1/payment-links/<paymentLinkId>" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Step 3 is the only mutation and requires an Idempotency-Key: if the response is lost, retry with the same key to get the original link back instead of creating a second one. There is no standalone customers resource — customer display fields live on the invoice, and confirmed payments are read via /v1/payments.

Errors

Errors share one shape. request_id echoes the X-Request-Id response header — include it when reporting a problem. Validation errors add a details array of { field, message }.

{
  "error": {
    "code": "permission_denied",
    "message": "The API key does not have permission to perform this operation.",
    "request_id": "req_2f7c1a9b3d5e4f60718293a4"
  }
}
CodeStatusRetry?Meaning
missing_credentials401fix requestNo Authorization: Bearer header was sent.
invalid_credentials401fix requestThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists.
revoked_credentials401fix requestThe presented key was revoked. Create a new key in Settings → API.
feature_unavailable403fix requestThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement.
permission_denied403fix requestThe key's permission does not allow this operation (readonly keys cannot call admin-only operations).
not_found404fix requestNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones.
validation_failed400fix requestThe request failed schema validation. See error.details for field messages.
conflict409retryState conflict — e.g. an active payment link already exists for the installment, a sync is already running, or a concurrent identical request is in flight.
idempotency_key_required400fix requestThis operation requires the Idempotency-Key header (1–255 characters).
idempotency_conflict409fix requestThe Idempotency-Key was already used with a DIFFERENT request body. Use a fresh key for a new request.
rate_limit_exceeded429retryToo many requests. Honor the Retry-After header (seconds) before retrying.
payload_too_large413fix requestThe request body exceeds the 64 KiB limit.
method_not_allowed405fix requestThe path exists but not with this HTTP method.
installment_not_collectible422fix requestThe installment cannot be collected right now — it is already paid, disputed, excluded from collections, has no outstanding balance, or its invoice is not collection-ready. GET /v1/invoices/{invoiceId} reports each installment's payment_state, collectible flag, and block reasons.
integration_unavailable422fix requestThe tenant has no connected payments integration able to mint this link, or the one selected is not ready. Connect or repair a payment provider in the Finero app, then retry.
currency_not_supported422fix requestThe selected payment provider cannot collect the invoice's currency (single-currency providers can only charge in their store currency). Use a provider that supports it, or collect the invoice outside Finero.
internal_error500retryUnexpected server error. Safe to retry with the same Idempotency-Key.

Endpoint reference

All examples use fictional data. Replace path placeholders like <invoiceId> with real ids from list responses.

API context

GET
/v1/me
Admin or Read-only key
getApiContext

Identify the calling API key

Returns the tenant and key metadata for the presented credential. Useful as a connectivity/permission check before other calls. No side effects.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/me" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "tenant_id": "5b0f6a7e-2f5d-4d24-9e6b-3c1a2b4d5e6f",
  "tenant_name": "Acme Industries",
  "api_key": {
    "id": "4d3c2b1a-0f9e-48d7-b6c5-a4b3c2d1e0f9",
    "name": "Zapier integration",
    "permission": "readonly",
    "created_at": "2026-07-01T08:00:00+00:00",
    "last_used_at": "2026-07-14T06:59:31+00:00"
  }
}

Response fields

FieldTypeRequiredDescription
tenant_iduuidyesThe tenant this API key belongs to. All data is scoped to it.
tenant_namestringyesTenant display name.
api_key.iduuidyesAPI key id.
api_key.namestringyesKey name given at creation.
api_key.permission"admin" | "readonly"yesadmin can call every operation; readonly only side-effect-free ones.
api_key.created_atdate-timeyesKey creation time (ISO 8601 UTC).
api_key.last_used_atdate-time | nullyesPrevious use of this key (ISO 8601 UTC).

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable

Invoices

GET
/v1/invoices
Admin or Read-only key
listInvoices

List invoices

Lists the tenant's synced invoices, newest first. Cursor-paginated: pass ?limit= (1–100) and follow pagination.next_cursor until has_more is false. Filters are allowlisted; combine freely.

Parameters

FieldTypeRequiredDescription
limit (query)integernoPage size, 1–100. Default 25.
cursor (query)stringnoOpaque pagination cursor from a previous response's pagination.next_cursor.
order (query)"asc" | "desc"noSort direction by creation time. Default desc (newest first).
finalization_state (query)"draft" | "final" | "cancelled" | "unknown"noFilter by the ERP document-lifecycle state (final/draft/cancelled/unknown).
collection_ready (query)booleannoFilter by collection readiness.
currency (query)stringnoFilter by ISO 4217 currency code.
invoice_number (query)stringnoExact-match filter on the ERP invoice number.
connection_id (query)uuidnoFilter by ERP connection.
updated_since (query)date-timenoOnly invoices updated at or after this ISO 8601 timestamp.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/invoices" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "data": [
    {
      "id": "8f14e45f-ceea-4a5b-9d2c-167ce7de1a10",
      "invoice_number": "INV-10421",
      "finalization_state": "final",
      "currency": "USD",
      "total_amount": "1250.0000",
      "open_balance": "1250.0000",
      "invoice_date": "2026-07-01",
      "due_date": "2026-08-01",
      "collection_ready": true,
      "customer": {
        "number": "CUST-2201",
        "name": "Acme Industries Ltd",
        "email": "[email protected]"
      },
      "origin": "erp",
      "connection_id": "1a2b3c4d-5e6f-4a80-91b2-c3d4e5f60718",
      "created_at": "2026-07-01T09:15:00+00:00",
      "updated_at": "2026-07-10T06:30:00+00:00"
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}

Response fields

FieldTypeRequiredDescription
dataarray of objectyesInvoices, newest first.
data[].iduuidyesInvoice id (stable Finero identifier).
data[].invoice_numberstring | nullyesHuman-readable local or ERP invoice number.
data[].finalization_state"draft" | "final" | "cancelled" | "unknown"yesERP document-lifecycle state: final = finalized in the ERP, draft = not yet finalized, cancelled = voided in the ERP, unknown = unmappable source value. Only final invoices are collectible. Not a payment state.
data[].currencystring | nullyesInvoice currency. ISO 4217 alphabetic code, e.g. "USD".
data[].total_amountstring | nullyesInvoice total. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
data[].open_balancestring | nullyesOutstanding balance across the invoice. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
data[].invoice_datedate | nullyesInvoice date (YYYY-MM-DD).
data[].due_datedate | nullyesInvoice due date (YYYY-MM-DD).
data[].collection_readybooleanyesWhether the invoice is eligible for payment-link collection (authoritative readiness flag).
data[].customer.numberstring | nullyesBill-to customer number from the ERP.
data[].customer.namestring | nullyesBill-to customer name.
data[].customer.emailstring | nullyesBilling email the payment-link email is sent to.
data[].origin"local" | "erp"yesProvenance / system of record: local = the invoice exists only in Finero; erp = an ERP connection owns (or will own) the record.
data[].connection_iduuid | nullyesThe exact ERP connection associated with this invoice.
data[].created_atdate-timeyesCreation time (ISO 8601 UTC).
data[].updated_atdate-timeyesLast update time (ISO 8601 UTC).
pagination.next_cursorstring | nullyesOpaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
pagination.has_morebooleanyesWhether another page exists.
pagination.limitintegeryesThe page size that was applied.

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable
GET
/v1/invoices/{invoiceId}
Admin or Read-only key
getInvoice

Get an invoice with its installments

Returns one invoice including its installments (ordered by sequence). Use an installment's id to create a payment link. Returns not_found for ids outside your tenant.

Parameters

FieldTypeRequiredDescription
invoiceId (path)uuidyesInvoice id.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/invoices/<invoiceId>" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "id": "8f14e45f-ceea-4a5b-9d2c-167ce7de1a10",
  "invoice_number": "INV-10421",
  "finalization_state": "final",
  "currency": "USD",
  "total_amount": "1250.0000",
  "open_balance": "1250.0000",
  "invoice_date": "2026-07-01",
  "due_date": "2026-08-01",
  "collection_ready": true,
  "customer": {
    "number": "CUST-2201",
    "name": "Acme Industries Ltd",
    "email": "[email protected]"
  },
  "origin": "erp",
  "connection_id": "1a2b3c4d-5e6f-4a80-91b2-c3d4e5f60718",
  "created_at": "2026-07-01T09:15:00+00:00",
  "updated_at": "2026-07-10T06:30:00+00:00",
  "installments": [
    {
      "id": "a3c9d2e1-55b4-4c8e-9f01-2b3c4d5e6f70",
      "sequence": 1,
      "original_amount": "1250.0000",
      "outstanding_amount": "1250.0000",
      "disputed_amount": "0.0000",
      "due_date": "2026-08-01",
      "source_status": "OPEN",
      "payment_state": "open",
      "collectible": true,
      "excluded_from_collections": false,
      "created_at": "2026-07-01T09:15:00+00:00",
      "updated_at": "2026-07-10T06:30:00+00:00"
    }
  ]
}

Response fields

FieldTypeRequiredDescription
iduuidyesInvoice id (stable Finero identifier).
invoice_numberstring | nullyesHuman-readable local or ERP invoice number.
finalization_state"draft" | "final" | "cancelled" | "unknown"yesERP document-lifecycle state: final = finalized in the ERP, draft = not yet finalized, cancelled = voided in the ERP, unknown = unmappable source value. Only final invoices are collectible. Not a payment state.
currencystring | nullyesInvoice currency. ISO 4217 alphabetic code, e.g. "USD".
total_amountstring | nullyesInvoice total. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
open_balancestring | nullyesOutstanding balance across the invoice. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
invoice_datedate | nullyesInvoice date (YYYY-MM-DD).
due_datedate | nullyesInvoice due date (YYYY-MM-DD).
collection_readybooleanyesWhether the invoice is eligible for payment-link collection (authoritative readiness flag).
customer.numberstring | nullyesBill-to customer number from the ERP.
customer.namestring | nullyesBill-to customer name.
customer.emailstring | nullyesBilling email the payment-link email is sent to.
origin"local" | "erp"yesProvenance / system of record: local = the invoice exists only in Finero; erp = an ERP connection owns (or will own) the record.
connection_iduuid | nullyesThe exact ERP connection associated with this invoice.
created_atdate-timeyesCreation time (ISO 8601 UTC).
updated_atdate-timeyesLast update time (ISO 8601 UTC).
installmentsarray of objectyesThe invoice's installments, ordered by sequence.
installments[].iduuidyesInstallment id — use as installment_id when creating a payment link.
installments[].sequenceintegeryes1-based installment sequence within the invoice.
installments[].original_amountstringyesOriginal installment amount. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
installments[].outstanding_amountstringyesOutstanding (still payable) amount. Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
installments[].disputed_amountstringyesAmount under dispute (blocks collection when > 0). Decimal amount as a string (exact, 4 dp) — never parse as float for arithmetic.
installments[].due_datedate | nullyesInstallment due date (YYYY-MM-DD).
installments[].source_statusstringyesRaw installment status from the ERP.
installments[].payment_state"paid" | "open" | "inactive"yesWhether the money is in: `paid` once the installment is settled (in the ERP, or by a Finero payment the ERP has not synced back yet); `inactive` when payment is no longer expected because the receivable ended — cancelled, voided, credited or written off — so do NOT count it as revenue; otherwise `open`. Note `inactive` is about the MONEY and is distinct from the invoice's `finalization_state: cancelled`, which is the ERP document's own lifecycle. Independent of `collectible` — an open installment can still be uncollectible, and a due date being in the past does not change this field.
installments[].collectiblebooleanyesWhether Finero considers this installment collectible right now. False whenever payment_state is `paid`, and also for open installments blocked by a dispute, an exclusion, a non-final invoice, or a missing billing email.
installments[].excluded_from_collectionsbooleanyesManually excluded from collections.
installments[].created_atdate-timeyesCreation time (ISO 8601 UTC).
installments[].updated_atdate-timeyesLast update time (ISO 8601 UTC).

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable

Payment links

Payments

GET
/v1/payments
Admin or Read-only key
listPayments

List confirmed payments

Lists confirmed payments, newest first. A payment appears here only after the payment provider verifies settlement; payments cannot be created through the API. Cursor-paginated: pass ?limit= (1–100) and follow pagination.next_cursor until has_more is false.

Parameters

FieldTypeRequiredDescription
limit (query)integernoPage size, 1–100. Default 25.
cursor (query)stringnoOpaque pagination cursor from a previous response's pagination.next_cursor.
order (query)"asc" | "desc"noSort direction by creation time. Default desc (newest first).
invoice_id (query)uuidnoFilter by invoice.
payment_link_id (query)uuidnoFilter by payment link.
provider (query)"stripe" | "wix"noFilter by provider.
confirmed_since (query)date-timenoOnly payments confirmed at or after this ISO 8601 timestamp.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/payments" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "data": [
    {
      "id": "7e6d5c4b-3a29-4180-9f8e-7d6c5b4a3928",
      "invoice_id": "8f14e45f-ceea-4a5b-9d2c-167ce7de1a10",
      "installment_id": "a3c9d2e1-55b4-4c8e-9f01-2b3c4d5e6f70",
      "payment_link_id": "0d9c8b7a-6e5f-4d3c-b2a1-908f7e6d5c4b",
      "provider": "stripe",
      "provider_payment_id": "pi_ExampleOnly000000000000",
      "amount_minor": 125000,
      "currency": "USD",
      "mode": "live",
      "status": "confirmed",
      "provider_paid_at": "2026-07-11T14:02:11+00:00",
      "confirmed_at": "2026-07-11T14:02:14+00:00"
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}

Response fields

FieldTypeRequiredDescription
dataarray of objectyesConfirmed payments, newest first.
data[].iduuidyesPayment id.
data[].invoice_iduuidyesInvoice the payment settles.
data[].installment_iduuidyesInstallment the payment settles.
data[].payment_link_iduuidyesThe payment link the payer used.
data[].provider"stripe" | "wix"yesPayment provider.
data[].provider_payment_idstringyesThe provider's payment/transaction identifier.
data[].amount_minorintegeryesSettled amount. Integer amount in the currency's MINOR unit (e.g. cents).
data[].currencystringyesSettled currency. ISO 4217 alphabetic code, e.g. "USD".
data[].mode"test" | "live"yesProvider environment.
data[].status"confirmed"yesPayments appear here only once verified/confirmed by the provider.
data[].provider_paid_atdate-time | nullyesProvider-reported payment time (ISO 8601 UTC).
data[].confirmed_atdate-timeyesWhen Finero confirmed the settlement (ISO 8601 UTC).
pagination.next_cursorstring | nullyesOpaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
pagination.has_morebooleanyesWhether another page exists.
pagination.limitintegeryesThe page size that was applied.

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable
GET
/v1/payments/{paymentId}
Admin or Read-only key
getPayment

Get a payment

Returns one confirmed payment by id, including the provider reference and settlement timestamps.

Parameters

FieldTypeRequiredDescription
paymentId (path)uuidyesPayment id.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/payments/<paymentId>" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "id": "7e6d5c4b-3a29-4180-9f8e-7d6c5b4a3928",
  "invoice_id": "8f14e45f-ceea-4a5b-9d2c-167ce7de1a10",
  "installment_id": "a3c9d2e1-55b4-4c8e-9f01-2b3c4d5e6f70",
  "payment_link_id": "0d9c8b7a-6e5f-4d3c-b2a1-908f7e6d5c4b",
  "provider": "stripe",
  "provider_payment_id": "pi_ExampleOnly000000000000",
  "amount_minor": 125000,
  "currency": "USD",
  "mode": "live",
  "status": "confirmed",
  "provider_paid_at": "2026-07-11T14:02:11+00:00",
  "confirmed_at": "2026-07-11T14:02:14+00:00"
}

Response fields

FieldTypeRequiredDescription
iduuidyesPayment id.
invoice_iduuidyesInvoice the payment settles.
installment_iduuidyesInstallment the payment settles.
payment_link_iduuidyesThe payment link the payer used.
provider"stripe" | "wix"yesPayment provider.
provider_payment_idstringyesThe provider's payment/transaction identifier.
amount_minorintegeryesSettled amount. Integer amount in the currency's MINOR unit (e.g. cents).
currencystringyesSettled currency. ISO 4217 alphabetic code, e.g. "USD".
mode"test" | "live"yesProvider environment.
status"confirmed"yesPayments appear here only once verified/confirmed by the provider.
provider_paid_atdate-time | nullyesProvider-reported payment time (ISO 8601 UTC).
confirmed_atdate-timeyesWhen Finero confirmed the settlement (ISO 8601 UTC).

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable

ERP sync

GET
/v1/erp-connections
Admin or Read-only key
listErpConnections

List ERP connections

Lists the tenant's ERP connections (safe status metadata only — never credentials, hosts, or configuration). Read-only visibility: connecting, configuring, and syncing are managed inside the Finero app.

Parameters

FieldTypeRequiredDescription
limit (query)integernoPage size, 1–100. Default 25.
cursor (query)stringnoOpaque pagination cursor from a previous response's pagination.next_cursor.
order (query)"asc" | "desc"noSort direction by creation time. Default desc (newest first).

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/erp-connections" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "data": [
    {
      "id": "1a2b3c4d-5e6f-4a80-91b2-c3d4e5f60718",
      "provider": "oracle_fusion",
      "status": "connected",
      "last_sync_at": "2026-07-14T05:00:04+00:00",
      "auto_sync_enabled": true,
      "auto_sync_interval_minutes": 60,
      "created_at": "2026-06-20T11:00:00+00:00"
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}

Response fields

FieldTypeRequiredDescription
dataarray of objectyesERP connections.
data[].iduuidyesERP connection id — use as connection_id when starting a sync run.
data[].provider"oracle_fusion"yesERP system this connection syncs from.
data[].status"connected" | "requires_reauthentication" | "temporarily_unavailable" | "disconnected"yesConnection health.
data[].last_sync_atdate-time | nullyesLast successful sync completion (ISO 8601 UTC).
data[].auto_sync_enabledbooleanyesWhether scheduled auto-sync is on.
data[].auto_sync_interval_minutesintegeryesScheduled auto-sync cadence in minutes.
data[].created_atdate-timeyesCreation time (ISO 8601 UTC).
pagination.next_cursorstring | nullyesOpaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
pagination.has_morebooleanyesWhether another page exists.
pagination.limitintegeryesThe page size that was applied.

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable
GET
/v1/sync-runs
Admin or Read-only key
listSyncRuns

List sync runs

Lists ERP sync runs, newest first. Cursor-paginated: pass ?limit= (1–100) and follow pagination.next_cursor until has_more is false.

Parameters

FieldTypeRequiredDescription
limit (query)integernoPage size, 1–100. Default 25.
cursor (query)stringnoOpaque pagination cursor from a previous response's pagination.next_cursor.
order (query)"asc" | "desc"noSort direction by creation time. Default desc (newest first).
connection_id (query)uuidnoFilter by ERP connection.
status (query)"running" | "success" | "partial" | "failed"noFilter by run status.
direction (query)"pull" | "push"noFilter by sync direction. Only `pull` matches new runs; `push` matches historical runs recorded before outbound sync was removed.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/sync-runs" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "data": [
    {
      "id": "3f2e1d0c-9b8a-4756-8493-21f0e9d8c7b6",
      "connection_id": "1a2b3c4d-5e6f-4a80-91b2-c3d4e5f60718",
      "direction": "pull",
      "trigger": "manual",
      "status": "success",
      "started_at": "2026-07-14T05:00:04+00:00",
      "finished_at": "2026-07-14T05:00:41+00:00",
      "items_processed": 36,
      "items_failed": 0,
      "error_summary": null
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}

Response fields

FieldTypeRequiredDescription
dataarray of objectyesSync runs, newest first.
data[].iduuidyesSync run id — poll GET /v1/sync-runs/{syncRunId} until status is terminal.
data[].connection_iduuidyesThe ERP connection that ran.
data[].direction"pull" | "push"yesSync direction. Every new run is `pull` — Finero no longer writes invoices back to an ERP. `push` remains in the enum because historical runs carry it.
data[].trigger"manual" | "scheduled"yesHow the run started. API-started runs are `manual`.
data[].status"running" | "success" | "partial" | "failed"yesrunning is non-terminal; success/partial/failed are terminal.
data[].started_atdate-timeyesRun start time (ISO 8601 UTC).
data[].finished_atdate-time | nullyesRun finish time (null while running) (ISO 8601 UTC).
data[].items_processedintegeryesInvoices processed.
data[].items_failedintegeryesInvoices that failed to process.
data[].error_summarystring | nullyesCategorical failure summary (never raw provider payloads).
pagination.next_cursorstring | nullyesOpaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
pagination.has_morebooleanyesWhether another page exists.
pagination.limitintegeryesThe page size that was applied.

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable
GET
/v1/sync-runs/{syncRunId}
Admin or Read-only key
getSyncRun

Get a sync run

Returns one ERP sync run (read-only operational visibility). Syncs are started from within Finero — the public API cannot trigger synchronization.

Parameters

FieldTypeRequiredDescription
syncRunId (path)uuidyesSync run id.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/sync-runs/<syncRunId>" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "id": "3f2e1d0c-9b8a-4756-8493-21f0e9d8c7b6",
  "connection_id": "1a2b3c4d-5e6f-4a80-91b2-c3d4e5f60718",
  "direction": "pull",
  "trigger": "manual",
  "status": "success",
  "started_at": "2026-07-14T05:00:04+00:00",
  "finished_at": "2026-07-14T05:00:41+00:00",
  "items_processed": 36,
  "items_failed": 0,
  "error_summary": null
}

Response fields

FieldTypeRequiredDescription
iduuidyesSync run id — poll GET /v1/sync-runs/{syncRunId} until status is terminal.
connection_iduuidyesThe ERP connection that ran.
direction"pull" | "push"yesSync direction. Every new run is `pull` — Finero no longer writes invoices back to an ERP. `push` remains in the enum because historical runs carry it.
trigger"manual" | "scheduled"yesHow the run started. API-started runs are `manual`.
status"running" | "success" | "partial" | "failed"yesrunning is non-terminal; success/partial/failed are terminal.
started_atdate-timeyesRun start time (ISO 8601 UTC).
finished_atdate-time | nullyesRun finish time (null while running) (ISO 8601 UTC).
items_processedintegeryesInvoices processed.
items_failedintegeryesInvoices that failed to process.
error_summarystring | nullyesCategorical failure summary (never raw provider payloads).

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable

Workflows

GET
/v1/workflow-executions
Admin or Read-only key
listWorkflowExecutions

List workflow executions

Audit trail of the tenant's automation runs (payment-link automation + email notification): what ran, what was skipped, and why — with stable machine-readable reason codes. Cursor-paginated: pass ?limit= (1–100) and follow pagination.next_cursor until has_more is false.

Parameters

FieldTypeRequiredDescription
limit (query)integernoPage size, 1–100. Default 25.
cursor (query)stringnoOpaque pagination cursor from a previous response's pagination.next_cursor.
order (query)"asc" | "desc"noSort direction by creation time. Default desc (newest first).
workflow_type (query)"payment_link_automation" | "email_notification"noFilter by workflow type.
status (query)"pending" | "processing" | "succeeded" | "skipped" | "failed"noFilter by outcome.
invoice_id (query)uuidnoFilter by invoice.

Example request

curl "https://api.getfinero.com/functions/v1/api/v1/workflow-executions" \
  -H "Authorization: Bearer $FINERO_API_KEY"

Success response (200)

{
  "data": [
    {
      "id": "6c5d4e3f-2a1b-4c9d-8e7f-0a1b2c3d4e5f",
      "workflow_type": "payment_link_automation",
      "invoice_id": "8f14e45f-ceea-4a5b-9d2c-167ce7de1a10",
      "installment_id": "a3c9d2e1-55b4-4c8e-9f01-2b3c4d5e6f70",
      "payment_link_id": "0d9c8b7a-6e5f-4d3c-b2a1-908f7e6d5c4b",
      "trigger_reason": "invoice_synced",
      "status": "succeeded",
      "reason_code": null,
      "reason_message": null,
      "started_at": "2026-07-10T06:31:00+00:00",
      "finished_at": "2026-07-10T06:31:01+00:00"
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}

Response fields

FieldTypeRequiredDescription
dataarray of objectyesWorkflow executions, newest first.
data[].iduuidyesWorkflow execution id.
data[].workflow_type"payment_link_automation" | "email_notification"yesWhich automation ran.
data[].invoice_iduuid | nullyesRelated invoice.
data[].installment_iduuid | nullyesRelated installment.
data[].payment_link_iduuid | nullyesRelated payment link.
data[].trigger_reasonstringyesWhat triggered the run.
data[].status"pending" | "processing" | "succeeded" | "skipped" | "failed"yesOutcome of this execution.
data[].reason_codestring | nullyesCategorical reason for a skip/failure (stable machine-readable code).
data[].reason_messagestring | nullyesHuman-readable reason.
data[].started_atdate-timeyesExecution start (ISO 8601 UTC).
data[].finished_atdate-time | nullyesExecution finish (ISO 8601 UTC).
pagination.next_cursorstring | nullyesOpaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
pagination.has_morebooleanyesWhether another page exists.
pagination.limitintegeryesThe page size that was applied.

Errors

StatusCodeWhen it happens · what to do
400validation_failedThe request failed schema validation. See error.details for field messages. → fix the request
401invalid_credentialsThe credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. → fix the request
401missing_credentialsNo Authorization: Bearer header was sent. → fix the request
401revoked_credentialsThe presented key was revoked. Create a new key in Settings → API. → fix the request
403feature_unavailableThe tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. → fix the request
403permission_deniedThe key's permission does not allow this operation (readonly keys cannot call admin-only operations). → fix the request
404not_foundNo such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones. → fix the request
429rate_limit_exceededToo many requests. Honor the Retry-After header (seconds) before retrying. → retryable
500internal_errorUnexpected server error. Safe to retry with the same Idempotency-Key. → retryable