-
Notifications
You must be signed in to change notification settings - Fork 14
Webhook Design Draft
Just as a meta note, the code blocks on this page are using Python syntax, not JSON. The webhook API will be using JSON, it was just a bit faster for me to write it up like this. I'm going to be going through and fixing up this page later (moving comments out of code blocks and into tables probably, JSON syntax), this is just to start getting some feedback if possible. Comments at #88.
Fired when a Request is submitted to a Division.Note that this will be fired multiple times if a Request is moved to a new Division. This is an attempt to ease the eventual transition when I work on separating Killmail info from Requests (see Github issue #46 for details).
{
# All hook payloads will have an 'event' data member with one of the event
# types listed above.
'event': 'request_submit',
# As mentioned above, this API is a half-step towards separating a Killmail
# data from Request data. This means there will be some differences from
# the existing read-only API.
'killmail': {
'href': 'https://zkillboard.com/kill/39861569/', # The link to the
# killmail submitted.
'pilot': {
'id': 570140137,
'name': 'Paxswill',
'corporation': {
'id': 1018389948,
'name': 'Dreddit',
},
# For those Pilots without an alliance, this item will be null.
'alliance': {
'id': 498125261,
'name': 'Test Alliance Please Ignore',
},
},
'timestamp': '2014-07-02T19:26:00' # This is equivalent to the kill
# timestamp in the old API.
'location': {
'system': {
'id': 30001160,
'name': 'WD-VTV',
},
'constellation': {
'id': 20000169,
'name': 'UX3-N2'
},
'region': {
'id': 10000014
'name': 'Catch',
},
},
'ship': 'Guardian',
},
'id': 39861569, # This ID will maintain the same semantics of the current
# request ID, in that it is also the ID of the killmail.
'href': 'http://example.com/requests/12345', # An absolute URL to this
# request in the app.
'division': { # The division this hook is being fired for.
'id': 1,
'name': 'Example Division',
},
'timestamp': '2014-07-09T19:43:58.126158', # This is equivalent to the
# submission timestamp in the
# old API
'user': {
'id': 42,
'name': 'paxswill',
'notes': [
# If a user has no notes about them, this array will be empty.
{
'id': 34
'note': 'A note about the user.',
'timestamp': '2016-04-30T21:17:35',
'submitter': { # The person who made the note
'id': 42,
'name': 'paxswill',
},
},
],
},
'details': 'Some text here.',
}
The consumer MAY respond to a request. Not sure how I'm going to do this (a new HTTP request? Response to the original request?).
request_submit_response = {
# All of these members are optional.
'payout': '20000000', # Sets the base payout for the request
'actions': [ # These actions are added in order.
{
'type': 'comment', # Required. One of 'approved', 'rejected',
# 'incomplete', 'evaluating',
# 'comment', or 'paid'. This must be a valid
# status for the request to move to (see
# documentation for the state diagram).
'note': '', # Optional. If omitted, the default value is the empty
# string.
},
],
'modifiers': [ # Order is irrelevant for modifiers, but they will probably
# be added in order (this is an implementation detail, and
# not guaranteed!).
{
'type': 'absolute', # Required. One of 'absolute' or 'relative'.
'value': '5000000', # Required. If type is 'absolute', the amount
# to add to the base payout. For penalties, use
# a negative value. This value MAY be a String
# or a Number. String is recommended for
# absolute modifiers, as the app
# converts this value to a fixed point number.
'note': '', # Optional. If omitted, the default value is the empty
# string.
},
],
}
Fired when an Action is added to a Request. Actions are things that change a Request's status, in addition to comments.
action_add_hook = {
'event': 'action_add',
'action': { # The action that triggered this hook
'user': {
'id': 42,
'name': 'paxswill',
},
'type': 'comment',
'note': '', # May be empty, may have text.
# NOTE: should this be nullable?
'timestamp': '2015-07-02T19:47:00'
},
'request': {
'killmail': {
'href': 'https://zkillboard.com/kill/39861569/',
'pilot': {
'id': 570140137,
'name': 'Paxswill',
'corporation': {
'id': 1018389948,
'name': 'Dreddit',
},
'alliance': {
'id': 498125261,
'name': 'Test Alliance Please Ignore',
},
},
'timestamp': '2014-07-02T19:26:00',
'location': {
'system': {
'id': 30001160,
'name': 'WD-VTV',
},
'constellation': {
'id': 20000169,
'name': 'UX3-N2'
},
'region': {
'id': 10000014
'name': 'Catch',
},
},
'ship': 'Guardian',
},
'id': 39861569,
'href': 'http://example.com/requests/12345',
'division': {
'id': 1,
'name': 'Example Division',
},
'timestamp': '2014-07-09T19:43:58.126158',
'user': {
'id': 42,
'name': 'paxswill',
'notes': [
{
'note': 'A note about the user.',
'timestamp': '2016-04-30T21:17:35',
'submitter': {
'id': 42,
'name': 'paxswill',
},
},
],
},
'details': 'Some text here.',
'actions': [
# The action that triggered this hook /will/ be present in the
# actions array. It /might not/ be the first (most recent) item in
# the array.
{
'user': {
'id': 42,
'name': 'paxswill',
},
'type': 'comment',
'note': '', # May be empty, may have text.
# NOTE: should this be nullable?
'timestamp': '2015-07-02T19:47:00'
'id': 230,
}
],
'modifiers': [
{
'type': 'absolute', # One of 'absolute' or 'relative'.
'value': '-5000000', # Absolute modifiers are given as strings
# to avoid floating point errors.
# Penalties have negative values (leading
# negative sign), bonuses are positive (no
# leading sign).
'note': '',
'timestamp':'2015-07-02T19:47:00',
'id': 543, # The ID number of the modifier.
'void': null, # If a modifier has not been voided (i.e.: it is
# still active), this member will be null.
},
{
'type': 'relative',
'value': 0.1, # Relative modifiers are given as double
# precision floating point numbers representing a
# percentage bonus or penalty (using the same
# logic as absolute modifiers: positive is bonus,
# negative is penalty).
'note': 'Happy little bonus',
'timestamp': '2010-12-24T12:24:10',
'id': 9001,
# If the modifier has been voided, instead of None, the value
# will be similar to this:
'void': {
'timestamp': '2014-07-02T19:26:00', # When the modifier was
# voided.
'user': { # The user that voided this modifier
'id': 42,
'name': 'paxswill',
},
},
},
}
],
'base_payout': '42000000',
'payout': '37000000',
},
}
Identical to the request_submit
response with the exception that if a consumer's response includes an actions
member, that consumer will not receive an event notification for those action(s) when they are added.
Convenience event for when an API consumer doesn't need all of the information of the action_add
event. This event type does not fire when a comment is added to a Request.
status_change_hook = {
'event': 'status_change',
'href': 'http://example.com/requests/123456789',
'old_status': 'evaluating',
'new_status': 'approved',
'note': '', # Like the action.note item above, might be nullable.
'timestamp': '2015-07-02T19:47:00'
'id': 765, # The ID of the Action that changed the status.
'user': {
'id': 42,
'name': 'paxswill',
},
}
The convenience hooks will not be able to respond. If a consumer wants to do that, they'll have to use the action_add
hook. Do note that read-only access will be available (somehow) to consumers via the link in the href
member.
Counterpart to the status
event type. Will only fire when a comment is added to a Request.
comment_add_hook = {
'event': 'comment_add',
'href': 'http://example.com/requests/123456789',
'note': 'Hopefully there\'s text here', # being a comment and all...
'timestamp': '2015-07-02T19:47:00',
'id': 325, # The ID of the Action, if you need to look it up later.
'user': {
'id': 42,
'name': 'paxswill',
},
}
As mentioned above, the convenience hooks will not be able to respond.
Fired when the base payout of a Request is changed.
payout_change_hook = {
'event': 'payout_change',
# Note, that even though the base and computed payouts are included for
# both the old and new values, this hook is only fired when the base payout
# changes. For when the computed payout changes, look at the
# modifier_change event.
'old_payout': {
'base_payout': '42000000', # Again, note that this API will be emitting
# the payout values and absolute modifiers
# as strings to avoid running into floating
# point issues.
'payout': '37000000',
},
'new_payout': {
'base_payout': '40000000',
'payout': '35000000',
}
'user': {
# While right now the user that changed a payout is not surfaced in the
# app (nor is it recorded) this might change in the future.
'id': 42,
'name': 'paxswill',
},
'request': action_add_hook['request'],
}
Identical to the request_submit
response with the exception that if a consumer's response includes a payout
member, that consumer will not receive an event notification for that payout change.
Fired when a modifier is added to a Request or voided.
modifier_change_hook = {
'event': 'modifier_change',
'modifier': { # The modifier that has been added or voided
# For details on these fields, see action_add_hook.request.modifiers
'type': 'relative',
'value': -0.5, # Relative modifiers are specified as a percentage in
# a double precision floating point number.
'note': '', # Again, might be null, might be an empty string. Not sure
# yet.
'timestamp': '2014-07-02T19:26:00', # When the modifier was added.
'id': 235, # This ID is global across the app, not by request.
'void': None,
# If the modifier has been voided, instead of None, the value will be
# similar to this:
'void': {
'timestamp': '2014-07-02T19:26:00', # When the modifier was voided.
'user': { # The user that voided this modifier
'id': 42,
'name': 'paxswill',
},
}
},
'user': {
'id': 42,
'name': 'paxswill',
}
'request': action_add_hook['request'],
}
Identical to the request_submit
response with the exception that if a consumer's response includes a modifiers
member, that consumer will not receive event notifications for those modifiers.
Fired when a Note is added to a User.
note_add_hook = {
'event': 'note_add',
'note': ('The text of the note. If there are embedded links, they will not'
' be marked up in any way. This includes the automatic '
'linkification of things in the form #1234567 that normally links'
' to the request of that number.'),
'id': 39, # The note's ID number
'timestamp':'2016-05-30T21:17:35'
'submitter': { # The person who's adding the note.
'id': 42,
'name': 'paxswill',
},
'user': { # The user the note is being added to.
'id': 42,
'name': 'Paxswill',
'notes': [
{
'id': 34
'note': 'A note about the user.',
'timestamp': '2016-04-30T21:17:35',
'submitter': {
'id': 40,
'name': 'Kalrogin Kerona',
},
},
# The information about the newly added note will be duplicated in
# this array.
{
'id': 39,
'note': 'The same text as the top-level note member',
'timestamp': '2016-05-30T21:17:35',
'submitter': {
'id': 42,
'name': 'paxswill',
},
},
],
},
}
No responses accepted.
Fired when a Permission is added to or removed to from a Division.
role_change_hook = {
'event': 'role_change',
'role': {
'entity': { # The User or Group that that is being added/removed
'type': 'group', # Will be either 'user' or 'group'
'name': 'Test Alliance', # The name of the User or Group
'id': 21,
# Also note, the number of members in a Group will not be exposed
# via this API.
},
'permission': 'submit', # Will be one of 'submit', 'review', 'pay',
# 'audit' or 'admin'.
},
'action': 'add', # Will be one of 'add' or 'remove'
'user': { # The user who added or removed the role in question. Like the
# payout_change event, this data is not logged within the app.
'id': 42,
'name': 'paxswill',
},
# No timestamp, as role changes are not logged within the app. If the
# consumer needs that sort of record keeping, they will need to do it
# themselves (which is why this hook is here).
}
No responses accepted.
Fired when a User logs in. The intent of this hook is to allow for customized logging setups.
login_hook = {
'event': 'login',
'user': {
'id': 42,
'name': 'paxswill',
'method': 'Test OAuth', # Note: this will probably be the only place
# the authentication method the user uses is
# mentioned in the API. For other resources, I
# do not think it's relevant information.
'new': false, # Wether this is the first time the user has logged in.
},
'source_ip': '123.45.67.89', # The IP address (v4 or v6) the user signs in
# from. Not sure if I'll keep this data in or
# not.
}
This will be a special API, probably enabled by a special app configuration option. Even then, this is still up in the air.
login_response = {
'divisions': [ # Optional. Divisions to create.
{
'name': 'Clever Division Name',
'roles': [
{
'entity': 14, # The ID of a User or Group to grant this
# permission to.
'permission': 'submit', # Must be one of 'submit',
# 'review', 'pay', 'audit' or
# 'admin'.
},
],
},
],
'roles': [ # Optional. Roles to grant in existing divisions.
{
'division': 1, # The ID of a division to grant this permission in.
'entity': 14, # The ID of a User or Group to grant this
# permission to.
'permission': 'submit', # Must be one of 'submit',
# 'review', 'pay', 'audit' or
# 'admin'.
},
],
}
Fired when a Division is created.
division_add_hook = {
'event': 'division_add',
'id': 2,
'name': 'A Second Division',
'user': { # This user will be a site-wide admin.
'id': 42,
'name': 'paxswill',
},
}
Again, not sure if this should even be included.
division_add_response = {
'roles': [ # Optional. If present, must be an array.
{
'permission': 'submit', # Must be one of 'submit', 'review', 'pay',
# 'audit' or 'admin'
'entity': 40, # Must be the ID of a User or Group.
},
],
}
Many items in Eve have both a name (which may or may not be localized in a language other than English) and an ID used by the various APIs CCP exposes. These items all share the same basic structure. English is used for the names of all items in this app.
Key Name | Description |
---|---|
id |
The ID number for this item. |
name |
The English name for this item. |
This example is using a solar system, but other items follow the sane pattern.
{
"id": 30001160,
"name": "WD-VTV"
}
Killmails represent the information regarding the loss of a ship in Eve that a user is asking for compensation for.
Key Name | Description |
---|---|
link |
The link the submitter provided for evaluation. |
location |
A location object. |
pilot |
A pilot object. |
timestamp |
The date and time the loss happened within Eve. It will be in ISO 8601 format, without a timezone as everything in Eve is in UTC. |
ship |
An Eve object for the ship (or other item) that generated a killmail in Eve. |
id |
The reference ID for this killmail. It is the same ID that the Eve API uses to refer to this killmail. |
href |
An absolute URL to the information from the app about this killmail. |
user |
A user object. |
divisions |
An array of division objects. |
requests |
An object with the values being request objects and the keys the ID of the division for that request. |
{
"killmail": {
"href": "https://zkillboard.com/kill/39861569/",
"pilot": {
"id": 570140137,
"name": "Paxswill",
"corporation": {
"id": 1018389948,
"name": "Dreddit"
},
"alliance": {
"id": 498125261,
"name": "Test Alliance Please Ignore"
}
},
"timestamp": "2014-07-02T19:26:00",
"location": {
"system": {
"id": 30001160,
"name": "WD-VTV"
},
"constellation": {
"id": 20000169,
"name": "UX3-N2"
},
"region": {
"id": 10000014,
"name": "Catch"
}
},
"ship": "Guardian"
},
"id": 39861569,
"href": "http://example.com/requests/12345",
"division": {
"id": 1,
"name": "Example Division"
},
"timestamp": "2014-07-09T19:43:58.126158",
"user": {
"id": 42,
"name": "paxswill",
"notes": [
{
"note": "A note about the user.",
"timestamp": "2016-04-30T21:17:35",
"submitter": {
"id": 42,
"name": "paxswill"
}
}
]
},
"details": "Some text here.",
"actions": [
# The action that triggered this hook /will/ be present in the
# actions array. It /might not/ be the first (most recent) item in
# the array.
{
"user": {
"id": 42,
"name": "paxswill"
},
"type": "comment",
"note": "", # May be empty, may have text.
# NOTE: should this be nullable?
"timestamp": "2015-07-02T19:47:00"
"id": 230
}
],
"modifiers": [
{
"type": "absolute", # One of "absolute" or "relative".
"value": "-5000000", # Absolute modifiers are given as strings
# to avoid floating point errors.
# Penalties have negative values (leading
# negative sign), bonuses are positive (no
# leading sign).
"note": "",
"timestamp":"2015-07-02T19:47:00",
"id": 543, # The ID number of the modifier.
"void": null # If a modifier has not been voided (i.e.: it is
# still active), this member will be null.
},
{
"type": "relative",
"value": 0.1, # Relative modifiers are given as double
# precision floating point numbers representing a
# percentage bonus or penalty (using the same
# logic as absolute modifiers: positive is bonus,
# negative is penalty).
"note": "Happy little bonus",
"timestamp": "2010-12-24T12:24:10",
"id": 9001,
# If the modifier has been voided, instead of None, the value
# will be similar to this:
"void": {
"timestamp": "2014-07-02T19:26:00", # When the modifier was
# voided.
"user": { # The user that voided this modifier
"id": 42,
"name": "paxswill"
}
}
}
]
}
A location within the Eve universe.
Key Name | Description |
---|---|
system |
An object for a solar system. |
constellation |
An object for the constellation system is in. |
region |
An object for the region that constellation is in. |
Each of these objects are described in the Eve items section.
Each of the values in this object are an object with a name
and id
key.
name
will be a string with the human-readable name of the item in question in
English. id
will be a number with the integer ID number used by Eve for that
entity.
{
"system": {
"id": 30001160,
"name": "WD-VTV"
},
"constellation": {
"id": 20000169,
"name": "UX3-N2"
},
"region": {
"id": 10000014,
"name": "Catch"
}
}
An object describing a player's character within Eve.
Key Name | Description |
---|---|
id |
The Eve ID number for this pilot. |
name |
A string with the name of this pilot. |
corporation |
An Eve object for the corporation this pilot is in. |
alliance |
If the corporation is in an alliance, this value will be an Eve object for that alliance. Otherwise, it will be null . |
A pilot in a coproation that is in an alliance:
{
"id": 570140137,
"name": "Paxswill",
"corporation": {
"id": 1018389948,
"name": "Dreddit"
},
"alliance": {
"id": 498125261,
"name": "Test Alliance Please Ignore"
}
}
A pilot in a corporation that is not in an alliance.
{
"id": 93260529,
"name": "Aimi Shihari",
"corporation": {
"id": 98261309,
"name": "Such Corporation"
},
"alliance": null
}
A User is the person who owns the account that a pilot is associated with.
Key Name | Description |
---|---|
id |
The unique ID number for this user. This value is internal to the app and has no meaning outside of it. It will not change once it has been assigned. |
name |
In contrast to id , the display name of the user may change, and is not guaranteed to be unique. |
notes |
An array of notes left about this user. If a user does not have any notes, the array will be empty. |
A User may have notes attached to them by other users with the reviewer, payer or admin permission. They can only be seen by users with the reviewer, payer, auditor or admin permission in the division that created them.
Key Name | Description |
---|---|
note |
The text of the note. |
timestamp |
The date and time this note was made. |
submitter |
A user object (without a notes key and value) for the user that left this note. |
division |
The division that this note was made from. |
{
"id": 42,
"name": "paxswill",
"notes": [
{
"note": "A note about the user.",
"timestamp": "2016-04-30T21:17:35",
"submitter": {
"id": 42,
"name": "paxswill"
}
}
]
}
A division is an administrative section that a user can submit requests for reimbursement too. Each division will have sets of people who will be able to submit requests within, review requests within the division to set a payout and approve or reject them, mark those same requests as paid, audit made requests in a division, or administer that division.
Key Name | Description |
---|---|
id |
The unique ID number for this division. It is only unique within the set of all divisions in this app, and will not change. |
name |
The name of this division. This is not guaranteed to not change in the future. |
permissions |
A permissions object. |
permissions |
An object with values being arrays of permission objects with the keys being one of "submit" , "review" , "pay" , "audit" , or "admin" corresponding to that role within the division. |
Keys are one of "submit"
, "review"
, "pay"
, "audit"
, and "admin"
corresponding to that role within the division, values are an array of objects
corresponding to users or groups that have that role. The objects will have
name
, id
and type
keys, type
being one of the strings user
or group
and the other two keys being self explanatory.
{
"id": 1,
"name": "Example Division",
"permissions": {
"submit": [
{
"id": 23,
"name": "paxswill",
"type": "user"
},
{
"id": 39,
"name": "Test Alliance",
"type": "group"
}
],
"review": [],
"pay": [],
"audit": [],
"admin": [
{
"id": 23,
"name": "paxswill",
"type": "user"
}
]
}
}
A request made to a division to reimburse a user for the loss detailed in a
killmail. the payout
and base_payout
keys are strings of a fixed-point
number. Instead of using a native JSON number, we're using a string to try to
maintain data integrity as much as possible and avoid floating-point issues.
Key Name | Description |
---|---|
id |
A unique ID number for this specific request. Other requests for this killmail will have different IDs. |
details |
A string containing additional information about the request. |
timestamp |
The date and time a request was submitted/created. |
division |
A division object without the permissions key. |
actions |
An array of action objects, in reverse chronological order. |
modifiers |
An aray of modifier objects, in chronological order. |
base_payout |
The base payout amount for this request, as a string. |
payout |
The total payout for this request, computed from the base payout and modifiers. |
status |
The current status of this request. Will be one of evaluating , approved , incomplete , rejected or paid . |
{
"details": "I literally forgot how to broadcast for armor.",
"timestamp": "2014-07-09T19:43:58.126158",
"id": 70,
"division": {
"id": 2,
"name": "A Second Division"
},
"actions": [
{
"user": {
"id": 42,
"name": "paxswill"
},
"type": "comment",
"note": "",
"timestamp": "2015-07-02T19:47:00",
"id": 230
}
],
"modifiers": [
{
"type": "absolute",
"value": "-5000000",
"note": "",
"timestamp":"2015-07-02T19:47:00",
"id": 543,
"void": null
},
{
"type": "relative",
"value": 0.1,
"note": "Happy little bonus",
"timestamp": "2010-12-24T12:24:10",
"id": 9001,
"void": {
"timestamp": "2014-07-02T19:26:00",
"user": {
"id": 42,
"name": "paxswill"
}
}
}
],
"base_payout": "100000000",
"payout": "142500000",
"status": "approved"
}
Actions are the way reviewers and payers change the status of a request. THey are also the way users can add a comment to a request.
Key Name | Description |
---|---|
user |
The user who created the action. |
type |
A string of either comment , evaluating , approved , incomplete , rejected , or paid . When something other than comment , this action changes the request's status. |
note |
A string containing additional information about this action. |
timestamp |
The date and time this action was created. |
id |
A unique ID number for this action. |
{
"user": {
"id": 42,
"name": "paxswill"
},
"type": "comment",
"note": "",
"timestamp": "2015-07-02T19:47:00",
"id": 230
}
Modifiers provide a way for reviewers to change the base payout of a request, by either increasing or decreasing the final payout. There are two kinds of modifiers available; absolute and relative. Absolute modifiers change the final payout by a set amount that does not depend on the value of the base payout. Relative modifiers on the other hand modify the final payout as a percentage of the base payout. If a modifier has a positive value, it will increase the final payout, while negative values will decrease it.
Key Name | Description |
---|---|
type |
A string of either absolute or relative
|
value |
For an absolute modifier, a string of a fixed-point number. For a relative modifier, a double precision floating point number representing a percentage. |
note |
A string containing a note about this modifier. May be an empty string. |
timestamp |
The date and time this modifier was initially created. |
id |
A unique ID number for this modifier. |
user |
A user object without the notes key for the user who added/created this modifier. |
void |
Either null if this modifier has not been voided, or a void object
|
If a modifier has been voided, it will have an object as the value for the
void
key.
Key Name | Description |
---|---|
timestamp |
The date and time the modifier was voided. |
user |
A user object without the notes key for the user who voided the modifier. |
An absolute modifier that has not been voided.
{
"type": "absolute",
"value": "-5000000",
"note": "",
"timestamp":"2015-07-02T19:47:00",
"id": 543,
"user": {
"id": 42,
"name": "paxswill"
},
"void": null
}
A relative modifier that has been voided.
{
"type": "relative",
"value": 0.1,
"note": "Happy little bonus",
"timestamp": "2010-12-24T12:24:10",
"id": 9001,
"user": {
"id": 22,
"name": "Aimi Shihari"
},
"void": {
"timestamp": "2014-07-02T19:26:00",
"user": {
"id": 42,
"name": "paxswill"
}
}
}