Factuarea APIDevelopers

Account webhooks

Receive the events of your account and its tax IDs at one endpoint, with the equivalence table against company webhooks.

A company webhook endpoint hears about one tax ID. An account webhook endpoint hears about your whole account: the events of every tax ID it holds, the events of the accounts you provision for your clients, and the account.* events of the account itself, such as a member joining or a tax ID arriving by transfer. One endpoint, one signing secret and one delivery history replace a company endpoint for each tax ID.

It is a different resource, not a rename. It lives under /v1/accounts/{account}/webhooks, it has its own cap per plan tier and its own rules about who can manage it, and it signs and retries like a company endpoint. This guide covers what it receives, who can manage it, the account.* catalog and the envelope, the equivalence table against company endpoints, retries, tests, rotation of the secret, the cap per tier, the account request logs and what stays out.

What an account endpoint receives

An endpoint receives an event only when it is active, it subscribes to the event type, its account_relationship filter admits the event and its environment is the environment of the event. Then the subject of the event decides:

The event is aboutIt reaches the endpoint when
A tax ID of your accountThe tax ID still belongs to your account. One that leaves it stops sending events, except the events that announce its departure.
A tax ID of an account you manageYour account provisioned that account, the management is in force, your access level is not none and the tax ID is inside the scope of the key that created the endpoint.
The account itself (account.*)The family of the event lets it through.
A tax ID of an account that granted you accessNever. A granted access is not followed by webhooks, so those tax IDs do not enter.

An endpoint created from the web app has no key. For the tax IDs of a managed account, what counts then is what the person who created it reaches in the environment of the endpoint.

The account_relationship filter

ValueThe endpoint hears about
ownThe tax IDs of your account.
managedThe accounts your account manages.
allBoth. It is the default.

You set it when you create the endpoint and change it with PATCH. Every delivery carries its own account_relationship, own or managed and never all: it tells you how that event relates to your account, not how the endpoint is set up.

The events about the relation itself, such as account.management_ended, still reach the provider whose management has just ended or dropped to none, because the event is the relation.

The environment of the endpoint

An endpoint belongs to one account and one environment, live or test. The credential or the session that creates it fixes the environment, an environment sent in the body is ignored and it never changes. A live endpoint never receives events of the test environment and a test endpoint never receives live ones: the events of a managed test account reach only test endpoints.

A test endpoint never reaches the network. Each delivery is recorded with its envelope, stays pending with attempt set to 0, and you read it with a fact_test_ key in the deliveries of the endpoint. A test key cannot create or change endpoints, and a live key does not see a test one, so you create a test endpoint in the web app in test mode and the API only reads it. Test managed accounts follows the whole path, from creating the endpoint to reading its deliveries.

Who can manage an endpoint

Having the webhooks:* scope is not enough. On every request to an account webhook or request log route, reads included, Factuarea checks this, in this order:

  1. The account is yours. {account} must be the account of the credential. An account that is not yours, one that your account manages, one that does not exist and a value that is not an identifier all answer the same 404 account_not_found, never a 403.
  2. Writes need a live credential. A fact_test_ key reads, but it does not create, change, rotate, test, retry or delete, not even on a test account.
  3. The person who issued the key is an owner or admin of the account today. It is read again on every request, so demoting that person cuts off the keys they issued on the next call. A key issued by a member fails here, whatever grants it has.
  4. The tax ID scope of the key covers every tax ID of the account. A key narrowed with scoped_company_ids to a part of the account does not manage account webhooks.

The third and the fourth answer the same 403 forbidden_action with the same message, so the answer does not reveal which of the two failed.

A test key that tries to write gets a 403, and nothing is created or changed. It is insufficient_scope when the key carries no write scope, which is the usual case because a test key is not issued one, module_not_available_in_sandbox over the API when it carries one anyway, and live_credential_required over the MCP server.

