Skip to content

Quickstart

This walkthrough takes you from zero to downloading a file in under five minutes, assuming an organization owner has already created an API client and given you three values:

  • IBINDER_ORG_ID — the Organisations id (x-ibinder-tenantid)
  • IBINDER_CLIENT_ID — the API client's id
  • IBINDER_CLIENT_SECRET — the API client's secret

The flow is:

  1. Exchange the client credentials for an access token.
  2. List the binders you have access to.
  3. Search a binder for documents.
  4. Resolve a document version to a download URL and fetch the bytes.

Full end-to-end example

ts
const API   = 'https://api.ibinder.com/api'
const AUTH  = 'https://signin.ibinder.com/connect/token'
const orgId = process.env.IBINDER_ORG_ID!

// 1. Token
const tokenRes = await fetch(AUTH, {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type:    'client_credentials',
    client_id:     process.env.IBINDER_CLIENT_ID!,
    client_secret: process.env.IBINDER_CLIENT_SECRET!,
    scope:         'ibinder_public',
  }),
})
const { access_token } = await tokenRes.json()

const headers = {
  Authorization:       `Bearer ${access_token}`,
  'x-ibinder-tenantid': orgId,
  'Content-Type':       'application/json',
}

// 2. List binders
const binders = await fetch(`${API}/binders`, { headers }).then(r => r.json())
const binderId = binders.items[0].id

// 3. Search documents in that binder
const search = await fetch(`${API}/documents?pageSize=10&pageNumber=1`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    MetadataFilters: [
      { metadataElementId: 'GLOBAL_BinderId', valueId: binderId },
    ],
  }),
}).then(r => r.json())

const doc = search.items[0]
const versionId = doc.latestVersionId

// 4. Get a download URL and fetch the bytes (no Authorization header on the storage URL)
const { url } = await fetch(
  `${API}/documents/${doc.id}/versions/${versionId}/downloadlink`,
  { headers },
).then(r => r.json())

const fileBytes = await fetch(url).then(r => r.arrayBuffer())
console.log(`Downloaded ${fileBytes.byteLength} bytes`)
csharp
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

const string Api  = "https://api.ibinder.com/api";
const string Auth = "https://signin.ibinder.com/connect/token";

var orgId        = Environment.GetEnvironmentVariable("IBINDER_ORG_ID")!;
var clientId     = Environment.GetEnvironmentVariable("IBINDER_CLIENT_ID")!;
var clientSecret = Environment.GetEnvironmentVariable("IBINDER_CLIENT_SECRET")!;

using var http = new HttpClient();

// 1. Token
var tokenResp = await http.PostAsync(Auth, new FormUrlEncodedContent(
    new Dictionary<string, string>
    {
        ["grant_type"]    = "client_credentials",
        ["client_id"]     = clientId,
        ["client_secret"] = clientSecret,
        ["scope"]         = "ibinder_public",
    }));
var token = (await tokenResp.Content.ReadFromJsonAsync<JsonElement>())
            .GetProperty("access_token").GetString();

http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
http.DefaultRequestHeaders.Add("x-ibinder-tenantid", orgId);

// 2. List binders
var binders  = await http.GetFromJsonAsync<JsonElement>($"{Api}/binders");
var binderId = binders.GetProperty("items")[0].GetProperty("id").GetString();

// 3. Search documents in that binder
var search = await http.PostAsJsonAsync(
    $"{Api}/documents?pageSize=10&pageNumber=1",
    new
    {
        MetadataFilters = new[]
        {
            new { metadataElementId = "GLOBAL_BinderId", valueId = binderId },
        },
    });
var hits      = await search.Content.ReadFromJsonAsync<JsonElement>();
var doc       = hits.GetProperty("items")[0];
var docId     = doc.GetProperty("id").GetString();
var versionId = doc.GetProperty("latestVersionId").GetString();

// 4. Resolve download URL and fetch
var link = await http.GetFromJsonAsync<JsonElement>(
    $"{Api}/documents/{docId}/versions/{versionId}/downloadlink");
var url  = link.GetProperty("url").GetString();

// Storage URL — do NOT send the bearer token here
using var bare = new HttpClient();
var bytes = await bare.GetByteArrayAsync(url);
Console.WriteLine($"Downloaded {bytes.Length} bytes");
bash
API=https://api.ibinder.com/api
AUTH=https://signin.ibinder.com/connect/token

# 1. Token
TOKEN=$(curl -s -X POST "$AUTH" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$IBINDER_CLIENT_ID" \
  -d "client_secret=$IBINDER_CLIENT_SECRET" \
  -d "scope=ibinder_public" | jq -r .access_token)

H_AUTH="Authorization: Bearer $TOKEN"
H_TEN="x-ibinder-tenantid: $IBINDER_ORG_ID"

# 2. List binders
BINDER_ID=$(curl -s "$API/binders" -H "$H_AUTH" -H "$H_TEN" \
  | jq -r '.items[0].id')

# 3. Search documents in that binder
SEARCH=$(curl -s -X POST "$API/documents?pageSize=10&pageNumber=1" \
  -H "$H_AUTH" -H "$H_TEN" -H "Content-Type: application/json" \
  -d "{\"MetadataFilters\":[{\"metadataElementId\":\"GLOBAL_BinderId\",\"valueId\":\"$BINDER_ID\"}]}")
DOC_ID=$(echo "$SEARCH"     | jq -r '.items[0].id')
VERSION_ID=$(echo "$SEARCH" | jq -r '.items[0].latestVersionId')

# 4. Resolve download URL and fetch
URL=$(curl -s "$API/documents/$DOC_ID/versions/$VERSION_ID/downloadlink" \
  -H "$H_AUTH" -H "$H_TEN" | jq -r .url)

# Note: no auth header on the storage URL
curl -s "$URL" -o downloaded.bin
ls -lh downloaded.bin

Token caching

Don't request a new token on every call. Cache the access_token for its expires_in lifetime (minus a small safety margin) and refresh on demand.

Released under the MIT License.