Skip to main content
BackedHelp Centre

OData feed for BI tools and data warehouses

Read ten of your organisation's record types into Power BI, Excel or a data warehouse through a standard OData v4 feed, with filters, paging and change tracking.

Last updated

The OData feed is a read-only address that business intelligence tools understand without any custom code. Power BI, Excel and most data warehouse loaders can read it: they ask the feed what it holds, then read each table page by page. It lives on your organisation's own address, under /odata/v4/.

The feed reads the same records your organisation's reports read, and only your own organisation's. Backed sends nothing anywhere: your tool asks, and the feed answers with the records as they are at that moment.

Before you start

  • An Administrator creates an API credential under Settings > Profile and terms, on the API Access tab, as API access explains, and ticks Read reporting feed under Scopes. Only an Administrator who also holds Can generate reports can give that scope. You can add it to an existing credential with Edit scopes; it takes effect on the credential's next request, with no new token needed.
  • Tick Include bank account numbers only if the tool needs applicants' full bank account numbers. Without it, the feed leaves those columns out.
  • Keep the credential's Client ID and Client Secret to hand. The secret is shown once.
  • Know your organisation's address: the one your team signs in at, such as https://your-subdomain.backed.giving. The feed is at that address plus /odata/v4/.

How the feed signs in

Every request carries a token in an Authorization: Bearer <token> header. The tool gets the token by sending the credential's Client ID and Client Secret to /oauth/token on your organisation's address, exactly as in Reporting feed for analytics tools. The feed takes the token only from that header, never from the address or a cookie.

A tool that can only ask for a user name and password, such as Tableau's or Power BI's OData connector, can sign in to the feed with the credential itself: the Client ID as the user name and the Client Secret as the password. The feed checks the pair on every request, just as /oauth/token checks it, so there is no token to renew. Only the feed takes a user name and password; the rest of the API takes a token alone. A wrong pair, or a deleted credential, answers 401 Unauthorized.

A token lasts five days. After that, every request answers 401 Unauthorized until the tool asks for a new one. A scheduled refresh needs a fresh token: either the query asks for one each time it runs (the Power BI sample below does), or someone renews the token before it expires.

A credential without Read reporting feed answers 403 with insufficient_scope. A credential may make 120 calls a minute, the feed and the rest of the API together; past that the feed answers 429 with a Retry-After header.

What the feed holds

Entity set What each row is
Applications an Application, with a column for each of your Field Tags
Applicants an applicant
RegistrationEntities an applicant organisation or person
FundingRounds a Funding Round
Assessments an assessment
Decisions a decision line
Contracts a contract
Milestones a milestone, with a column for each of your Field Tags on its deliverables
Payments a payment
Funds a Fund

The columns are those of the matching data source in a Backed report, so a column in your tool and a column in a data table match by name. Every set also has an updated_at column. The feed never carries people's email addresses, phone numbers, postal addresses or first and last names, whatever the credential.

/odata/v4/ lists the ten entity sets, and /odata/v4/$metadata describes every column and its type, which is how a BI tool builds its tables. The API's OpenAPI document points to the feed but does not describe it: $metadata does. See Developer documentation.

Field Tag columns

On Applications and Milestones, each of your organisation's Field Tags is a text column named after the tag, such as amount_requested. A character a column name can't hold becomes _, and a name that would repeat another column's gets the tag's number added, such as title_42. A table or repeatable answer comes back as one value, its cells separated by commas. Tag the fields you report on, and the columns keep their names across Funding Rounds while the tags keep theirs.

Value formats

Amounts are numbers. Dates are YYYY-MM-DD, and dates with times are in UTC, such as 2026-11-08T03:15:00.000Z.

Ask for less: query options

Add these to an entity set's address to narrow what comes back:

Option Example What it does
$select $select=record_id,application_title,current_status only these columns
$filter $filter=grant_id eq 12 and submission_date ge 2026-07-01T00:00:00Z only rows that match
$orderby $orderby=submission_date desc sort by up to eight columns, each asc or desc
$top $top=200 at most this many rows in all
$count $count=true adds @odata.count, the number of rows that match

A filter compares one column with one value using eq, ne, gt, ge, lt or le, and joins comparisons with and, or, not and brackets. Text goes in single quotes, and dates are written as 2026-07-01 or 2026-07-01T00:00:00Z. A list or JSON column can't be filtered or sorted.

The feed answers 501 with not_implemented for an option it doesn't support, such as $skip, $expand, $search or $apply, and for a filter that uses a function (contains, startswith), arithmetic, in or has. A mistake, such as a column that doesn't exist or the same option twice, answers 400 with bad_request. Both say which option was wrong. An entity set name is case-sensitive; one that doesn't exist answers 404.

Pages

A page holds up to 1,000 rows. When there are more, the page ends with @odata.nextLink: the address of the next page, with your options carried in it. Read that address next, and stop when a page has no @odata.nextLink. Power BI and Excel do this for you. A $top larger than 1,000 is not refused: you get 1,000 rows and a @odata.nextLink for the rest. Use the feed's own links rather than $skip, which the feed does not support.

Read only what changed

A warehouse loader that refreshes often can read only the rows changed since its last read, instead of the whole set:

  1. Read an entity set in full with the header Prefer: odata.track-changes. Follow every @odata.nextLink as usual. Leave out $filter: delta links are issued for unfiltered reads only (a filtered read is answered without one, and a delta link read with a $filter answers 400), so apply any filter on your side.
  2. The last page ends with @odata.deltaLink instead. Keep that address.
  3. Next time, read the @odata.deltaLink. It returns the rows changed since step 1, and its last page ends with a new @odata.deltaLink for the time after that.