The MCP tools apply the same checks and add one: they work only with an API key. A connection through OAuth does not list the twelve tools of account webhooks and request logs, and calling one answers 403 forbidden_action.

The endpoint is checked again on every delivery

Before each delivery Factuarea applies the rules of what an endpoint receives again, so a delivery never leaves on the strength of a past decision:

  • If the endpoint should no longer receive it, for instance because the tax ID left the account, the management ended or you unsubscribed the type, the delivery becomes cancelled with its cancel_reason, nothing is posted and its payload is dropped.
  • If the creator lost the capability, the endpoint itself is disabled with disabled_reason: "creator_lost_capability", the change is audited and the delivery is cancelled with nothing posted. The person who created it stopped being an owner or admin, or, for events of your own tax IDs, the key that created it was revoked, expired or no longer covers every tax ID of the account.

A disabled endpoint can be turned on again. Send PATCH with status: active: whoever reactivates it becomes its creator, so the endpoint is checked against that person or that key from then on. You do not need to delete it and create another one. While it is disabled it keeps its place in the cap per tier and the list still shows its disabled_reason. An endpoint created with an API key depends on that key for the events of your own tax IDs, so create your endpoints with a key that you keep: revoking it or letting it expire disables the endpoint on its next such delivery.

Create an endpoint

curl -X POST https://api.factuarea.com/v1/accounts/{account}/webhooks \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/factuarea-account",
    "description": "Alerts of the account.",
    "enabled_events": ["invoice.created", "account.member_added"],
    "account_relationship": "all"
  }'

The answer is a 201 with the canonical URL of the endpoint in the Location header. The secret is returned only once:

{
  "data": {
    "id": "01933b70-8a41-7c3e-9d52-4b6e8f1a2c01",
    "object": "account_webhook",
    "environment": "live",
    "url": "https://example.com/hooks/factuarea-account",
    "enabled_events": ["invoice.created", "account.member_added"],
    "account_relationship": "all",
    "status": "active",
    "disabled_reason": null,
    "api_version": "2026-09-23",
    "description": "Alerts of the account.",
    "created_at": "2026-09-28T10:15:00+00:00",
    "updated_at": "2026-09-28T10:15:00+00:00",
    "secret": "whsec_01HKQS5N8VR7QXJ9K3T6BWPMZA9876543210ABCDEF"
  }
}
  • url is an HTTPS URL of up to 2048 characters.
  • enabled_events needs at least one type, and it mixes the company events of the public catalog with the account.* events. An unknown, reserved or unreleased type answers 422 and nothing is created. A company endpoint cannot subscribe to account.* events.
  • account_relationship is own, managed or all, the default.
  • description is optional, up to 255 characters.
  • api_version is a YYYY-MM-DD date. Without it, the endpoint is pinned to the latest version at the time of creation. An unsupported version answers 422.
  • The environment is never a field. The endpoint is born in the environment of the credential.
  • Idempotency-Key is optional on create and on update, and required on deleting, rotating the secret, testing and retrying.

The other operations of the endpoint work like this:

  • List. GET /v1/accounts/{account}/webhooks lists the endpoints of the environment of the credential with cursor pagination: limit from 1 to 100, 25 by default, and starting_after. ending_before is not accepted and answers 400 parameter_unknown.
  • Update. PATCH changes url, enabled_events, account_relationship, description or api_version. The fields you omit keep their value, and description: null clears the description.
  • Delete. DELETE stops the endpoint at once, cancels its queued and failed deliveries and answers 204. It cannot be undone.
  • Not found. An endpoint that does not exist, was deleted or belongs to another account or environment answers the same 404 webhook_endpoint_not_found.

The signing secret is never part of the endpoint you read again. To get a new one, rotate it.

The account.* catalog

There are 15 account-level events. They are not in GET /v1/event-catalog, which lists the company events only. Their names are the AccountEventType schema of the reference, and only account endpoints can subscribe to them.

