Merchant audit trail

List the audit trail of a merchant in the Tokeflow Dashboard — who changed what, when, from where, and whether the action succeeded.

The audit trail is the merchant's immutable activity log. Every meaningful change inside a merchant — a connector created, an API key revoked, a webhook endpoint updated, a routing profile edited — is recorded as an audit log entry that captures the entity affected, the action performed, who (or what) performed it, the state before and after the change, and whether the action succeeded.

The Dashboard's Activity view for a merchant is powered by the single endpoint on this page. Entries are append-only and cannot be edited or deleted, which makes the trail suitable for compliance reviews and incident forensics — the recorded fields align with PCI DSS audit-logging requirements, including the explicit outcome of each event.

This page covers the merchant-scoped trail. Organization-wide activity (spanning all merchants plus org-level entities) lives at Organization audit trail, and programmatic access with API keys is available through the public Audit logs API.

This endpoint powers the Tokeflow Dashboard UI. It is authenticated with a Dashboard session (JWT bearer) obtained by signing in — see Dashboard authentication. It does not accept sk_/pk_ API keys.

The audit log entry object

FieldTypeDescription
idstringAudit log ID (UUID).
organization_idstring | nullOrganization the event belongs to, prefixed org_.
merchant_idstring | nullMerchant the event belongs to, prefixed mrc_.
entity_typestringType of entity affected (e.g. merchant_connector).
entity_idstring | nullID of the affected entity.
actionstringAction performed (e.g. created).
actor_typestringType of actor. One of user, system, api_key, psp_webhook.
actor_idstring | nullActor ID (user or API key). Null for anonymous or purely internal events.
before_stateobject | nullState before the change. Null on creation.
after_stateobject | nullState after the change. Null on deletion.
outcomestringOutcome of the event. One of success, failure.
error_messagestring | nullError message when outcome is failure.
ip_addressstring | nullClient IP address the action originated from.
created_atstringTimestamp of the audit event (ISO 8601 UTC).

The before_state / after_state pair is what makes an entry reviewable: diff the two objects to see exactly which fields changed. A created entry has before_state: null; a deleted entry has after_state: null.

Actor types

ValueMeaning
userA signed-in Dashboard user performed the action.
systemTokeflow itself performed the action (e.g. an automated lifecycle transition).
api_keyThe action came through the public API, authenticated with an API key.
psp_webhookThe change was triggered by a notification from a connected payment provider.

Endpoints

GET/api/v1/merchant/activity

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Returns a paginated list of audit trail entries for the merchant, newest first. The merchant context comes from the x-merchant-id header, which the Dashboard sends for the currently selected merchant.

Headers

HeaderRequiredDescription
x-merchant-idYesThe merchant whose audit trail to list, prefixed mrc_. The signed-in user must be a member of this merchant.

Query parameters

FieldTypeRequiredDescription
pagenumberNoPage number, 1-indexed (default 1, min 1).
limitnumberNoItems per page (default 20, min 1, max 100).

Example request

curl -G https://api.tokeflow.com/api/v1/merchant/activity \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs…" \
  -H "x-merchant-id: mrc_123" \
  --data-urlencode "page=1" \
  --data-urlencode "limit=20"

Example response200 OK

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "organization_id": "org_123",
      "merchant_id": "mrc_123",
      "entity_type": "merchant_connector",
      "entity_id": "conn_a1b2c3",
      "action": "created",
      "actor_type": "user",
      "actor_id": "9c1de2f4-77aa-4b0e-9a3d-2f6c8b1e5d90",
      "before_state": null,
      "after_state": {
        "provider_slug": "acquirer_a",
        "status": "active"
      },
      "outcome": "success",
      "error_message": null,
      "ip_address": "203.0.113.42",
      "created_at": "2026-08-10T14:22:05.000Z"
    },
    {
      "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "organization_id": "org_123",
      "merchant_id": "mrc_123",
      "entity_type": "webhook_endpoint",
      "entity_id": "whe_5f8d2c",
      "action": "updated",
      "actor_type": "api_key",
      "actor_id": "b2f7c9a1-4e3d-4a6b-8c5e-1d9f0a7b3c62",
      "before_state": {
        "url": "https://example.com/webhooks/old"
      },
      "after_state": null,
      "outcome": "failure",
      "error_message": "Webhook endpoint URL failed validation",
      "ip_address": "198.51.100.7",
      "created_at": "2026-08-10T13:58:41.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "total_pages": 3,
    "has_next": true,
    "has_prev": false
  }
}

Unlike the public API envelope, this dashboard endpoint returns the payload directly — an array of entries in data and the pagination metadata in meta.

Pagination metadata

FieldTypeDescription
pagenumberCurrent page number.
limitnumberNumber of items per page.
totalnumberTotal number of items.
total_pagesnumberTotal number of pages.
has_nextbooleanWhether there is a next page.
has_prevbooleanWhether there is a previous page.

Failed actions are recorded too. An entry with outcome: "failure" means the attempt was denied or errored — error_message explains why, and the target entity was left unchanged. Do not filter these out when reviewing security-relevant activity; failed attempts are often the interesting ones.


Errors

HTTPtypeTypical cause
400validation_errorpage or limit outside the allowed range.
401authentication_errorMissing, expired, or invalid session token — sign in again.
403authorization_errorThe signed-in user is not a member of the merchant in x-merchant-id.

See Errors for the full envelope and type catalog.

On this page