A changed row comes back whole. A deleted assessment, payment or Fund comes back as a deleted-entity entry, in OData 4.0's form: "@odata.context" ending $metadata#<EntitySet>/$deletedEntity, an "id" such as "Payments(123)", "reason": "deleted" and the record's key, on the first page of the delta read; the entry is dated from when the feed recorded the deletion, a few seconds after it happened, so a delta read in that gap still gets it next time. The other entity sets carry no deleted-entity entries: most of their records are never deleted (they close, withdraw or decline, and reach you as a changed row), but an Administrator can delete an application or a registration entity, and such a record simply stops appearing without a removal entry. If your model must drop deleted applications or organisations, schedule a full reload of Applications, Applicants and RegistrationEntities (weekly is usual) beside the incremental refresh of the rest.

A delta link works only for the credential it was issued to, and only for 30 days after the read that issued it. An older, unknown or another credential's delta link answers 410 with delta_token_expired: read the entity set in full again, with Prefer: odata.track-changes, and start over from the new link.

Power BI and Excel don't use delta links: each refresh reads the tables in full.

Load the feed into Power BI Desktop

The simplest route is Power BI's own OData feed connector, signing in with the credential:

  1. In Power BI Desktop, select Get data, then OData feed.
  2. Under URL, enter your organisation's address plus /odata/v4/, such as https://your-subdomain.backed.giving/odata/v4/, and select OK.
  3. When Power BI asks how to connect, choose Basic. Enter the Client ID as the User name and the Client Secret as the Password, and select Connect.
  4. In the Navigator, tick the entity sets you want, then select Load or Transform Data.

Power BI keeps the pair with its data source settings, not in the .pbix file. If you would rather the feed see a token, start from a blank query that asks for one and then opens the feed:

  1. In Power BI Desktop, select Get data, then Blank query.
  2. In the Power Query editor, select Advanced Editor, paste the sample below, and replace the three settings at the top with your organisation's address, Client ID and Client Secret.
  3. Select Done. The query lists the ten entity sets; select Table beside each one you want.
  4. If Power BI asks how to connect to your organisation's address, choose Anonymous: the query sends its own token.
  5. Set column types where you need to, then select Close & Apply.
let
    // Your organisation's address and your credential's pair.
    BaseUrl = "https://your-subdomain.backed.giving",
    ClientId = "your-client-id",
    ClientSecret = "your-client-secret",

    // A token, asked for at every refresh (each lasts five days).
    Token = Json.Document(
        Web.Contents(BaseUrl, [
            RelativePath = "oauth/token",
            Headers = [#"Content-Type" = "application/x-www-form-urlencoded"],
            Content = Text.ToBinary(Uri.BuildQueryString([
                grant_type = "client_credentials",
                client_id = ClientId,
                client_secret = ClientSecret
            ]))
        ])
    )[access_token],

    // The feed, with the token on every request it makes.
    Feed = OData.Feed(
        BaseUrl & "/odata/v4/",
        null,
        [Headers = [Authorization = "Bearer " & Token], Implementation = "2.0"]
    )
in
    Feed

Filters and column choices you make in Power Query are sent to the feed as $filter and $select, so only what you keep is read. A step the feed can't answer, such as Remove Top Rows (sent as $skip) or a text filter like Begins With (sent as startswith), fails with 501. Put such a step after a Table.Buffer step, so Power BI applies it to rows it has already read.

Refresh on a schedule

  1. In Power BI Desktop, select Publish and choose a workspace.
  2. In the Power BI service, open the semantic model's Settings.
  3. Under Data source credentials, select Edit credentials for your organisation's address. For a model built with the OData feed connector, choose Basic and enter the Client ID and Client Secret again; for one built with the sample query, choose Anonymous.
  4. Under Refresh, turn on Configure a refresh schedule, choose the times, and select Apply.

With Basic, every refresh signs in with the pair; the sample asks for a new token at every refresh. Either way, the five-day token limit never stops it. If a refresh fails with 401 Unauthorized, the credential has been deleted or its secret is wrong; with 403, it has lost Read reporting feed. Keep the .pbix file to people who may see the credential's secret, as it is written in the query.

Load the feed into Excel

Excel's Get Data > From Other Sources > From OData Feed signs in as Power BI's OData feed connector does: choose Basic and enter the Client ID and Client Secret. To send a token instead, use the same query as Power BI:

  1. In Excel, select Data, then Get Data, From Other Sources, Blank Query.
  2. Select Advanced Editor, paste the Power BI sample above, and replace the three settings.
  3. Select Done, choose Anonymous if Excel asks how to connect, pick the entity sets you want, then select Close & Load.

Refresh All on the Data tab asks for a new token each time.

Tableau and other tools

Tableau Desktop reads the feed through its OData connector, signing in with the credential:

  1. In Tableau Desktop, under Connect, select To a Server, then OData.
  2. Under Server, enter your organisation's address plus /odata/v4/, such as https://your-subdomain.backed.giving/odata/v4/.
  3. Under Authentication, choose Username and Password. Enter the Client ID as the Username and the Client Secret as the Password, and select Sign In.
  4. Pick the entity set you want, such as Applications, and build your view. Add another OData connection for each further entity set.

Any other tool that can send an Authorization header with each request can read the feed, with a token or with the credential's pair as a user name and password.

A loader that runs on a schedule should ask for a new token at each run, keep each entity set's @odata.deltaLink, and read in full again when a delta link answers 410.

Who read what

Every read of an entity set is written to your organisation's Audit log as reporting_feed.read, with the entity set, the credential and the number of rows. Reading the list of entity sets or $metadata is not recorded, as neither holds any of your records.

See also

This page uses Backed's default terms, such as Funding Round and Application Template. An organisation may rename them, so read each as your organisation's own term if you've renamed it.