Eventdata.objectFields of data.object
account.member_addedaccount_memberobject, id, user_id, email, role, previous_role (null)
account.member_removedaccount_memberThe same fields as account.member_added.
account.member_role_changedaccount_memberThe same fields, with previous_role set to the previous role.
account.owner_transferredaccount_ownerobject, user_id, previous_user_id
account.member_grant_changedaccount_member_grantobject, member_id, company_id, level, previous_level. One name for a grant given, changed and removed.
account.access_grantedaccount_relationobject, id, origin, level, previous_level, grantor_account_id, grantee_account_id, status
account.access_revokedaccount_relationThe same fields. It covers a revocation, a renunciation and the end of a management. A rejected invitation is not published.
account.access_level_changedaccount_relationThe same fields, with previous_level set to the previous level.
account.managed_account_provisionedaccount_relationThe fields of account_relation plus managed_account_id and external_ref.
account.managed_account_claimedaccount_relationThe same fields as account.managed_account_provisioned.
account.management_endedaccount_relationThe same fields as account.managed_account_provisioned.
account.nif_addedcompanyobject, id, tax_id, name. It covers a tax ID created and one registered.
account.nif_transferredcompanyThe fields of company plus direction, in or out.
account.nif_archivedcompanyThe fields of company, with no direction.
account.import_completedmanaged_account_importobject, id, stats

Every identifier in data.object is an opaque UUID v7 and never an internal one. The granted access guide and the managed accounts guide say what these events mean in their own flows.

Who hears each event

The family of an event decides whether it can leave the account it happens in:

  • Members, ownership, grants and import completion stay in their account. They never reach the provider of a managed account.
  • Tax ID events (account.nif_added, account.nif_transferred and account.nif_archived) also reach the provider that manages the account, within the scope of the key that created the endpoint.
  • Access and management events reach the provider only when the relation is a provisioning one. The access that an account grants to another stays with the granting account, and the receiving account is sent nothing about it.

What is not published

  • The client takes over the payment. The provisioned relation becomes a granted access and no account.* event is published. The provider simply stops receiving the events of that account. To notice it, read GET /v1/accounts/{account}, which answers 404 once the management is no longer in force, or look for the account in client_accounts of GET /v1/me with origin: "granted", which needs the privileged accounts:read scope.
  • A change of the tax IDs of a granted access. Its effects reach you as tax IDs that enter or leave, not as an event of their own.
  • A tax ID that is deleted or administratively excluded. The account catalog has no name for them: a deleted tax ID is already announced by its own company event, and an excluded one does not change owner.
  • A rejected invitation. It was never an access, so there is no access to end.

The envelope and its headers

The body of each delivery is the envelope of a company event plus account, account_relationship and company_id. All eleven fields are always present:

FieldWhat it carries
idThe identifier of the event (UUID v7), exactly as it is stored: the same event of a tax ID carries the same id in the company envelope and in the account one. See deduplication.
typeAn account.* type or, for an event of a tax ID forwarded to the account, a type of the company catalog.
api_versionThe version (YYYY-MM-DD) in which data is shaped.
createdWhen the event happened, as a Unix timestamp in seconds.
livemodetrue for the live environment, false for the test one.
testtrue only on a synthetic event sent by the test operation. It has nothing to do with livemode.
correlation_idA UUID v7 that follows the event from the operation that caused it, or null when the event has no correlation context.
accountThe account of the endpoint, as { "id": … } with its UUID v7.
account_relationshipown or managed: how the event relates to your account.
company_idThe UUID v7 of the tax ID the event is about, or null in the account events that are not about a tax ID.
data{ "type", "object" }. For a company event, the same data the company webhook carries.

An account event about a member, as delivered to an endpoint:

