A webhook is an array with two keys sent as a json encoded string using the php function json_encode() with no options set.
Each webhook has the key X-CI-AUTH in the header that contains a validation token that can be used to ensure that the webhook was indeed sent by courierinvoice. The token is a hash of the webhook, your account number, and the time value included in the webhook using your Private API Key.
$token = hash_hmac('sha256', $webhook . 'Your_Account_Number' . $timeVal, $privateKey);
The token should be regenerated in similar fashion and tested using the function hash_equals()
Retreived token:
$token = $_SERVER['HTTP_X_CI_AUTH'] ?? bin2hex(random_bytes(1e4));
or
$headers = array_change_key_case(getallheaders(), CASE_UPPER);
$token = $headers['X-CI-AUTH'] ?? bin2hex(random_bytes(1e4));
- Webhook structure:
- "timestamp": (integer) Timestamp generated by time()
- "Data": (array) This array contains the details of the webhook(s).
- [0] (object)
- "error": (string) Information regarding any problem encountered while creating the webhook. NULL if no problems are encountered.
- "type": (string) Dot-notated webhook type. Ex: "ticket.oncall.receive", "invoice.update"
- "BillTo": (integer) Billing client for either tickets or invoices. NULL in cases other than tickets, invoices, and contract runs.
- "DispatchedTo": (integer) Identifier associated with the driver a ticket is dispatched to. 0 (zero) if ticket is not dispatched. NULL in cases other than tickets and routes.
- "TicketNumber": (integer) Identifier associated with a ticket. NULL in cases other than tickets.
- "RouteName": (string) Identifies a route. NULL in cases other than routes and schedule overrides.
- "InvoiceNumber": (string) Identifier associated with an invoice. NULL in cases other than invoices.
- "ClientID": (integer) Identifier associated with a client. NULL in cases other than clients and o_clients.
- "DriverID": (integer) Identifier associated with driver. NULL in cases other than drivers.
- "DispatchID": (integer) Identifier associated with dispatcher. NULL in cases other than dispatchers.
- "RunNumber": (integer) Identifier associated with the contract run. NULL in cases other than contract runs and schedule overrides.
- "ScheduleID": (integer) Identifier associated with a schedule override event. NULL in cases other than schedule overrides.
- "stored": (object) Contains key-value pairs of information in the database and will be populated in all cases except DELETE. "stored" will have the following properties depending on the endpoint targeted:
- tickets
- ticket_index
- RepeatClient
- Charge
- RequestedBy
- ReceivedReady
- ReadyDate
- pClient
- pAddress1
- pAddress2
- pCountry
- pContact
- pTelephone
- dClient
- dAddress1
- dAddress2
- dCountry
- dContact
- dTelephone
- dryIce
- diWeight
- diPrice
- EmailConfirm
- EmailAddress
- pSigReq
- dSigReq
- d2SigReq
- InvoiceNumber
- TransferState
- PendingReciever
- pLat
- pLng
- dLat
- dLng
- d2Lat
- d2Lng
- pTimeStamp
- dTimeStamp
- d2TimeStamp
- DispatchTimeStamp
- ReceivedDate
- invoices
- invoice_index
- RepeatClient
- InvoiceTotal
- InvoiceSubTotal
- BalanceForwarded
- AmountDue
- StartDate
- EndDate
- DateIssued
- AmountPaid
- Balance
- CheckNumber
- Closed
- Deleted
- clients
- client_index
- RepeatClient
- ClientName
- Department
- ShippingAddress1
- ShippingAddress2
- ShippingCountry
- BillingName
- BillingAddress1
- BillingAddress2
- BillingCountry
- Telephone
- EmailAddress
- Attention
- Deleted
- o_clients
- o_client_index
- Name
- Login
- ListBy
- drivers
- driver_index
- FirstName
- LastName
- EmailAddress
- LastSeen
- LoggedIn
- CanDispatch
- dispatchers
- dispatch_index
- FirstName
- LastName
- EmailAddress
- LastSeen
- LoggedIn
- contract_runs
- crun_index
- pickup_id
- pClient
- pAddress1
- pAddress2
- pCountry
- pTelephone
- pContact
- dropoff_id
- dClient
- dAddress1
- dAddress2
- dCountry
- dTelephone
- dContact
- pTime
- dTime
- d2Time
- StartDate
- LastCompleted
- DryIce
- diWeight
- PriceOverride
- TicketPrice
- schedule_override
- s_o_index
- crun_index
- route_index
- Cancel
- StartDate
- EndDate
- pTime
- dTime
- d2Time
- contract_locations
- cloc_index
- Client
- Department
- Contact
- Address1
- Address2
- Country
- c_run_schedule
- routes
- route_index
- RouteName
- driver_index
- Overnight
- LastDispatched
- StartTime
- StartDate
- route_schedule
- webhooks
- webhook_index
- Protocol
- Listener
- Events
- Deleted
- "received": (object) contains key-value pairs of the information sent to the API.
To help prevent sending redundant webhooks, a webhook is created based first upon the type of request made to the API, then by what information is in the database and what information is sent with the request. For example, a PUT request to update an oncall ticket that has been picked up would include the data key "pTimeStamp" and, optionally, "Notes". A call to the database determines if the ticket is contract or on call. If only the one or two values are present the timestamp key will determine what step to include in the webhook. This example would result in a webhook of "ticket.oncall.pickup". If the ticket already had a value in the database for "pTimeStamp" or more values are sent then the webhook would be "ticket.oncall.update". If multiple timestamp keys are included in a request they are tested in reverse order (d2TimeStamp, dTimeStamp, pTimeStamp, DispatchTimeStamp, ReceivedDate) and the first key encountered determines which webhook is to be sent. If the call includes the TransferState key all timestamps are ignored and a transfer webhook is sent. So if a ticket is received and dispatched in the same call to the API only the dispatch webhook would be sent. If multiple resources are created / updated / deleted with a single call to the API then the Data array will contain a webhook for each resource.