Fence API Integration Guide API v2

Fence · Developer Documentation

Client Integration Guide

Integrate with Fence to declare assets, register supporting documents and report payment transactions, and to read back what Fence holds for your facility: assets, metric values and generated reports. This guide covers authentication, the declaration pipeline, document verification, reading data back, and error handling for the v2 API.

AudienceTechnical integration teams API Versionv2 Active Base URLhttps://dev-api.fence.finance

01 Getting Started

Fence is a tech-native facility agency for asset-backed finance. The API lets your systems declare portfolio assets, attach verification documents, and record payment transactions against a credit facility in real time. It also lets them read data back out of Fence: the assets Fence holds (see Section 6), the facility’s metrics (see Section 7) and its reports (see Section 8).

1.1 Environments

Fence provides two environments. All API paths in this guide are relative to the environment base URL.

EnvironmentBase URLPurpose
Sandbox https://dev-api.fence.finance Integration testing. Non-production data; safe to experiment.
Production https://api.fence.finance Live environment.

For example, /v2/{deal_id}/documents resolves to https://dev-api.fence.finance/v2/{deal_id}/documents in Sandbox. Use the environment toggle in the top bar to switch every example to your target environment.

1.2 Facility Scope

Each facility is identified in Fence by a deal_id — a UUID that scopes requests to that facility. Most endpoints include {deal_id} as a path parameter. Fence will provide separate deal_id values for the Sandbox and Production environments during onboarding.

The login endpoint (POST /v1/login/access-token) is the exception: it does not take a deal_id. Authentication is performed with client_id + client_secret, and the returned token is implicitly scoped to the facilities your account is linked to.

1.3 Credentials

API credentials (client_id + client_secret) and your deal_id are provisioned by Fence per environment. To request them, contact your Fence onboarding representative. Fence will provide the credentials in a secure way during onboarding.


02 Authentication

Fence uses OAuth 2.0. Machine-to-machine integrations should use the Client Credentials grant.

Obtaining an Access Token

The login endpoint does not require a deal_id. Authentication is performed with client_id + client_secret, and the returned token is implicitly scoped to the deals your account is linked to.

Client Credentials Grant (recommended for machine-to-machine integrations):