{
  "id": "01933b70-f2c3-7a15-b8d4-6e9a1b3c4e03",
  "type": "account.member_added",
  "api_version": "2026-09-23",
  "created": 1790590561,
  "livemode": true,
  "test": false,
  "correlation_id": "01933b70-e5a1-7b2c-9d3e-4f5a6b7c8d90",
  "account": { "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a00" },
  "account_relationship": "own",
  "company_id": null,
  "data": {
    "type": "account.member_added",
    "object": {
      "object": "account_member",
      "id": "01933b70-c4d2-7e6a-a1b3-7d8e9f0a1b04",
      "user_id": "01933b70-c4d2-7e6a-a1b3-7d8e9f0a1b05",
      "email": "marta@acme.example",
      "role": "member",
      "previous_role": null
    }
  }
}

Every delivery carries these headers:

Factuarea-Signature: t=1747314060,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Factuarea-Event-Id: 01933b70-f2c3-7a15-b8d4-6e9a1b3c4e03
Factuarea-Event-Type: account.member_added
Factuarea-Delivery-Id: 01933b71-1f0a-7d4b-8e63-5c7f9a2b3d02
Idempotency-Key: 01933b70-f2c3-7a15-b8d4-6e9a1b3c4e03
Factuarea-Account-Relationship: own
HeaderValue
Factuarea-SignatureThe HMAC signature of the body, made like the one of a company endpoint. Webhooks explains how to verify it.
Factuarea-Event-IdThe id of the event.
Factuarea-Event-TypeThe name of the event.
Factuarea-Delivery-IdThe UUID of the delivery.
Idempotency-KeyThe same value as Factuarea-Event-Id.
Factuarea-Account-Relationshipown or managed, as in the envelope.

Equivalence with company webhooks

Every operation of an account endpoint has its twin on the company axis, except ping. The scope is the same on both axes. The first table pairs the routes, and the second one the names that the SDKs, the CLI and the MCP server use. Both keep the same order.

Account routeCompany routeScope
GET /v1/accounts/{account}/webhooksGET /v1/companies/{company}/webhook-endpointswebhooks:read
POST /v1/accounts/{account}/webhooksPOST /v1/companies/{company}/webhook-endpointswebhooks:write
GET /v1/accounts/{account}/webhooks/{webhook}GET /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}webhooks:read
PATCH /v1/accounts/{account}/webhooks/{webhook}PATCH /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}webhooks:write
DELETE /v1/accounts/{account}/webhooks/{webhook}DELETE /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}webhooks:delete
GET /v1/accounts/{account}/webhooks/{webhook}/deliveriesGET /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/deliverieswebhooks:read
GET /v1/accounts/{account}/webhooks/{webhook}/deliveries/{delivery}GET /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/deliveries/{delivery}webhooks:read
POST /v1/accounts/{account}/webhooks/{webhook}/deliveries/{delivery}/retryPOST /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/deliveries/{delivery}/replaywebhooks:write
POST /v1/accounts/{account}/webhooks/{webhook}/secretPOST /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/rotate-secretwebhooks:write
POST /v1/accounts/{account}/webhooks/{webhook}/testPOST /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/test-eventwebhooks:write
No equivalentPOST /v1/companies/{company}/webhook-endpoints/{webhook_endpoint}/pingwebhooks:write
GET /v1/accounts/{account}/request-logsGET /v1/companies/{company}/request-logsdevelopers:read
GET /v1/accounts/{account}/request-logs/{request_id}GET /v1/companies/{company}/request-logs/{request_id}developers:read
Account operationAccount toolCompany operationCompany tool
public-api.v1.account.webhooks.listlist_account_webhookspublic-api.v1.webhook_endpoints.listsearch_webhook_endpoints
public-api.v1.account.webhooks.createcreate_account_webhookpublic-api.v1.webhook_endpoints.createcreate_webhook_endpoint
public-api.v1.account.webhooks.showget_account_webhookpublic-api.v1.webhook_endpoints.showget_webhook_endpoint
public-api.v1.account.webhooks.updateupdate_account_webhookpublic-api.v1.webhook_endpoints.updateupdate_webhook_endpoint
public-api.v1.account.webhooks.deletedelete_account_webhookpublic-api.v1.webhook_endpoints.deletedelete_webhook_endpoint
public-api.v1.account.webhooks.deliveries.listlist_account_webhook_deliveriespublic-api.v1.webhook_endpoints.deliveries.listlist_webhook_deliveries
public-api.v1.account.webhooks.deliveries.showget_account_webhook_deliverypublic-api.v1.webhook_endpoints.deliveries.showget_webhook_delivery
public-api.v1.account.webhooks.deliveries.retryretry_account_webhook_deliverypublic-api.v1.webhook_endpoints.deliveries.replayreplay_webhook_delivery
public-api.v1.account.webhooks.rotate_secretrotate_account_webhook_secretpublic-api.v1.webhook_endpoints.rotate_secretrotate_webhook_secret
public-api.v1.account.webhooks.testtest_account_webhookpublic-api.v1.webhook_endpoints.test_eventtest_webhook_endpoint
No equivalentNo equivalentpublic-api.v1.webhook_endpoints.pingping_webhook_endpoint
public-api.v1.account.request_logs.listlist_account_request_logspublic-api.v1.developers.request_logs.listlist_developers_request_logs
public-api.v1.account.request_logs.showget_account_request_logpublic-api.v1.developers.request_logs.showget_developers_request_logs

