Working across an organization
Discover businesses, read multiple ledgers, and initialize source writes with one organization-level token.
Build reporting and automation across an organization with a service account or an organization app. Both issue organization-level tokens. Financial requests still operate on one entity at a time: your integration selects the entity for each request and combines results when it needs consolidated reporting.
1. Choose authentication and access
Follow Authentication for credentials, consent, token exchange, and renewal.
| Mode | Setup | Renewal |
|---|---|---|
| Service account | Direct access to your own firm’s or organization’s data; production credentials; client_credentials | Request another token; no refresh token is issued |
| Organization app | Create an app with Installs Into → Organization; a user with permission to install organization connections approves OAuth access | Exchange the authorization code, then use the refresh token |
An entity app connects one business at a time and cannot become an organization app by requesting more scopes. Create a new organization-targeted app to adopt organization authorization. For an entity-app sandbox walkthrough, use Quickstart.
Enable ledger:read for financial reads and source:sync if writing source data. The discovery requests below require an organization-level token, with no additional scope. The token's organization determines which businesses are accessible.
Set the token obtained from Authentication:
export DIGITS_ACCESS_TOKEN='<organization_access_token>'2. Discover the entities
An organization owns entities or manages clients. A client is another organization with its own entities. An entity is a business or accounting unit with its own financial data. A client organization ID is not an entity ID.
Read the organization represented by the token:
curl 'https://connect.digits.com/v1/organization' \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}"This returns an organization object with id and name, plus caller-assigned identifiers when set. Organization endpoints use the token's organization; they do not take the financial request's entity selector.
Directly owned entities
If the organization owns its entities, use List Entities:
curl 'https://connect.digits.com/v1/organization/entities?limit=100' \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}"The response has entities and next. Use each entity's id for financial requests. This list covers directly owned entities, not all of a firm's client entities.
A firm's client entities
Use List Clients, then Get Client for each client:
curl 'https://connect.digits.com/v1/organization/clients?limit=100' \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}"The response has clients and next. Each client contains an organization object. Take its organization.id as the client ID:
export DIGITS_CLIENT_ORGANIZATION_ID='<client_organization_id>'
curl "https://connect.digits.com/v1/organization/client/${DIGITS_CLIENT_ORGANIZATION_ID}" \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}"Get Client returns the client’s organization and entities. Take entities[].id for the next steps.
Follow next.cursor while next.more is true for List Entities and List Clients. Get Client returns its entities without pagination. Choose the discovery path appropriate to the organization's structure.
3. Read two entities with one token
Set two accessible entity IDs from discovery. They can belong to the same client or different clients accessible to the token's organization:
export DIGITS_ENTITY_A='<first_digits_entity_id>'
export DIGITS_ENTITY_B='<second_digits_entity_id>'
for entity_id in "$DIGITS_ENTITY_A" "$DIGITS_ENTITY_B"; do
curl --get 'https://connect.digits.com/v1/ledger/categories' \
--data-urlencode "entity.id=${entity_id}" \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}"
doneEach response contains the selected entity's categories. The same token is used for both requests; each requires ledger:read. Financial Statements use the same selection pattern. Combine per-entity results in your application for consolidated reporting, accounting for differences in charts of accounts and reporting periods.
For GET requests, use entity.id in the query string. For JSON requests whose schema defines entity, put "entity": {"id": "<digits_entity_id>"} at the top level, alongside fields such as sources, parties, or transactions. Never put it inside each record. The EntitySelector also accepts external_id instead of id for an entity's caller-assigned ID in the authorizing organization's namespace; it is not a source or transaction external ID. Supply only one identifier.
Keep the same entity selector and filters on every pagination request. Maintain separate cursors and sync checkpoints for each entity. An entity-app token remains bound to its authorized entity; adding a selector cannot expand access.
4. Initialize source writes for each entity
With source:sync, call Sync Sources separately for each selected entity before writing parties or transactions. This initializes your integration's connection for that entity. Initializing entity A does not initialize entity B.
For a new connection, this example establishes one source for each entity. For an existing connection, send its complete desired source set instead of replacing it with this sample:
for entity_id in "$DIGITS_ENTITY_A" "$DIGITS_ENTITY_B"; do
curl --request POST 'https://connect.digits.com/v1/connection/sources' \
--header "Authorization: Bearer ${DIGITS_ACCESS_TOKEN}" \
--header 'Content-Type: application/json' \
--data "{
\"entity\": {\"id\": \"${entity_id}\"},
\"sources\": [{
\"external_id\": {\"issuer\": \"YourSystem\", \"id\": \"checking-001\"},
\"name\": \"Main Checking Account\",
\"type\": \"bank\",
\"subtype\": \"checking\"
}]
}"
doneEach successful response is {"success": true}. Sources are scoped to each entity's connection. Reusing checking-001 in the second entity does not refer to the first entity's account. Configure source labels before sending transactions that refer to those labels; see Connection Source Setup.
Every Sync Sources request supplies the complete source set for that entity's connection. Omitted sources are archived, existing ledger data remains, and archived sources are excluded from List Sources. Sending an archived source's external ID again reactivates it. Never send just a new source when you intend to retain the other sources.
Next, sync parties, then sync transactions, using the same top-level entity selector on each request. Source IDs, party references, category IDs, and sync checkpoints must belong to the selected entity and connection. See Identifiers for the boundaries.
5. Handle renewal and access changes
Use expires_in to renew before expiration. Service accounts repeat client_credentials; organization apps use refresh_token. If an app refresh token is invalid after disconnection or uninstall, repeat user authorization.
A missing selector on an entity-specific request with an organization token is an error. For a missing or inaccessible entity, verify discovery and the organization's current access; do not retry the same request indefinitely or drop the selector. Access to a client or entity can change after discovery.
Updated 1 day ago