Sample code for 30+ languages & platforms
Unicode C 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 Unicode C Downloads

Unicode C
#include <C_CkHttpCurlW.h>
#include <C_CkJsonObjectW.h>
#include <C_CkFileAccessW.h>
#include <C_CkStringBuilderW.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkHttpCurlW curl;
    HCkJsonObjectW state;
    HCkFileAccessW files;
    const wchar_t *statePath;
    HCkJsonObjectW page;
    HCkStringBuilderW seenPath;
    const wchar_t *eventId;
    const wchar_t *nextPosition;
    int batch;
    int i;
    int count;
    BOOL more;
    HCkStringBuilderW authorizedCommand1;
    int headerReplacement1;

    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 = CkHttpCurlW_Create();
    CkHttpCurlW_SetVar(curl,L"access_token",L"BOX_ACCESS_TOKEN");

    state = CkJsonObjectW_Create();
    files = CkFileAccessW_Create();
    statePath = L"qa_data/box_events_state.json";
    if (CkFileAccessW_FileExists(files,statePath) == TRUE) {
        success = CkJsonObjectW_LoadFile(state,statePath);
        if (success != TRUE) {
            wprintf(L"%s\n",CkJsonObjectW_lastErrorText(state));
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            return;
        }

        if (CkJsonObjectW_HasMember(state,L"position") != TRUE) {
            wprintf(L"Invalid checkpoint: position missing.\n");
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            return;
        }

    }
    else {
        //  "now" starts a new subscription. It deliberately skips historical events.
        CkJsonObjectW_UpdateString(state,L"position",L"now");
    }

    CkHttpCurlW_SetVar(curl,L"position",CkJsonObjectW_stringOf(state,L"position"));
    page = CkJsonObjectW_Create();
    seenPath = CkStringBuilderW_Create();

    batch = 0;

    more = TRUE;
    while ((more == TRUE) && (batch < 20)) {
        CkHttpCurlW_ClearTargetOutput(curl,L"*");
        authorizedCommand1 = CkStringBuilderW_Create();
        CkStringBuilderW_SetString(authorizedCommand1,L"curl -X GET \"https://api.box.com/2.0/events?stream_type=all&stream_position={{position}}&limit=100\" -H \"Authorization: Bearer {{access_token}}\"");
        headerReplacement1 = CkStringBuilderW_Replace(authorizedCommand1,L"{{access_token}}",CkHttpCurlW_getVar(curl,L"access_token"));
        success = CkHttpCurlW_DoYourThing(curl,CkStringBuilderW_getAsString(authorizedCommand1));
        if ((success != TRUE) || (CkHttpCurlW_getStatusCode(curl) != 200)) {
            wprintf(L"Box request failed. HTTP status: %d\n",CkHttpCurlW_getStatusCode(curl));
            wprintf(L"Failure reason: %d\n",CkHttpCurlW_getFailReason(curl));
            wprintf(L"%s\n",CkHttpCurlW_responseBodyStr(curl));
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            CkJsonObjectW_Dispose(page);
            CkStringBuilderW_Dispose(seenPath);
            CkStringBuilderW_Dispose(authorizedCommand1);
            return;
        }

        success = CkHttpCurlW_GetResponseJson(curl,page);
        if (success != TRUE) {
            wprintf(L"%s\n",CkHttpCurlW_lastErrorText(curl));
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            CkJsonObjectW_Dispose(page);
            CkStringBuilderW_Dispose(seenPath);
            CkStringBuilderW_Dispose(authorizedCommand1);
            return;
        }

        count = CkJsonObjectW_SizeOfArray(page,L"entries");
        i = 0;
        while (i < count) {
            CkJsonObjectW_putI(page,i);
            eventId = CkJsonObjectW_stringOf(page,L"entries[i].event_id");
            if (eventId == L"") {
                wprintf(L"Event without an event_id; checkpoint not advanced.\n");
                CkHttpCurlW_Dispose(curl);
                CkJsonObjectW_Dispose(state);
                CkFileAccessW_Dispose(files);
                CkJsonObjectW_Dispose(page);
                CkStringBuilderW_Dispose(seenPath);
                CkStringBuilderW_Dispose(authorizedCommand1);
                return;
            }

            CkStringBuilderW_Clear(seenPath);
            CkStringBuilderW_Append(seenPath,L"seen.");
            CkStringBuilderW_Append(seenPath,eventId);
            if (CkJsonObjectW_HasMember(state,CkStringBuilderW_getAsString(seenPath)) == FALSE) {
                //  Replace this logging with your idempotent business operation.
                //  Record success only after that operation succeeds.
                wprintf(L"%s %s %s\n",eventId,CkJsonObjectW_stringOf(page,L"entries[i].event_type"),CkJsonObjectW_stringOf(page,L"entries[i].source.id"));
                CkJsonObjectW_UpdateBool(state,CkStringBuilderW_getAsString(seenPath),TRUE);
            }

            i = i + 1;
        }

        nextPosition = CkJsonObjectW_stringOf(page,L"next_stream_position");
        if (nextPosition == L"") {
            wprintf(L"Missing next_stream_position; checkpoint not advanced.\n");
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            CkJsonObjectW_Dispose(page);
            CkStringBuilderW_Dispose(seenPath);
            CkStringBuilderW_Dispose(authorizedCommand1);
            return;
        }

        more = (count > 0) && (nextPosition != CkHttpCurlW_getVar(curl,L"position"));
        CkJsonObjectW_UpdateString(state,L"position",nextPosition);
        success = CkJsonObjectW_WriteFile(state,statePath);
        if (success != TRUE) {
            wprintf(L"%s\n",CkJsonObjectW_lastErrorText(state));
            CkHttpCurlW_Dispose(curl);
            CkJsonObjectW_Dispose(state);
            CkFileAccessW_Dispose(files);
            CkJsonObjectW_Dispose(page);
            CkStringBuilderW_Dispose(seenPath);
            CkStringBuilderW_Dispose(authorizedCommand1);
            return;
        }

        CkHttpCurlW_SetVar(curl,L"position",nextPosition);
        batch = batch + 1;
    }

    wprintf(L"Checkpoint saved. Run again later to continue polling.\n");


    CkHttpCurlW_Dispose(curl);
    CkJsonObjectW_Dispose(state);
    CkFileAccessW_Dispose(files);
    CkJsonObjectW_Dispose(page);
    CkStringBuilderW_Dispose(seenPath);
    CkStringBuilderW_Dispose(authorizedCommand1);

    }