---
title: "List the payment events of a company's connection"
method: GET
path: "/v1/companies/{company_id}/payment-connections/{connection_id}/events"
tags: ["CompanyPaymentEvents"]
---

# List the payment events of a company's connection

`GET /v1/companies/{company_id}/payment-connections/{connection_id}/events`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/companies/{company_id}/payment-connections/{connection_id}/events`
- Auth: HTTP bearer

Lists the payment events received through the payment provider connection of a NIF
(company), most recent first. Use it to audit the charges that produced an invoice and to
find the ones that did not.

- **By default, every event is listed.** Nothing is hidden: events the connection
  skipped, duplicates and disputes are all returned. Narrow the list with the filters
  below; what you do not filter, you get. Set `charges_only=true` to read the same events
  as one row per money movement instead.
- **Scope:** events belong to the connection, not to the NIF directly. The
  `{connection_id}` segment picks one connection of the NIF in the path, and only the
  events of that connection are returned; an event of another NIF of the same account is
  never reachable from here.
- **Unknown connection:** a `{connection_id}` that belongs to no connection of this NIF
  returns `404`.

## Query parameters

- `page` integer
- `limit` integer
- `status` PaymentEventStatus[]
- `failure_reason` string[]
- `failure_category` PaymentEventFailureCategory[]
- `event_kind` PaymentEventType[]
- `min_amount` number
- `max_amount` number
- `needs_action` boolean
- `from` string, date-time
- `to` string, date-time
- `q` string
- `include_discarded` boolean
- `charges_only` boolean

## Response `200`

Payment events of the connection

- ListManagedPaymentEventsResponse
  - `success` boolean
  - `data` object
    - `events` ManagedPaymentEvent[], required
      - `id` string, uuid, required: Identifier of the payment event.
      - `provider` string, required: Payment provider slug (lowercase).
      - `event_type` string, required: Raw event name as the provider emitted it. Preserved verbatim so you can trace the event back on the provider's side. Not filterable — filter by `event_kind`.
      - `event_kind` 'PAYMENT_COMPLETED' | 'PAYMENT_FAILED' | 'REFUND_COMPLETED' | 'DISPUTE_OPENED' | 'DISPUTE_CLOSED' | 'UNKNOWN', required: What a payment event is about, once the provider's own event name has been classified. - `PAYMENT_COMPLETED`: a charge went through - `PAYMENT_FAILED`: a charge was attempted and did not go through - `REFUND_COMPLETED`: money was returned (refund or credit note) - `DISPUTE_OPENED`: the payer disputed a charge - `DISPUTE_CLOSED`: a dispute was settled, in favour of either party - `UNKNOWN`: the provider event does not fall in any of the above
      - `external_event_id` string, required: Provider-side event identifier.
      - `external_payment_id` string, nullable: Canonical identity of the payment at the provider. On Stripe this is always the PaymentIntent id (`pi_…`), so every event of the same payment carries the same value and can be grouped by it. Null while the identity is not yet resolved. To trace the event back to the object that delivered it, use `source_object_id`.
      - `source_object_id` string, nullable: Provider object that delivered this event (`in_…`, `cs_…`, `ch_…`, `pi_…`). Use it to open the originating invoice, checkout session or charge at the provider. It is an audit trail only: it never identifies the payment — `external_payment_id` does.
      - `currency` string, nullable: ISO 4217 currency of the event. Absent on an event that moves no money — a failed intent, or a provider notice we do not classify — and then `amount` is absent too.
      - `amount` number, nullable: Amount the event carries. Absent whenever `currency` is: the two travel together, so an amount never arrives without the currency that gives it meaning.
      - `fee_amount` number, nullable: Provider fee, when reported.
      - `net_amount` number, nullable: Amount net of the provider fee, when reported.
      - `category` 'DIRECT_PAYMENT' | 'SUBSCRIPTION' | 'REFUND' | 'CREDIT_NOTE': Which product line a payment event's money came from. A different axis from `event_kind`, which says what happened: a `checkout.session.completed` is `PAYMENT_COMPLETED` either way, and the category tells you whether it was a one-off checkout or the start of a subscription. - `DIRECT_PAYMENT`: a one-off charge - `SUBSCRIPTION`: a charge produced by a recurring subscription - `REFUND`: money given back - `CREDIT_NOTE`: a credit note issued on the provider's side
      - `money_returned` boolean, nullable: Whether money actually went back to the payer through the provider. Always `true` for a refund. For a credit note it is `true` only when the note settles provider refunds: a note credited against an unpaid invoice, or settled outside the provider, corrects the same amount without moving any money. `null` when the concept does not apply, as on a charge.
      - `customer_email` string, nullable: Payer email reported by the provider.
      - `customer_name` string, nullable: Payer name reported by the provider.
      - `status` 'RECEIVED' | 'PROCESSING' | 'PROCESSED' | 'FAILED' | 'SKIPPED' | 'MANUALLY_RESOLVED', required: Processing status of a payment event. - RECEIVED: queued, awaiting processing - PROCESSING: in flight - PROCESSED: invoice was created (`invoice_id` is set) - FAILED: processing failed (see failure_reason / failure_message) - SKIPPED: filtered out by user rules (see skip_reason) - MANUALLY_RESOLVED: operator marked it as resolved outside BeeL — terminal
      - `invoice_id` string, uuid, nullable: Invoice generated from the event, when there is one.
      - `invoice_number` string, nullable: Number of the invoice generated from the event. `null` while that invoice is still a draft — a draft has no number yet — and `null` when the event produced no invoice.
      - `failure_category` 'USER_CONFIGURATION' | 'PROVIDER_DATA' | 'DOMAIN_RULE' | 'INFRASTRUCTURE' | 'SYSTEM_ERROR': High-level cause of an event that did not complete, so you can tell apart what you can fix from what you cannot. - `USER_CONFIGURATION`: your configuration stopped it (filters, missing series) - `PROVIDER_DATA`: the provider data was insufficient or inconsistent - `DOMAIN_RULE`: an invoicing rule forbade it — permanent, retrying changes nothing - `INFRASTRUCTURE`: a transient failure; retrying may work - `SYSTEM_ERROR`: a defect on our side
      - `failure_reason` string, nullable: Stable failure code you can branch on.
      - `failure_message` string, nullable: Readable explanation of the failure, in the language of the request.
      - `needs_action` boolean, required: Whether the event did not complete and is still worth acting on. Events that failed for reasons outside your control are excluded.
      - `draft_available` boolean, required: Whether a draft invoice can be generated from this event. When `false`, the draft operation would be rejected.
      - `retry_available` boolean, required: Whether retrying this event would be accepted right now. Do not derive it from `status`: a skipped event may still be recoverable, and a failed one with no retries left is not.
      - `discard_available` boolean, required: Whether this event can be discarded — taken out of the list. When `false`, the discard operation would be rejected. An event that is `PROCESSED` or `PROCESSING` cannot be discarded: it has (or is about to have) an invoice that already went through VeriFactu, and hiding it would break the audit trail. Do not derive it from `status`: read this flag. Already-discarded events keep the flag they would have — what applies to them is restore, not discard.
      - `retry_count` integer, required: Retries charged to the event: those that ended in an outcome attributable to it. A retry that failed for a transient cause outside the event is not counted.
      - `received_at` string, date-time, required: When the event was received.
      - `processed_at` string, date-time, nullable: When processing of the event finished.
      - `description` string, nullable: Charge description as the provider reported it. It is what the description filters of the connection match against, so it is what makes them auditable.
      - `payment_method` 'NONE' | 'BANK_TRANSFER' | 'CARD' | 'CASH' | 'CHECK' | 'DIRECT_DEBIT' | 'BIZUM' | 'OTHER': Payment method shown on invoices and recurring invoices. - `NONE`: no payment information is shown. - `BANK_TRANSFER`: bank transfer to the IBAN of the payment details; the only method that requires an IBAN. - `CARD`: card payment. - `CASH`: cash payment. - `CHECK`: payment by cheque. - `DIRECT_DEBIT`: direct debit from the customer's bank account. - `BIZUM`: payment through Bizum. - `OTHER`: any other method.
      - `discarded` boolean, required: Whether the event was discarded (soft-deleted) and is hidden by default.
      - `discarded_at` string, date-time, nullable: When the event was discarded, when it is.
    - `pagination` Pagination
      - `current_page` integer, required
      - `total_pages` integer, required: How many pages the query has. An empty collection has **one** page — the first one, empty — so the smallest value a canonical route returns is `1`. The deprecated flat aliases (`/v1/invoices`, `/v1/customers`, …) answer `0` for that same empty collection, and `has_next`/`has_previous` follow suit. They were left as they were on purpose: a client that reads `total_pages == 0` as "no results" would break if it changed under it. Do not compare the two families of routes field by field; read `total_items` if what you want to know is whether anything came back.
      - `total_items` integer, required
      - `items_per_page` integer, required
      - `has_next` boolean
      - `has_previous` boolean
    - `counts` PaymentEventCounts: How the events of the connection break down, over the whole connection and not just the page you are reading. The filters of the request (`q`, `status`, `needs_action`, dates, amounts and the rest) do not narrow these counts, which may therefore exceed `pagination.total_items`: they are what lets you show "12 need action" without asking for every page. Only two parameters have a bearing on them: `charges_only` changes what is counted (money movements instead of events), and `include_discarded` decides whether discarded events take part in `by_status` and `failure_reasons`.
      - `total` integer, required: Events of the connection that are not discarded — the size of the list you get when you filter by nothing.
      - `discarded` integer, required: Events you discarded. They are not part of `total`; ask for them with `include_discarded=true`.
      - `needs_action` integer, required: Events that are waiting for you to do something — the same set you get with `needs_action=true`. Counts only events that are not discarded, so it is part of `total`. **Deprecated. Retires on 11 December 2026.** Filter with `needs_action=true` and read `pagination.total_items` instead. See the [migration guide](https://docs.beel.es/changelog/payments-cleanup).
      - `ignored` integer, required: Events that were skipped on purpose and need nothing from you (duplicates, your own filters, event types that are not invoiced). Counts only events that are not discarded, so it is part of `total`. **Deprecated. Retires on 11 December 2026.** The closest surviving figure is `by_status.SKIPPED`. See the [migration guide](https://docs.beel.es/changelog/payments-cleanup).
      - `by_status` object, required: Number of events per processing status.
      - `by_failure_reason` object, required: Number of events per failure reason, among those that did not complete. Events that completed do not appear here. **Deprecated. Retires on 11 December 2026.** Use `failure_reasons`, which carries the same counts plus the reason written out for a person. See the [migration guide](https://docs.beel.es/changelog/payments-cleanup).
      - `failure_reasons` PaymentEventFailureReasonCount[], required: Number of events per failure reason, among those that did not complete, with the reason already written out in the language of the request. Events that completed do not appear here. Replaces the deprecated `by_failure_reason`.
        - `code` string, required: Stable identifier of the reason. Branch on this, not on `label`.
        - `label` string, required: The reason written out for a person, in the language of the request.
        - `count` integer, required: Events of the connection with this reason.
  - `meta` ResponseMeta
    - `timestamp` string, date-time
    - `request_id` string

## Other responses

- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: Your account does not own or manage this company. The same answer is given for a NIF that does not exist. That case answers `error.code` `ACTIVE_COMPANY_NOT_ACCESSIBLE`.
- `404`: `CONNECTION_NOT_FOUND` — no connection of this NIF carries this `{connection_id}`. It speaks of the connection, never of the NIF: a NIF you cannot reach answers `403`, while a connection of another NIF answers this same `404` so that naming it reveals nothing.
- `422`: The request cannot be answered as written: - `EVENT_FILTER_RANGE_INVALID`: a range came inverted — `min_amount` above `max_amount`, or `from` after `to`. Both ends are inclusive, so equal values are fine. The range is rejected rather than applied because an inverted one matches nothing, and an empty list would be indistinguishable from having no events.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