Four differences that are not a name

  • Only your own account. {account} is always the account of your credential. A provider does not administer the webhooks or the request logs of the accounts it manages through this path: it receives their events at its own endpoint with the managed filter. Who can manage an endpoint has the answer.
  • An issuer that is owner or admin, and a scope that covers the whole account. A company endpoint needs the scope and access to the tax ID in the path. An account endpoint also needs the person who issued the key to be an owner or admin today and the key to reach every tax ID of the account.
  • No OAuth. The twelve account tools are for API keys only. The company webhook tools are also reachable through OAuth.
  • Writes only with a live credential. A test key reads the test environment and never writes here.

retry is not replay, and there is no ping

  • retry re-arms the same delivery. It keeps its id and its counters, attempt stays and manual_retry_count grows. There is at most one delivery for each endpoint and event, so a retry never produces a second one.
  • replay creates a new delivery. On a company endpoint it queues a new delivery row, with attempt: 1, for the same event and endpoint.
  • ping has no account equivalent. It sends a synthetic webhook.ping. On an account endpoint you use test, which simulates one of the types the endpoint subscribes to, account.* included.

Other differences in the fields: an account endpoint has account_relationship and no ip_allowlist, metadata, custom_headers or timeout_seconds. The account test does not store the synthetic event anywhere, while the company test-event records a real event. The account request logs have no environment parameter, because the environment is the one of the credential.

Deliveries, retries and manual retry

A delivery is one event sent to one endpoint. Its status is one of these:

StatusWhat it means
pendingQueued or waiting for its next attempt. On a test endpoint it stays here for good, with attempt 0: it is recorded and never sent.
deliveredYour server answered with a 2xx.
failedA recoverable failure. The next attempt is scheduled in next_retry_at.
failed_permanentlyThe attempts ran out or the destination refused the delivery. You can retry it by hand.
cancelledAborted and final. cancel_reason says why and payload is null.

Your server has 10 seconds to answer. Factuarea retries a 5xx, a timeout and a 408, 425 or 429. It does not retry any other 4xx, nor a destination that its outbound security checks refuse: they end in failed_permanently at once. The account endpoints use the same schedule as the company ones, with 8 attempts in total:

AttemptDelay after the previous one
1immediate
21 minute
35 minutes
430 minutes
52 hours
612 hours
71 day
83 days

Each delay varies by up to ±10 %. After the last attempt the delivery is failed_permanently. Deliveries are kept for 90 days, and the events behind them for 30 days.

