Sample code for 30+ languages & platforms
Lazarus Pascal Requires Chilkat v11.5.0+

Box: Poll User Events and Save a Checkpoint

See more Box Examples

Poll the authenticated user event stream in bounded batches. The local JSON checkpoint keeps processed event IDs and the next stream position. This single-process demonstration logs events; a production worker should commit its business action, deduplication record, and cursor transactionally and prune old IDs.

See the Box API guide for setup and the complete workflow.

Chilkat Lazarus Pascal Downloads

Lazarus Pascal
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.FileAccess,
  Chilkat.HttpCurl,
  Chilkat.StringBuilder,
  Chilkat.JsonObject;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  curl: THttpCurl;
  state: TJsonObject;
  files: TFileAccess;
  statePath: string;
  page: TJsonObject;
  seenPath: TStringBuilder;
  eventId: string;
  nextPosition: string;
  batch: Integer;
  i: Integer;
  count: Integer;
  more: Boolean;
  authorizedCommand1: TStringBuilder;
  headerReplacement1: Integer;

begin
  success := False;

  //  Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
  //  See Global Unlock Sample.
  //  Guide: Box API Guide.

  success := False;

  //  Supply an unexpired token obtained with one of the Box authentication examples.
  //  A token represents a particular user or service account. IDs must be accessible to it.
  curl := THttpCurl.Create;
  curl.SetVar('access_token','BOX_ACCESS_TOKEN');

  state := TJsonObject.Create;
  files := TFileAccess.Create;
  statePath := 'qa_data/box_events_state.json';
  if (files.FileExists(statePath) = True) then
    begin
      success := state.LoadFile(statePath);
      if (success <> True) then
        begin
          WriteLn(state.LastErrorText);
          Exit;
        end;
      if (state.HasMember('position') <> True) then
        begin
          WriteLn('Invalid checkpoint: position missing.');
          Exit;
        end;
    end
  else
    begin
      //  "now" starts a new subscription. It deliberately skips historical events.
      state.UpdateString('position','now');
    end;
  curl.SetVar('position',state.StringOf('position'));
  page := TJsonObject.Create;
  seenPath := TStringBuilder.Create;

  batch := 0;

  more := True;
  while (more = True) and (batch < 20) do
    begin
      curl.ClearTargetOutput('*');
      authorizedCommand1 := TStringBuilder.Create;
      authorizedCommand1.SetString('curl -X GET "https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100" -H "Authorization: Bearer {{access_token}}"');
      headerReplacement1 := authorizedCommand1.Replace('{{access_token}}',curl.GetVar('access_token'));
      success := curl.DoYourThing(authorizedCommand1.GetAsString());
      if ((success <> True) or (curl.StatusCode <> 200)) then
        begin
          WriteLn('Box request failed. HTTP status: ' + curl.StatusCode);
          WriteLn('Failure reason: ' + curl.FailReason);
          WriteLn(curl.ResponseBodyStr);
          Exit;
        end;
      success := curl.GetResponseJson(page);
      if (success <> True) then
        begin
          WriteLn(curl.LastErrorText);
          Exit;
        end;
      count := page.SizeOfArray('entries');
      i := 0;
      while i < count do
        begin
          page.I := i;
          eventId := page.StringOf('entries[i].event_id');
          if (eventId = '') then
            begin
              WriteLn('Event without an event_id; checkpoint not advanced.');
              Exit;
            end;
          seenPath.Clear();
          seenPath.Append('seen.');
          seenPath.Append(eventId);
          if (state.HasMember(seenPath.GetAsString()) = False) then
            begin
              //  Replace this logging with your idempotent business operation.
              //  Record success only after that operation succeeds.
              WriteLn(eventId + ' ' + page.StringOf('entries[i].event_type') + ' ' + page.StringOf('entries[i].source.id'));
              state.UpdateBool(seenPath.GetAsString(),True);
            end;
          i := i + 1;
        end;

      nextPosition := page.StringOf('next_stream_position');
      if (nextPosition = '') then
        begin
          WriteLn('Missing next_stream_position; checkpoint not advanced.');
          Exit;
        end;
      more := (count > 0) and (nextPosition <> curl.GetVar('position'));
      state.UpdateString('position',nextPosition);
      success := state.WriteFile(statePath);
      if (success <> True) then
        begin
          WriteLn(state.LastErrorText);
          Exit;
        end;
      curl.SetVar('position',nextPosition);
      batch := batch + 1;
    end;

  WriteLn('Checkpoint saved. Run again later to continue polling.');


  curl.Free;
  state.Free;
  files.Free;
  page.Free;
  seenPath.Free;
      authorizedCommand1.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.