POST https://dev-api.fence.finance/v1/login/access-token
HTTP Request
POST /v1/login/access-token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id={your_client_id}
&client_secret={your_client_secret}
Response200 OK
{
  "access_token": "eyJraWQiOi...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Using the Token

Include the token in every subsequent request:

Header
Authorization: Bearer {access_token}

Authorization Model

Clients are authorized at the deal level. Your credentials grant access only to the deals your account is linked to.

  • Actions: read, write, create, declare — each endpoint requires a specific action.
  • Attempting to access a deal you're not authorized for returns 403 Forbidden.

03 Asset Declaration

3.1 Overview

Asset declaration is the process of submitting your portfolio of assets (e.g., loans, receivables, advances) to Fence. Fence validates, persists, and processes these assets through a configurable pipeline that can include eligibility checks, borrow base calculations, and expected payment generation.

Declaration is a single call: POST /v2/declarations creates the declaration, adds the assets and triggers the pipeline together. Use the run id it returns to monitor progress.

3.2 Declaration Flow

A single endpoint that creates the portfolio declaration, adds the assets, and triggers the pipeline in one call.

Up to 50,000 assets per request. Above that the call returns 400 and nothing is created — send a larger book as several declarations.

POST https://dev-api.fence.finance/v2/declarations
Request Body
{
  "deal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "dry_run": false,
  "assets": [
    {
      "asset_external_id": "ADV-2026-001234",
      "document_external_ids": [],
      "origination_installment_id": "INS-78901",
      "organization_name": "Acme Corp",
      "employee_id": "EMP-456",
      "user_state": "CA",
      "user_country": "US",
      "total_principal_amount": 800.00,
      "total_fee_amount": 12.00,
      "outstanding_amount": 812.00,
      "transaction_date": "2026-04-01",
      "due_date": "2026-04-15",
      "currency": "USD",
      "status": "active"
    }
  ]
}
Response · 202 Accepted
{
  "id": "f55928c9-0e3d-4f2b-9a71-6c1d5e8b04af",
  "status": "queued",
  "dry_run": false
}

The 202 Accepted means the declaration has been queued for asynchronous processing. Use id as the run_id in the monitoring endpoints below.

Batching recommendation. The declaration queue processes declarations for a given deal sequentially. Each declaration has fixed infrastructure overhead, so sending many single-asset declarations will create significant backlog. Instead, batch assets over a period (e.g., every 15 minutes, hourly, or daily depending on your reporting needs) and send them in a single declaration.

3.3 Monitoring Declaration Progress

List Declaration Runs for a Deal

GET https://dev-api.fence.finance/v2/declarations?deal_id={deal_id}&page=1&page_size=100

Declaration Run Statuses:

StatusDescription
queuedDeclaration received, waiting for processing.
processingPipeline is actively processing assets.
completedAll pipeline steps finished successfully. All assets are declarable.
completed_with_errorsPipeline finished but some assets are not declarable (e.g., failed eligibility). Check per-asset results.
failedPipeline encountered a critical error. Check error_details.

Get a Specific Declaration Run

GET https://dev-api.fence.finance/v2/declarations/{run_id}

List Per-Asset Results

GET https://dev-api.fence.finance/v2/declarations/{run_id}/assets?page=1&size=50

Per-Asset Result Statuses:

StatusMeaning
successfulAsset passed this pipeline step.
unsuccessfulAsset was processed but did not meet the criteria (e.g., failed eligibility). Still created but flagged.
failedAn error occurred processing this asset at this step.

Pipeline Steps:

Step NameDescription
validationSchema, type and mutability checks. Carries the per-field diffs when a locked field is rejected.
persistenceCreates or updates the asset in Fence.
intake_derivationDerives expected payments and related intake records from the declared asset.
borrow_baseEvaluates the asset for borrowing base inclusion, where the facility has one.

Get a Single Asset Result

GET https://dev-api.fence.finance/v2/declarations/{run_id}/assets/{asset_id}

3.4 Dry Run Mode

Declarations support dry_run: true. In dry-run mode:

  • The full validation pipeline runs (schema validation, eligibility checks, borrow base).
  • No data is persisted — assets are not created/updated, no expected payments are generated.
  • Results are still available via the monitoring endpoints.

Use this to validate your data before committing.

Recommended workflow:

  1. Submit a declaration with dry_run: true.
  2. Inspect per-asset results for validation issues.
  3. Fix any issues in your source data.
  4. Submit again with dry_run: false.

04 Document Declaration

For deals that require verification, Fence validates each receivable against supporting portfolio documents (e.g., loan agreements, repayment authorizations, invoices). Clients register documents in batch, upload the files to S3 using the returned presigned URLs, and Fence processes them asynchronously.

document_external_id is the join key Fence uses to reconcile each document with its declared asset at verification time. The value convention (e.g., matching a specific asset field) is agreed during onboarding.

4.1 Document Registration

Register one or more documents in a single call. Fence creates the document records and returns presigned S3 URLs the client PUTs the file bytes to.

POST https://dev-api.fence.finance/v2/{deal_id}/documents
Request Body
{
  "documents": [
    {
      "document_category": "loan_agreement",
      "document_external_id": "DOC-2026-001234",
      "file_name_with_ext": "agreement.pdf",
      "title": "Loan Agreement - Acme Borrower"
    }
  ]
}

Request Field Reference:

FieldTypeRequiredDescription
document_category string Yes Category of the document (e.g., loan_agreement, invoice, repayment_authorization). Agreed during onboarding.
document_external_id string Yes Client-provided unique identifier. Used as the join key to reconcile this document with its declared asset during verification; the specific value convention is agreed during onboarding.
file_name_with_ext string Yes Filename including extension (e.g., agreement.pdf).
title string No Human-readable title. Defaults to filename if omitted.
Response201 Created
{
  "documents": [
    {
      "document_external_id": "DOC-2026-001234",
      "presigned_url": "https://s3.amazonaws.com/...",
      "expires_at": "2026-04-07T11:00:00Z",
      "uploaded_at": null
    }
  ]
}

For each document in the response, PUT the file bytes to the returned presigned_url before expires_at. Presigned URLs are valid for 1 hour from issuance.

PUT {presigned_url}
Re-registering with an existing document_external_id returns 422 Unprocessable Entity. To retry an upload whose URL has expired or whose PUT failed, use Section 4.2 Upload Status to request a fresh presigned URL — do not re-register the document.

4.2 Upload Status

Use this endpoint for two purposes: (1) confirming Fence has received each file from S3, and (2) retrieving a fresh presigned URL for any document that has not yet been uploaded.

uploaded_at is populated once Fence registers the S3 event. Until then, each call to this endpoint returns a newly-signed presigned_url with a fresh expires_at one hour in the future, so you can safely retry uploads that failed or whose URL has expired without re-registering the document.

GET https://dev-api.fence.finance/v2/{deal_id}/documents?document_external_ids=DOC-2026-001234,DOC-2026-001235
Response200 OK
{
  "documents": [
    {
      "document_external_id": "DOC-2026-001234",
      "presigned_url": null,
      "expires_at": null,
      "uploaded_at": "2026-04-07T10:15:32Z"
    },
    {
      "document_external_id": "DOC-2026-001235",
      "presigned_url": "https://s3.amazonaws.com/...",
      "expires_at": "2026-04-07T11:00:00Z",
      "uploaded_at": null
    }
  ]
}

Two mutually exclusive states are returned per document:

StateFields populatedMeaning
Pending presigned_url · expires_at; uploaded_at is null Document registered but not yet uploaded. The URL is freshly-signed on every call — retry as needed.
Uploaded uploaded_at; presigned_url and expires_at are null File has been received by Fence. No new URL will ever be issued for this document — the record is now immutable for verification.

Unrecognized document_external_id values are silently omitted from the response (no error). The endpoint is safe to call repeatedly; it has no side effects on the document record.


05 Payment Transaction Declaration

Payment transactions represent financial movements associated with a deal — intakes (incoming payments), expenses, repayments, outbound transfers, dispositions, and more.

Base URL — all payment transaction endpoints are scoped to a deal:

https://dev-api.fence.finance/v2/{deal_id}/payments

5.1 Bulk Create

Create multiple payment transactions in a single request. The processing mode is controlled by the dry_run query parameter:

POST https://dev-api.fence.finance/v2/{deal_id}/payments/bulk?dry_run=false
Request Body
{
  "data": [
    {
      "external_id": "TXN-20260407-001",
      "amount": 812.00,
      "transaction_date": "2026-04-07T14:30:00Z",
      "currency": "USD",
      "transaction_type": "intake",
      "from_": "Borrower Account",
      "to_": "SPV Collection Account",
      "memo": "Repayment for advance ADV-2026-001234",
      "bank_account_id": "e5f6a7b8-c9d0-1234-ef56-7890abcdef01",
      "metadata": {
        "metadata_type": "intake",
        "type": "repayment_collection"
      }
    }
  ]
}

Query Parameters:

ParameterTypeDefaultDescription
dry_run bool true If true, validates without persisting (synchronous 200). If false, validates and enqueues for async processing (202). Set to false explicitly to create transactions.

Transaction Types

TypeDescriptionMetadata Type
intakeIncoming payment to the deal (collections, deposits)intake
intake_metaMetadata-only intake (no financial movement)intake_meta
expenseFee or expense charged to the dealexpense
repaymentRepayment from borrower to lenderrepayment
outboundOutgoing payment from the dealoutgoing_type
dispositionAsset disposition event—
borrowBorrowing/draw eventborrow
utilizationFacility utilization eventutilization
waterfall_paymentWaterfall distribution payment—
outgoing_typeGeneral outgoing paymentoutgoing_type

Transaction Fields

FieldTypeRequiredDescription
external_idstringYesYour unique identifier for this transaction.
amountfloatYesTransaction amount.
transaction_datedatetimeYesWhen the transaction occurred.
currencystringYesISO currency code (e.g., "USD").
transaction_typestringNoOne of the transaction types above.
from_stringNoSource account identifier.
to_stringNoDestination account identifier.
memostringNoDescription or notes.
bank_account_idUUIDNoAssociated bank account in Fence.
ibanstringNoRecipient IBAN.
routing_numberstringNoRecipient routing number (when no IBAN).
account_numberstringNoRecipient account number (when no IBAN).
metadataobjectNoType-specific metadata (see below).

Metadata by Transaction Type

Intake
{ "metadata_type": "intake", "type": "repayment_collection" }
Repayment
{ "metadata_type": "repayment", "repayment_type": "scheduled" }
Expense
{
  "metadata_type": "expense",
  "category": "servicing",
  "description": "Monthly servicing fee"
}
Borrow
{
  "metadata_type": "borrow",
  "borrow_type": "initial_draw",
  "tranche_name": "Tranche A"
}
Utilization
{
  "metadata_type": "utilization",
  "utilization_type": "draw",
  "tranche_name": "Tranche A"
}
Outgoing Type
{
  "metadata_type": "outgoing_type",
  "outgoing_type": "distribution",
  "payment_date": "2026-04-07T00:00:00Z"
}
All metadata types accept an optional deal_specific_metadata dict for custom fields.

06 Reading Assets

Read back the assets Fence holds for your facility, using your own identifier: the asset_external_id you sent when declaring. Use these endpoints to check that Fence’s view of your book matches yours.

Each record is flat, like the declaration request: Fence’s own fields (such as id and created_at) sit next to your facility’s fields as top-level keys. Which facility fields appear follows the field dictionary agreed during onboarding.

6.1 List Assets

GET https://dev-api.fence.finance/v2/{deal_id}/assets?page=1&size=50

Query Parameters:

ParameterTypeRequiredDescription
contract_external_idstringNoOnly the assets that belong to this contract.
fieldsstringNoComma-separated list of facility fields to return, for example outstanding_amount,status. id, deal_id and created_at are always returned. If omitted, every field is returned.
pageintNoPage number, starting at 1. Default 1.
sizeintNoItems per page. Default 50.

Your facility may support more filters on its own fields. These are agreed during onboarding. An invalid filter value returns 422.

Response200 OK
{
  "items": [
    {
      "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
      "deal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "created_at": "2026-04-01T09:12:44Z",
      "asset_external_id": "ADV-2026-001234",
      "origination_installment_id": "INS-78901",
      "organization_name": "Acme Corp",
      "total_principal_amount": 800.00,
      "total_fee_amount": 12.00,
      "outstanding_amount": 812.00,
      "transaction_date": "2026-04-01",
      "due_date": "2026-04-15",
      "currency": "USD",
      "status": "active"
    }
  ],
  "total": 1,
  "page": 1,
  "size": 50,
  "pages": 1
}

The list is paginated with page and size; see Pagination. Use fields to keep large pages small.

6.2 Get an Asset

GET https://dev-api.fence.finance/v2/{deal_id}/assets/{asset_external_id}

Returns one asset, with the same fields as an item of the list above. Returns 404 if no asset with this asset_external_id exists for the deal.


07 Reading Metrics

Fence calculates a set of metrics for each facility, for example outstanding principal, borrowing base, concentration limits or covenant tests, and stores every reading with the date it applies to. These are the same figures shown in the Fence dashboard. The endpoints below let your systems read them.

7.1 Overview

A metric definition describes one figure: its name, description and status. A metric value is one stored reading of that figure for a given as_of_date. The usual flow is:

  1. List the metric definitions for your deal and keep the id of the ones you need.
  2. Read the latest value of each, or its history over a date range.
  3. Optionally, read the explanation of how a metric is calculated.
The metrics endpoints use the /v3 path prefix, not /v2. Authentication is the same: send the access token from Section 2. They return values Fence has already stored. Reading them never triggers a new calculation.
These endpoints are not paginated: each returns a plain JSON array. When reading value history, always send a date range (see 7.4) so the response stays small.

7.2 List Metric Definitions

Returns the metric definitions for the deals your credentials can access.

GET https://dev-api.fence.finance/v3/metrics?deal_id={deal_id}

Query Parameters:

ParameterTypeRequiredDescription
deal_idUUIDNoLimit the list to this deal. Repeat the parameter for several deals (?deal_id=…&deal_id=…). If omitted, metrics for every deal you can access are returned. A deal_id you cannot access returns 403.
namestringNoLimit the list to metrics with this exact name. Can be repeated.
Response200 OK
[
  {
    "id": "3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90",
    "name": "outstanding_principal",
    "status": "core",
    "description": "Total outstanding principal of the eligible portfolio.",
    "metadata": {}
  }
]

Use the metrics whose status is core: these are the facility’s live figures, updated on Fence’s regular schedule. The list can also return metrics with other statuses. They are not meant for integrations, so ignore them.

7.3 Get the Latest Value

Returns the most recent stored reading of one metric.

GET https://dev-api.fence.finance/v3/metrics/{metric_definition_id}/values/latest
Response200 OK
{
  "id": "9b8c7d6e-5f4a-4b3c-8d2e-1f0a9b8c7d6e",
  "name": "outstanding_principal",
  "metric_definition_id": "3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90",
  "deal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "value": { "value": 1250000000, "decimals": 2, "currency": "USD" },
  "as_of_date": "2026-10-15T00:00:00Z",
  "value_type": "amount",
  "metadata": null
}

In this example the amount is 1250000000 / 10^2 = 12,500,000.00 USD. See 7.6 Value Types. Returns 404 if the metric has no stored value yet, or if the metric does not exist or belongs to a deal you cannot access.

7.4 List Value History

Returns the stored readings of one metric, filtered by date.

GET https://dev-api.fence.finance/v3/metrics/{metric_definition_id}/values?as_of_date_gte=2026-09-01T00:00:00Z&as_of_date_lte=2026-09-30T23:59:59Z

Query Parameters (all optional, ISO 8601 date-time):

ParameterTypeRequiredDescription
as_of_date_gtedatetimeNoReadings whose as_of_date is on or after this moment.
as_of_date_ltedatetimeNoReadings whose as_of_date is on or before this moment.
created_at_gtedatetimeNoReadings that Fence stored on or after this moment. Use it to fetch only what is new since your last sync.
created_at_ltedatetimeNoReadings that Fence stored on or before this moment.

The response is an array of the same objects as in 7.3. Without any filter it returns the metric’s full history.

as_of_date is the date the figure describes. created_at is when Fence stored it. Fence can store a corrected reading for a past date, so to stay in sync, poll with created_at_gte set to the time of your previous poll.

You can also fetch a single reading by its id: GET /v3/metrics/{metric_definition_id}/values/{metric_value_id}.

7.5 Get a Metric Explanation

Returns how a metric is calculated: where its data comes from, the formula, and the meaning of each term.

GET https://dev-api.fence.finance/v3/metrics/{metric_definition_id}/explanation
Response200 OK
{
  "metric_definition_id": "3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90",
  "description": "Total outstanding principal of the eligible portfolio.",
  "data_source": "Declared assets",
  "formula_latex": "\\sum_{i} P_i",
  "sub_formula_latex": null,
  "terms": [
    {
      "key": "P_i",
      "label": "Outstanding principal",
      "description": "Outstanding principal of eligible asset i.",
      "metric_definition_id": null
    }
  ],
  "steps": [
    "Select the eligible assets.",
    "Add up their outstanding principal."
  ]
}

Formulas are written in LaTeX. When a term is itself another metric, its metric_definition_id is set so you can follow it. Not every metric has an explanation yet. Those return 200 with a null body.

7.6 Value Types

The shape of value depends on value_type. Compare value_type without regard to case.

value_typeShape of value
amountObject {"value": int, "decimals": int, "currency": string}. The amount is value / 10^decimals. Integers avoid rounding errors.
numberA number, for example a count of assets.
percentageA number. Check the metric’s description for whether it is a ratio (0.05) or a percentage (5).
booleantrue or false, for example whether a covenant test passes.
datetimeAn ISO 8601 date-time string.
*_per_entityamount_per_entity, number_per_entity, percentage_per_entity, datetime_per_entity: an object whose keys are entities (for example a country, an originator or a tranche) and whose values have the shape of the base type above.
time_seriesA series of dated points. The exact shape depends on the metric and is agreed during onboarding.

value can be null when the metric ran but had nothing to measure on that date, for example when no assets were in scope.


08 Downloading Reports

Fence generates reports for each facility, for example borrowing base certificates, portfolio tapes or covenant reports. Which reports exist depends on the facility and is agreed during onboarding. Downloading one takes two calls: list the reports available for your deal, then request a download link for the one you want.

8.1 List Available Reports

GET https://dev-api.fence.finance/v2/{deal_id}/reports/available
Response200 OK
[
  {
    "report_name": "borrowing_base_certificate",
    "report_description": "Borrowing base certificate as of a given date.",
    "report_type": "excel",
    "report_params": [
      {
        "name": "as_of_date",
        "description": "Date the report is calculated for.",
        "input_type": "date",
        "options": null
      }
    ]
  }
]

Each report lists the parameters it accepts in report_params. input_type is one of text, date, number or boolean. When options is set, the value must be one of those options. report_type is the file format: pdf, excel (.xlsx), csv or txt.

8.2 Download a Report

Generates the report and returns a temporary link to the file.

POST https://dev-api.fence.finance/v2/{deal_id}/reports/download
Request Body
{
  "report_name": "borrowing_base_certificate",
  "params": [
    { "name": "as_of_date", "value": "2026-09-30" }
  ]
}
FieldTypeRequiredDescription
report_namestringYesA report_name from 8.1.
paramslist of objectsNoOne {"name", "value"} pair per parameter. value is always a string, whatever the input_type: send dates as "YYYY-MM-DD", numbers as "100" and booleans as "true" or "false".
Response200 OK
{
  "url": "https://s3.amazonaws.com/...",
  "expiration": 3600
}

Send a GET request to url to download the file. The link is valid for expiration seconds (one hour). After that, call this endpoint again for a new link.

Fence generates the report while the request is open, so large reports can take a while to respond. Set a generous client timeout and do not retry in a tight loop.

Errors:

CodeMeaning
400A parameter is missing or has an invalid value. The message says which.
403You cannot access this deal, or this report is not available to your account.
404No report with this report_name exists for this deal.

09 Schemas Reference

Canonical request and response shapes for the declaration, read-back, metrics and reports endpoints. Responses can include fields not listed here. Ignore any field you do not recognise.

Asset Declaration — Request

FastTrackDeclarationApiInput
deal_idUUIDRequired
dry_runbooleanDefault: false
assetslist of objectsRequired, min 1 item, max 50,000 per request. Each asset object is flat: the facility's fields are top-level keys. Base fields: asset_external_id (string, required, max 100 chars) and document_external_ids (list of string, optional). Unknown fields are ignored silently, so a misspelled field is dropped rather than rejected. contract_external_id is facility-dependent: some facilities require it, others set it themselves and ignore what you send. The field dictionary for your facility is agreed during onboarding.

Portfolio Declaration Response

PortfolioDeclarationApiResponse
idUUID
deal_idUUID
namestring | null
asset_countinteger | null
created_atdatetime
updated_atdatetime

Declaration Run Response

DeclarationRunDetailApiResponse
idUUID
portfolio_declaration_idUUID
dry_runboolean
status"queued" | "processing" | "completed" | "completed_with_errors" | "failed"
summaryobject | null
error_detailsobject | null
started_atdatetime | null
completed_atdatetime | null
created_atdatetime | null
updated_atdatetime | null

Per-Asset Result Response

DeclarationRunAssetResultApiResponse
asset_idUUID
external_asset_idstring
contract_external_idstring | null
propertiesobject | null
is_eligibleboolean | null
is_declarableboolean | null
resultslist of AssetResultApiResponseEach result: id (UUID), step_name (string), status ("successful" | "unsuccessful" | "failed"), details (object | null).

Asset (read)

Asset
idUUIDFence’s id for the asset.
deal_idUUID
created_atdatetime
asset_external_idstringYour identifier, as declared.
…facility fieldsYour facility’s fields as top-level keys, following the field dictionary agreed during onboarding.

Paginated List

Page
itemslist of objects
totalinteger | null
pageinteger
sizeinteger
pagesinteger | null

Metric Definition Response

MetricDefinitionApiResponse
idUUID
namestring
statusstringUse metrics with "core". Ignore any other value.
descriptionstring | null
metadataobject | null

Metric Value Response

MetricValueApiResponse
idUUID
namestringName of the metric definition.
metric_definition_idUUID
deal_idUUID
valueany | nullShape depends on value_type. See 7.6.
as_of_datedatetime | null
value_typestring | null
metadataobject | null

Metric Explanation Response

MetricExplanationApiResponse
metric_definition_idUUID
descriptionstring
data_sourcestring
formula_latexstring
sub_formula_latexstring | null
termslist of objectsEach term: key, label, description (strings), metric_definition_id (UUID | null).
stepslist of string

Available Report

ReportSchema
report_namestring
report_descriptionstring
report_type"pdf" | "excel" | "csv" | "txt"
report_paramslist of objects | nullEach parameter: name, description (strings), input_type ("text" | "date" | "number" | "boolean"), options (list of string | null).

Report Download — Request

ReportDownloadBodySchema
report_namestringRequired
paramslist of objects | nullEach: name (string), value (string).

Report Download — Response

DocumentResponse
urlstringTemporary download link.
expirationintegerSeconds the link stays valid (3600).

Supported Currencies

54 ISO currency codes are accepted in the currency field.

ALLARSAUDBGNBOBBRLBZDCADCHFCLPCNYCOPCRCCZKDKKEGPEURGBPGELGTQHKDHUFIDRILSINRISKJPYKHRKRWLAKLKRMADMKDMVRMXNMYRNOKNZDPABPENPHPPLNPYGRONRSDSEKSGDTHBTRYTZSUSDUYUVNDZAR

10 Error Handling

HTTP Status Codes

CodeMeaning
200Success (synchronous operations).
201Resource created successfully.
202Accepted — async processing started.
400Bad request — validation error in request body.
401Unauthorized — invalid or expired token.
403Forbidden — you don't have access to this deal/resource.
404Resource not found.
422Unprocessable Entity — validation error (e.g., duplicate document_external_id, missing file extension).
409Conflict. Returned when a facility configured for streaming is declared through an endpoint that does not support it; the message names the endpoint to use.
500Internal server error.

Pagination

The declaration endpoints in section 3 paginate as follows. The asset list in section 6 takes size (default 50) instead and ignore page_size. The metrics and reports endpoints in sections 7 and 8 are not paginated: they return a plain array.

ParameterTypeDefaultDescription
pageint1Page number (1-indexed).
page_sizeint100Items per page, maximum 1000; above that the call returns 422. Note the asymmetry: the request parameter is page_size, while the response reports it back as size.

Response includes: total, page, size, pages.

Idempotency

  • Assets: external_id is the idempotency key. Re-declaring an asset with the same external_id performs an upsert (updates mutable fields, preserves immutable ones).
  • Payment Transactions: external_id should be unique per transaction.
  • Documents: document_external_id is unique per deal. Re-registering returns 422; use Section 4.2 Upload Status to retrieve a fresh presigned URL for any pending document.

Recommended Polling Strategy

For asset declarations and bulk payment batches:

  1. Poll GET /v2/declarations/{run_id} every 10–30 seconds.
  2. Check the status field.
  3. Once completed, completed_with_errors or failed, inspect per-asset results if needed.
  4. Typical processing time depends on portfolio size (seconds for small batches, minutes for large portfolios).

For document uploads, poll GET /v2/{deal_id}/documents (see Section 4.2) every 5–10 seconds until uploaded_at is populated. Each poll on a pending document returns a fresh presigned URL, so if a PUT fails you can retry immediately with the URL from the next poll.