GET /v1/accounts/{account}/webhooks/{webhook}/deliveries lists them oldest first, with limit, starting_after and an optional status filter. To look for recent failures, filter by status=failed or failed_permanently and keep following starting_after until has_more is false. Each delivery shows the event, the tax ID (company_id), its relationship with your account, the counters, what your server answered (response_status and a truncated response_body) and the signed payload that was sent.

Retry a delivery

curl -X POST https://api.factuarea.com/v1/accounts/{account}/webhooks/{webhook}/deliveries/{delivery}/retry \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

It answers 202 and the same delivery goes back to pending, to be sent again with the current secret:

{
  "data": {
    "id": "01933b71-9c2d-7e5f-a674-6d8f0b3c4e06",
    "object": "account_webhook_delivery",
    "status": "queued"
  }
}

Only failed and failed_permanently deliveries can be retried. A delivered, pending or cancelled one answers 422 with the subcode account_webhook_retry_not_allowed, and a delivery of a disabled endpoint answers 422 with account_webhook_endpoint_not_active. A delivery or an endpoint that your account does not see answers 404 webhook_delivery_not_found. It needs a live key and an Idempotency-Key, and it has its own limit: 30 requests per minute.

Send a test delivery

POST /v1/accounts/{account}/webhooks/{webhook}/test queues a signed test delivery, marked test: true in the envelope, to check that your endpoint is reachable and that your signature verification works:

curl -X POST https://api.factuarea.com/v1/accounts/{account}/webhooks/{webhook}/test \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "type": "account.member_added" }'
{
  "data": {
    "id": "01933b71-1f0a-7d4b-8e63-5c7f9a2b3d02",
    "object": "account_webhook_delivery",
    "event_id": "01933b70-f2c3-7a15-b8d4-6e9a1b3c4e03",
    "test": true,
    "status": "queued"
  }
}
  • type is optional. Without it, Factuarea uses the first type the endpoint subscribes to. If you give one, the endpoint must subscribe to it, or the answer is 422 with the subcode event_not_subscribed. account.* types are valid.
  • The event is synthetic. It is not stored in any event log and it reaches only this endpoint, but the delivery it creates is stored: you read the result in the deliveries of the endpoint.
  • A disabled endpoint answers 422 with the subcode account_webhook_endpoint_not_active.
  • On a test endpoint nothing goes out to the network and the delivery stays pending with attempt 0.
  • Limit: 10 requests per minute, with a live key and an Idempotency-Key.

Both limits, the test and the retry, are counted for each credential and its owning company, on top of the general limit of your tier. A request over them answers 429. Rate limits explains the general limit.

Rotate the secret

curl -X POST https://api.factuarea.com/v1/accounts/{account}/webhooks/{webhook}/secret \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

The answer is a 200 with the endpoint and the new secret, returned once. For 24 hours the previous secret keeps signing too: each delivery carries two v1 values in Factuarea-Signature, one for each secret, exactly as in a company endpoint. Deploy the new secret inside that window and your receiver never drops a delivery. Its verification accepts the request if any v1 matches.

A second rotation less than 5 minutes after the last one answers 422 business_rule_violation with the subcode webhook_secret_recently_rotated, and changes nothing. Rotating is irreversible, so it needs an Idempotency-Key. A replay of the same request with the same key returns secret: null, because the secret is never stored.

The cap per tier

The number of account endpoints depends on the tier of whoever pays for the account, not on the tier of the credential that creates the endpoint. For a managed account that its provider pays, that is the tier of the provider. It is counted for each account and each environment, apart from the company endpoints, and it includes the disabled ones.

TierGiven byAccount endpoints per environment
FreeThe trial0
StarterThe Emprendedor plan1
ProThe Empresario plan10
ScaleThe Enterprise plan50

The webhooks:read, webhooks:write and webhooks:delete scopes belong to the outgoing webhooks module (integration_webhooks), which the Empresario and Enterprise plans include. On the Emprendedor plan, the one that gives the Starter tier, a key cannot carry them, so its single account endpoint is created and managed from the web app, not through the API.

