Tito redux

Tito Documentation

Anything out of place? Please get in touch!!

Webhooks

Tito provides the option to add a webhook for when tickets are created and updated.

You can specify a webhook in the Webhooks tab in the Customize section.

Webhooks will POST a JSON payload to the endpoint you specify, with a X-Webhook-Name header. This will be either ticket.created, ticket.completed, ticket.updated, ticket.voided, ticket.unsnoozed, ticket.unvoided or ticket.reassigned.

Basic Ticket Payload

The payload will look something like this for a basic ticket:

{
  "id": 795,
  "event": {
    "id": 64,
    "title": "AwesomeConf ?",
    "url": "https://heroku.tito.io/paulca/awesomeconf",
    "account_slug": "paulca",
    "slug": "awesomeconf",
    "currency": "EUR",
    "start_date": "2020-12-01",
    "end_date": null
  },
  "name": "Peter Winter",
  "first_name": "Peter",
  "last_name": "Winter",
  "email": "[email protected]",
  "phone_number": null,
  "company_name": "Peter Winter",
  "reference": "1i5nfwf2t",
  "price": "1.00",
  "tax": "0.19",
  "price_less_tax": "0.81",
  "slug": "1i5nfwf2t24",
  "state_name": "incomplete",
  "gender": "male",
  "release_price": "1.00",
  "discount_code_used": "",
  "total_paid": "1.00",
  "total_paid_less_tax": "0.81",
  "updated_at": "2017-08-27T13:07:47.000Z",
  "url": "https://heroku.tito.io/tickets/1i5nfwf2t24",
  "admin_url": "https://heroku.tito.io/paulca/awesomeconf/admin/tickets/1i5nfwf2t24",
  "release_title": "AwesomeConf ticket",
  "release_slug": "31az2uvoh4",
  "release_id": 90,
  "release": {
    "id": 90,
    "title": "AwesomeConf ticket",
    "slug": "31az2uvoh4",
    "metadata": null
  },
  "custom": null,
  "registration_id": "bdtyap3hguq",
  "registration_slug": "bdtyap3hguq",
  "metadata": null,
  "answers": [
    {
      "question": {
        "title": "Phone Number",
        "description": "",
        "id": 200
      },
      "response": "[email protected]",
      "humanized_response": "[email protected]"
    },
    {
      "question": {
        "title": "Session 1 – Second Choice",
        "description": "",
        "id": 1293
      },
      "response": "One",
      "humanized_response": "One"
    },
    {
      "question": {
        "title": "Session 1 - First Choice",
        "description": "",
        "id": 1292
      },
      "response": "[email protected]",
      "humanized_response": "[email protected]"
    },
    {
      "question": {
        "title": "Country",
        "description": "",
        "id": 1005357
      },
      "response": "AU",
      "humanized_response": "AU"
    },
    {
      "question": {
        "title": "Session 1 — Third Choice",
        "description": "",
        "id": 1295
      },
      "response": "One",
      "humanized_response": "One"
    },
    {
      "question": {
        "title": "T-Shirt Size",
        "description": "",
        "id": 1009604
      },
      "response": "Women's S",
      "humanized_response": "Women's S"
    }
  ],
  "responses": {
    "phone-number": "[email protected]",
    "session-1-second-choice": "One",
    "session-1-first-choice": "[email protected]",
    "country": "AU",
    "session-1-third-choice": "One",
    "t-shirt-size": "Women's S"
  },
  "upgrade_ids": [

  ],
  "registration": {
    "url": "https://heroku.tito.io/registrations/bdtyap3hguq",
    "admin_url": "https://heroku.tito.io/paulca/awesomeconf/admin/registrations/bdtyap3hguq",
    "total": "1.00",
    "currency": "EUR",
    "payment_reference": null,
    "source": null,
    "name": "Paul Campbell",
    "email": "[email protected]",
    "receipt": {
      "total": "1.00",
      "tax": "0.19",
      "payment_provider": "Unknown",
      "paid": true,
      "receipt_lines": [
        {
          "total": "1.00",
          "quantity": 1,
          "tax": "0.19"
        }
      ]
    }
  }
}

Payload with Responses to Questions

If the ticket has answers to questions, it will look a bit like this:

{
  "id": 1052678,
  "event": {
    "id": 64,
    "title": "AwesomeConf ?",
    "url": "https://heroku.tito.io/paulca/awesomeconf",
    "account_slug": "paulca",
    "slug": "awesomeconf",
    "currency": "EUR",
    "start_date": "2020-12-01",
    "end_date": null
  },
  "name": "Peter Winter",
  "first_name": "Peter",
  "last_name": "Winter",
  "email": "[email protected]",
  "phone_number": null,
  "company_name": "Peter Winter",
  "reference": "A8FV-3",
  "price": "1.00",
  "tax": "0.19",
  "price_less_tax": "0.81",
  "slug": "pGZ3De1X3wLslG7yQwO7QFg",
  "state_name": "incomplete",
  "gender": "male",
  "release_price": "1.00",
  "discount_code_used": "",
  "total_paid": "1.00",
  "total_paid_less_tax": "0.81",
  "updated_at": "2017-08-27T13:07:50.000Z",
  "url": "https://heroku.tito.io/tickets/pGZ3De1X3wLslG7yQwO7QFg",
  "admin_url": "https://heroku.tito.io/paulca/awesomeconf/admin/tickets/pGZ3De1X3wLslG7yQwO7QFg",
  "release_title": "AwesomeConf ticket",
  "release_slug": "31az2uvoh4",
  "release_id": 90,
  "release": {
    "id": 90,
    "title": "AwesomeConf ticket",
    "slug": "31az2uvoh4",
    "metadata": null
  },
  "custom": null,
  "registration_id": "pbidGD4FWx7r47py0dYdDeg",
  "registration_slug": "pbidGD4FWx7r47py0dYdDeg",
  "metadata": null,
  "answers": [
    {
      "question": {
        "title": "Phone Number",
        "description": "",
        "id": 200
      },
      "response": "12345",
      "humanized_response": "12345"
    },
    {
      "question": {
        "title": "Session 1 – Second Choice",
        "description": "",
        "id": 1293
      },
      "response": "One",
      "humanized_response": "One"
    },
    {
      "question": {
        "title": "Country",
        "description": "",
        "id": 1005357
      },
      "response": "AU",
      "humanized_response": "AU"
    },
    {
      "question": {
        "title": "Session 1 - First Choice",
        "description": "",
        "id": 1292
      },
      "response": "[email protected]",
      "humanized_response": "[email protected]"
    },
    {
      "question": {
        "title": "Session 1 — Third Choice",
        "description": "",
        "id": 1295
      },
      "response": "One",
      "humanized_response": "One"
    },
    {
      "question": {
        "title": "T-Shirt Size",
        "description": "",
        "id": 1009604
      },
      "response": "Women's S",
      "humanized_response": "Women's S"
    }
  ],
  "responses": {
    "phone-number": "12345",
    "session-1-second-choice": "One",
    "country": "AU",
    "session-1-first-choice": "[email protected]",
    "session-1-third-choice": "One",
    "t-shirt-size": "Women's S"
  },
  "upgrade_ids": [

  ],
  "registration": {
    "url": "https://heroku.tito.io/registrations/pbidGD4FWx7r47py0dYdDeg",
    "admin_url": "https://heroku.tito.io/paulca/awesomeconf/admin/registrations/pbidGD4FWx7r47py0dYdDeg",
    "total": "3.00",
    "currency": "EUR",
    "payment_reference": "ch_4MkyHRycVDKfCp",
    "source": null,
    "name": "Paul Campbell",
    "email": "[email protected]",
    "receipt": {
      "total": "3.00",
      "tax": "0.56",
      "payment_provider": "Stripe (live)",
      "paid": true,
      "receipt_lines": [
        {
          "total": "3.00",
          "quantity": 3,
          "tax": "0.56"
        }
      ]
    }
  }
}

Verifying the payload

Each payload comes with a signed HMAC signature so that you can verify the origin of the webhook request.

In Customize -> Webhooks, you’ll find a shared security token. You can use the to sign the payload.

The security token is used as a key to sign the payload data with an HMAC key.

The HMAC key is your security token, the HMAC digest is SHA2, and the data is the raw payload JSON that is sent. The key is sent Base64 encoded via the Tito-Signature HTTP header.

If you’re using Ruby, for example, you can verify the authenticity of your payload with the following code:

key = 'YOUR EVENT SECURITY TOKEN'
hash = OpenSSL::Digest.new('sha256')
data = 'THE WEBHOOK REQUEST'

Base64.encode64(OpenSSL::HMAC.digest(hash, key, data)).strip