CorebanqCorebanq Developer Docs
Transfersv1Events

List transfer events

List transfer events using the standard get_all query format (search.*, sort, limit, offset, stack).

GET
/v1/transfers/events

Authorization

BearerAuth
AuthorizationBearer <token>

JWT authentication token

In: header

Query Parameters

search.transfer_id?string

Filter by transfer ID

search.event_type?string

Filter by event type (DSL-defined events, or 'status_change' for status change records). Only 'init' and 'complete' are system events.

search.from_status?string

Filter by from_status

search.to_status?string

Filter by to_status

search.created_by?string

Filter by creator user ID

search.error_code?string

Filter by error code

search.error_message?string

Filter by error message

stack?string

Stack response data by a field (e.g. stack=event_type or stack=created_at[YYYY-MM-DD])

sort?string

Sort field (prefix with - for descending). Example: -created_at or event_type

limit?integer

Number of items per page

offset?integer

Starting position for pagination

filter?string

JSON filter object, parsed by the shared parser. Malformed JSON is refused with 400.

search._text?string

Free-text search over the virtual full-row text expression, resolved by the shared parser's ExtractTextSearch. Bare search._text implies the like operator; the operator suffixes accepted are .eq, .like, .ilike, .contains, .start_with and .end_with. More than one of them in a single request is refused with 400, as is any other suffix.

Header Parameters

Accept-Language?string

Language preference for the response

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/transfers/events"
{
  "data": [
    {
      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
      "transfer_id": "d4a2d8dd-7def-4545-a062-761683b9aa05",
      "created_at": "2019-08-24T14:15:22Z",
      "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
      "event_type": "string",
      "from_status": "string",
      "to_status": "string",
      "payload": {},
      "context": {},
      "dsl_trace_id": "string",
      "error_code": "string",
      "error_message": "string"
    }
  ],
  "total": 0,
  "total_unfiltered": 0,
  "has_more": true,
  "keys": [
    "string"
  ]
}
{
  "status": 0,
  "message": "string",
  "code": "transfers_m.account_not_found",
  "class": "validation",
  "retryable": false,
  "details": [
    {
      "field": "amount",
      "rule": "gt",
      "param": "0",
      "message": "amount must be greater than 0"
    }
  ]
}
{
  "status": 0,
  "message": "string",
  "code": "transfers_m.account_not_found",
  "class": "validation",
  "retryable": false,
  "details": [
    {
      "field": "amount",
      "rule": "gt",
      "param": "0",
      "message": "amount must be greater than 0"
    }
  ]
}
{
  "status": 0,
  "message": "string",
  "code": "transfers_m.account_not_found",
  "class": "validation",
  "retryable": false,
  "details": [
    {
      "field": "amount",
      "rule": "gt",
      "param": "0",
      "message": "amount must be greater than 0"
    }
  ]
}
{
  "status": 429,
  "message": "Rate limit exceeded",
  "code": "rate_limits_m.exceeded",
  "class": "temporary",
  "retryable": true
}
{
  "status": 0,
  "message": "string",
  "code": "transfers_m.account_not_found",
  "class": "validation",
  "retryable": false,
  "details": [
    {
      "field": "amount",
      "rule": "gt",
      "param": "0",
      "message": "amount must be greater than 0"
    }
  ]
}

{
  "overall_status": "unhealthy",
  "message": "Service is shutting down",
  "timestamp": "2026-08-27T15:04:05Z"
}

GETGet Transfer Event

NOT IMPLEMENTED. GetTransferEvent ignores the request entirely and answers 501 with a bare {"error": "Not implemented yet"} map — not the apireply envelope, and the key is error rather than message. The 501 is not unconditional: the route goes through auth.WrapWithMiddlewares, so a missing, malformed or expired bearer token is refused with 401, and an RBAC or licence denial with 403, before the stub body is ever produced.

POSTReceive KYT Webhook

NOT IMPLEMENTED, AND UNAUTHENTICATED. The handler ignores the request entirely and answers 501 with a bare {"error": "Not implemented yet"} map — not the apireply envelope, and note the key is error rather than message. It is also the ONLY route in this module registered with a bare HandlerFunc rather than auth.WrapWithMiddlewares: no bearer token, no RBAC check, no licence check, and no signature verification of the body. It can therefore never answer 403. THE 501 IS NOT THE ONLY ANSWER. auth.RateLimitMiddleware is on the root router ahead of the route and refuses requests before the stub runs, whenever rate_limits.rate_limits_switcher is on: - 429 WITH NO TOKEN AT ALL. The anonymous branch increments rate_limit:ip_global:<ip>:POST:/v1/kyt/webhook and answers 429 both past the global IP limit and when the increment itself fails — the ordinary shape of a provider retrying its callbacks from one address. - 401 WITH A TOKEN. The limiter parses the Authorization header itself via checkAuthorization, ahead of auth.Middleware. A valid token takes its authenticated branch into findMatchingEndpoint, which returns errs.New('permission denied').WithCode(401) when no api_permission row matches the method and path — and a route registered bare has no such row. errs.New accepts a plain string as well as a MsgCode and stores it as AppError.Key, which is what MachineCode() returns, so code is NOT empty — it is the same free-text sentence as message. Matchable, but not a dotted key and never translated. - 500 WITH A TOKEN. The same authenticated path answers 500 common.server_error when the limiter's own lookups fail (fetchUserRoles, cacheUserLimits, or findMatchingEndpoint's key search, all WithCode(500)); handleRateLimitError's default branch writes that WITHOUT the AppError, so the specific keys are discarded. With the switcher off the limiter is not in the chain and none of those three can happen. The 503 below comes from a different middleware and is reachable either way. Restrict the route at the ingress if it is exposed at all — the application does not. The path also sits outside the module's own prefix: /v1/kyt/webhook, not /v1/transfers/...