Rate limits describes the tiers. Creating an endpoint can fail in two ways:

{
  "error": {
    "type": "payment_required_error",
    "code": "addon_required",
    "subcode": "account_webhooks_addon_required",
    "message": "El plan de pago de tu cuenta no permite crear endpoints de webhook de cuenta. Contrata un plan que los incluya.",
    "doc_url": "https://docs.factuarea.com/guides/errors#addon_required",
    "request_id": "req_7d2f8b01e3c45a7b9f1d2e3c4b"
  }
}
{
  "error": {
    "type": "invalid_request_error",
    "code": "account_webhook_endpoint_limit_reached",
    "message": "Has alcanzado el máximo de 1 endpoint de webhook de cuenta del tier starter. Mejora tu plan para añadir más.",
    "doc_url": "https://docs.factuarea.com/guides/errors#account_webhook_endpoint_limit_reached",
    "request_id": "req_8e3a9c12f4d56b8c0a2e3f4d5c"
  }
}

Only deleting an endpoint frees a place. An endpoint of a company does not use the cap of the account, and the endpoint of another account does not either.

Account request logs

Two operations show what has been called with the API keys of your account, so you can debug an integration without opening a support ticket:

They need the developers:read scope and the same checks as the endpoints. What makes them different from the company logs:

  • They aggregate every key of the account, and never those of another account. The company logs show only the requests of one tax ID.
  • The environment is the one of the credential. A live key sees the live traffic and a test key the test traffic. There is no environment parameter, and sending it or ending_before answers 400 parameter_unknown.
  • Rows are purged after 30 days. It is a window for debugging, not an audit trail.

The filters are the ones of the company listing: method[], status_range[], only_errors, api_key_prefix, path_search, created_at[gte] and created_at[lte], together with limit and starting_after.

curl "https://api.factuarea.com/v1/accounts/{account}/request-logs?only_errors=true&limit=25" \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"
{
  "data": [
    {
      "request_id": "req_01JQZP8K4M9N2T5V7X0Y3B6D8F",
      "object": "api_request_log",
      "api_key_prefix": "01931b3e",
      "method": "POST",
      "path": "/v1/companies/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a01/invoices",
      "status_code": 422,
      "duration_ms": 143,
      "ip": "203.0.113.24",
      "user_agent": "factuarea-cli/0.1.3",
      "error_type": "invalid_request_error",
      "error_code": "invalid_param_value",
      "factuarea_version": "2026-09-23",
      "environment": "live",
      "created_at": "2026-09-28T09:30:12+00:00"
    }
  ],
  "has_more": true,
  "next_cursor": "184320"
}

api_key_prefix is the first 8 characters of the identifier of the key that made the call, enough to tell which of your keys it was. The query string is never stored.

Company endpoints, logs and events on a tax ID reached through a relation

The eleven operations of …/webhook-endpoints, the two of …/request-logs and the two of …/events (list and show) on the company axis belong to the account that owns the tax ID. When you reach a tax ID through a relation between accounts, because another account granted it to you or because it belongs to a managed account, they answer 403 forbidden_action before anything is read or changed, at any access level. The MCP tools of those operations answer the same, list_events and get_event among them. On your own tax IDs they keep their contract.

To follow the tax IDs of the accounts you manage, use an account endpoint with the managed or all filter.

The history of emails is not exposed by account either. There is no GET /v1/accounts/{account}/emails, no detail and no indicators. Read it tax ID by tax ID with GET /v1/companies/{company}/emails and the emails:read scope.

From the MCP server

The twelve tools of the tables above mirror the operations of account webhooks and request logs, one by one. The ten webhook tools form the AccountWebhook domain of the catalog and the two log tools are listed with the PublicApi ones. Each needs the scope of the operation it mirrors, works only with an API key and applies the checks of who can manage an endpoint. Deleting an endpoint and rotating its secret are irreversible operations. MCP tools lists the whole catalog.

On this page

Need a hand?Contact support