The Hull API exposes 2 ways to import data:

  • The Firehose, which expects an HTTP payload that contains one or more input records such as track, traits, alias, unalias, and relies on the individual headers of each entry to resolve the User or Account to update.
  • The Import API which expects a JSON file that Hull can access and consume.

Firehose Authentication

When sending data to the firehose, authentication happens in each header object in the array that you will send. You need to create and pass a JWT in headers["Hull-Access-Token"] for each entry in the batch array. This JWT will include the claims for the command you send. For more details, see the section on building JWT Tokens

Here’s a summary of how the Tokens are created:

Mandatory Claims :

  • iss : Identifier of the issuer of the token (Your Hull Connector ID)
  • iat : Unix timestamp of the date the token has been issued at
  • io.hull.subjectType: The entity to apply the input record to. Possible values: "user"|"account"

Optional claims :

  • exp : Unix timestamp of the expiration date for the token. After this date, the token will not be considered valid.
  • nbf: Unix timestamp of a date. Before this date, the token will not be considered valid.
  • io.hull.active: Mark the User “Active”. Default: false
  • io.hull.create: If not found, create the user (What you want most of the time). Default: true

Identification Claims :

  • io.hull.asUser: Object with Identifiers. resolves the record to this user
  • io.hull.asAccount: Object with Identifiers. resolves the record to this account.
const claim = {
    iss: CONNECTOR_ID,
    iat: UnixTimeStamp,
    nbf: UnixTimeStamp,
    exp: UnixTimeStamp,
    "io.hull.asUser": { anonymous_id: "1234", external_id: "ad56e587fw9e8", domain: "foo.com" },
    "io.hull.create": true,
    "io.hull.active": false,
    "io.hull.subjectType": "user"
}
const token = jwt.encode(claim, CONNECTOR_SECRET)

For each input record, you must send an entry in the batch array with the following structure:

Update Attributes on Users or Accounts

"batch": [
  {
    "type": "traits",
    "timestamp": "2017-03-24T11:06:40.150Z",
    "headers": {
      // In the JWT, you need to encode the `User` and/or `Account` claims,
      // such as `email`, `external_id`, etc...
      "Hull-Access-Token": "JWT_ENCODED_CLAIMS"
    },
    "body": {
      // For a Traits call, body will contain all the attributes to update
      "foo": "bar"
    }
  }
]

Track an Event

"batch": [
  {
    "type": "track",
    "timestamp": "2017-03-24T11:06:40.150Z",
    "headers": {
      // In the JWT, you need to encode the `User` and/or `Account` claims,
      // such as `email`, `external_id`, etc...
      "Hull-Access-Token": "JWT_ENCODED_CLAIMS"
    },
    "body": {
      // For a Track call, these fields are the ones we recognize
      "ip": null,
      "ip": null,
      "url": null,
      "referer": null,
      // Pass the Event's Name in the `event` key
      "event": "hello",
      // Pass your custom event proeprties in the `properties` key.
      "properties": {
        "who": "world"
      }
    }
  }
]

Alias another anonymous_id to a User or Account

"batch": [
  {
    "type": "alias",
    "timestamp": "2017-03-24T11:06:40.150Z",
    "headers": {
      "Hull-Access-Token": "JWT_TOKEN"
    },
    "body": {
      "anonymous_id": "1234"
    }
  }
]

To link a User to an account, you need to create a special JWT_TOKEN that will contain both the io.hull.asUser and io.hull.asAccount claims. Linking will be done by the platform based on how the user and the account were resolved.

const claim = {
    iss: CONNECTOR_ID,
    iat: UnixTimeStamp,
    "io.hull.asUser": { anonymous_id: "abcd", external_id: "df46w8e7", domain: "user@foo.com" },
    "io.hull.asAccount": { anonymous_id: "1234", external_id: "ad56e587fw9e8", domain: "foo.com" },
    "io.hull.subjectType": "user"
}
const token = jwt.encode(claim, CONNECTOR_SECRET)