{"info":{"_postman_id":"f1e51280-8897-4ddf-a867-c8c2ddcba844","name":"Posthook","description":"The **Posthook** API lets developers schedule requests to be made back to their application at specified times in the future.\n\n```shell\ncurl https://api.posthook.io/v1/hooks \\\n  -H 'X-API-Key: {{apiKey}}' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n        \"path\": \"/webhooks/ph/event_reminder\",\n        \"postAt\": \"2018-05-03T01:11:55Z\",\n        \"data\": {\n          \"eventID\": 25\n        }\n      }'\n```\n\nThis is the main API call your application will be making to schedule new **Hooks**. **Posthook** will then wait until the **postAt** time and attempt to call back to your application as explained in the \"Hooks Fulfillment\" section below.\n\nNote that the domain is not specified when scheduling new **Hooks**. This is because we tie the domains to **Projects** in order to allow domains to be changed without having to change all your scheduled hooks for that project. Also note that we only support calling back to your application in **HTTPS** so your webhooks handling **Posthook** requests will need to served in **HTTPS**.\n\n\n# Authentication\n\nWe use API Keys for Authentication. You can retrieve your API Key under your [Account Settings](https://posthook.io/app/account#projects). Provide your API Key as the value for the `X-API-Key` header.\n\nAll API requests must be made over [HTTPS](https://en.wikipedia.org/wiki/HTTPS) and include an API Key.\n\n# Hook Fulfillment\n\nPosthook will try to make a POST request to your application at the specified *postAt* time **at least once** for each **Hook**. Even though in most cases this request will only happen once per hook, it is possible that in certain failure scenarios it will happen more than once. If your use case requires an action to happen only once it is recommended you validate it still needs to happen by checking in a database, for example.\n\nThis request can be replicated with this example curl:\n\n```shell\ncurl https://www.example.com/webhooks/ph/event_reminder \\\n-H `User-Agent: Posthook/1.0` \\\n-H `Content-Type: application/json` \\\n-H `X-Ph-Signature: 428354c940d6c634291f70537d202517466191f0b50c07bbe7f4307be11765ec` \\\n-d `{\n\t\t\"id\":\"98ff3a11-7677-480b-9f40-8c1035e09381\",\n\t\t\"path\":\"/webhooks/ph/event_reminder\",\n\t\t\"postAt\":\"2018-05-03T01:11:55Z\",\n\t\t\"postedAt\":\"2018-05-03T01:11:55.0107686Z\",\n\t\t\"data\":{\n\t\t\t\"eventID\":25\n\t\t},\n\t\t\"createdAt\":\"2018-05-03T01:11:52.466482Z\",\n\t\t\"updatedAt\":\"2018-05-03T01:11:53.460343Z\"\n\t}`\n```\n\nPosthook, by default will attempt to make this request twice, waiting for 5 seconds after the first attempt. This behavior can be modified under your [**Project**'s settings](https://posthook.io/app/account#projects). It will consider a failure any response with a status code that is not '200'. It will also timeout and consider a failure any request taking longer than 10 seconds, so it is important to do any long-running work asynchronously to avoid the request timing out and potentially retried. After Posthook has exhausted the number of retries configured for the project, it will notify you based on your [notification settings](https://posthook.io/app/account#notifications) and set the Hook's status to \"failed\". Your application would then able to recover from failed hooks by querying the `/v1/hooks` endpoint for failed hooks and catching up on the appropriate work.\n\n## Security\n\n**Calls back to your application are made over HTTPS only**. If you are developing locally we recommend using a service like [ngrok](https://ngrok.com/). These calls back also include a `X-Ph-Signature` header. Your application can optionally (though highly recommended, but depends on how you're using Posthook) verify that requests are coming from **Posthook** by verifying this signature. The signature is generated using a hash-based message authentication code ([HMAC](https://en.wikipedia.org/wiki/HMAC)) with [SHA-256](https://en.wikipedia.org/wiki/SHA-2). Compute the HMAC using the JSON payload (the request body) and your account's [signing key](https://posthook.io/app/account#signing_key) and compare it to the signature in the `X-Ph-Signature` header in the request.\n\n# Sequences\n\nSequences let you configure Posthook to automatically create hooks given a start date/time, an interval, and a list of paths.\n\n## Settings\n\n### Name\n\nA name to help you identify the Sequence.\n\n### Start At\n\nDate and time when the Sequence will first run at.\n\n### Repeat Interval\n\nThe time interval between each run of the Sequence.\n\nIf *Start At* is set to `2018-01-01T01:15:00Z`, a repeat interval set to 1 hour will run the Sequence at every 15 minutes past the hour.\n\n### Steps\n\nA set of paths hooks will be created for and the dependencies between them (in YAML format).\n\nEach step has two properties:\n\n**path (required)**: the URL path for this step in the Sequence\n\n**requires (optional)** : a list of steps that are required to run successfully before this step's hook will be created\n\nIn the example below, *getExchangeRates* and *getWeather* will both start running at the beginning of the Sequence. If they are both successful, *refreshCache* will run. And finally, *reportSuccess* will run if *refreshCache* is successful.\n\n```shell\ngetExchangeRates:\n  path: /ph/get_exchange_rates\ngetWeather:\n  path: /ph/get_weather\nrefreshCache:\n  path: /ph/refresh_cache\n  requires:\n    - getExchangeRates\n    - getWeather\nreportSuccess:\n  path: /ph/report_success_slack\n  requires:\n    - refreshCache\n```\n","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json"},"item":[{"name":"Hooks","item":[{"name":"Schedule a Hook","id":"f8d16c35-43d4-4b56-850b-4380e8b1eca3","request":{"auth":{"type":"noauth"},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-API-Key","value":"{{apiKey}}"}],"body":{"mode":"raw","raw":"{\n\t\"path\": \"/webhooks/ph/event_reminder\",\n\t\"postAt\": \"2018-06-15T21:00:00.000Z\",\n\t\"data\": {\n\t  \"eventID\": 25\n\t}\n}"},"url":"{{apiBaseURL}}/hooks","description":"Create a new hook to schedule a time for Posthook to make a request to your application.\n\n\n### Arguments\nParameter | Description\n--------- | -----------\npath _string_  **required** | The path Posthook will make a POST request to to fulfill the hook\npostAt _timestamp_ **required** | The time Posthook will attempt to make a request to your application in [RFC 3339](https://tools.ietf.org/html/rfc3339) format\ndata _object_ | optional JSON object you want to be included in the request back to your application\n\n> Even though an offset from UTC is accepted in the `postAt` parameter, it refers to a specific point in time and gets stored as UTC. It is up to the developer to ensure that this is either converted to UTC or has the correct offset.\n\n### Errors\n\nStatus Code | Description\n--------- | -----------\n400 | Bad Request. See response body for details.\n401 | Unauthorized. Verify the API Key is valid.\n413 | Request entity too large. Request body must be smaller than 64 KB.\n429 | Hooks quota exceeded.\n500 | Internal Server Error. Contact support@posthook.io.\n"},"response":[{"id":"679eaaf5-b091-406c-974a-3e9e034ea086","name":"Schedule a Hook","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json","disabled":false},{"key":"X-API-Key","value":"{{apiKey}}","disabled":false}],"body":{"mode":"raw","raw":"{\n\t\"path\": \"/webhooks/ph/event_reminder\",\n\t\"postAt\": \"2018-06-15T21:00:00.000Z\",\n\t\"data\": {\n\t  \"eventID\": 25\n\t}\n}"},"url":"{{apiBaseURL}}/hooks"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Length","value":"248","name":"Content-Length","description":"The length of the response body in octets (8-bit bytes)"},{"key":"Content-Type","value":"application/json","name":"Content-Type","description":"The mime type of this content"},{"key":"Date","value":"Mon, 09 Apr 2018 20:43:24 GMT","name":"Date","description":"The date and time that the message was sent"},{"key":"Vary","value":"Origin","name":"Vary","description":"Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server."}],"cookie":[],"responseTime":null,"body":"{\n    \"data\": {\n        \"id\": \"0525baf7-79f9-4991-bb39-6a601ead00e5\",\n        \"path\": \"/webhooks/ph/event_reminder\",\n        \"data\": {\n            \"eventID\": 25\n        },\n        \"postAt\": \"2018-06-15T21:00:00Z\",\n        \"status\": \"pending\",\n        \"createdAt\": \"2018-04-09T20:43:24.321778Z\",\n        \"updatedAt\": \"2018-04-09T20:43:24.321778Z\"\n    }\n}"}],"_postman_id":"f8d16c35-43d4-4b56-850b-4380e8b1eca3"},{"name":"Get Hooks","id":"d219deb5-7915-42bc-96b3-34f255569161","request":{"auth":{"type":"noauth"},"method":"GET","header":[{"key":"X-API-Key","value":"{{apiKey}}"}],"url":{"raw":"{{apiBaseURL}}/hooks?limit=100&status=pending&sortBy=postAt&sortOrder=ASC&postAtBefore=2018-08-01T00:00:00Z&postAtAfter=2018-07-01T00:00:00Z&createdAtBefore=2018-08-01T00:00:00Z&createdAtAfter=2018-03-01T00:00:00Z","host":["{{apiBaseURL}}"],"path":["hooks"],"query":[{"key":"limit","value":"100","description":"Maximum number of Hooks to return"},{"key":"status","value":"pending","description":"Only show hooks in this status (pending, completed or failed)"},{"key":"sortBy","value":"postAt","description":"postAt or createdAt"},{"key":"sortOrder","value":"ASC","description":"ASC or DESC"},{"key":"postAtBefore","value":"2018-08-01T00:00:00Z","description":"Return hooks set to postAt before this time"},{"key":"postAtAfter","value":"2018-07-01T00:00:00Z","description":"Return hooks set to postAt after this time"},{"key":"createdAtBefore","value":"2018-08-01T00:00:00Z","description":"Return hooks created at before this time"},{"key":"createdAtAfter","value":"2018-03-01T00:00:00Z","description":"Return hooks created at after this time"}]},"description":"Get Hooks that have already been scheduled."},"response":[{"id":"29eb1529-8691-4dc0-bd1c-bf9cb17022fd","name":"Get Hooks","originalRequest":{"method":"GET","header":[{"key":"X-API-Key","value":"{{apiKey}}"}],"url":{"raw":"{{apiBaseURL}}/hooks?limit=100&postAtBefore=2018-08-01T00:00:00Z&status=pending","host":["{{apiBaseURL}}"],"path":["hooks"],"query":[{"key":"limit","value":"100","description":"Maximum number of Hooks to return"},{"key":"postAtBefore","value":"2018-08-01T00:00:00Z","description":"Return hooks with the postAt time set before this time"},{"key":"status","value":"pending","description":"Only show hooks in this status (pending, completed or failed)"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Length","value":"797","name":"Content-Length","description":"The length of the response body in octets (8-bit bytes)"},{"key":"Content-Type","value":"application/json","name":"Content-Type","description":"The mime type of this content"},{"key":"Date","value":"Mon, 30 Apr 2018 17:46:26 GMT","name":"Date","description":"The date and time that the message was sent"},{"key":"Vary","value":"Origin","name":"Vary","description":"Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server."}],"cookie":[],"responseTime":null,"body":"{\n    \"data\": [\n        {\n            \"id\": \"8e3aa909-fb84-4495-944d-a4c192defe66\",\n            \"path\": \"/webhooks/ph/event_reminder\",\n            \"domain\": \"posthook.io\",\n            \"data\": {\n                \"eventID\": 25\n            },\n            \"postAt\": \"2018-07-19T21:00:00Z\",\n            \"status\": \"pending\",\n            \"createdAt\": \"2018-04-30T17:45:20.68114Z\",\n            \"updatedAt\": \"2018-04-30T17:45:20.68114Z\"\n        },\n        {\n            \"id\": \"c1ec9560-65fc-4b88-bfe0-1bc6e56cb3db\",\n            \"path\": \"/webhooks/ph/event_reminder\",\n            \"domain\": \"posthook.io\",\n            \"data\": {\n                \"eventID\": 25\n            },\n            \"postAt\": \"2018-07-17T21:00:00Z\",\n            \"status\": \"pending\",\n            \"createdAt\": \"2018-04-30T17:45:16.097812Z\",\n            \"updatedAt\": \"2018-04-30T17:45:16.097812Z\"\n        },\n        {\n            \"id\": \"6ab4d4d5-4767-452d-b72f-6ec40562b27e\",\n            \"path\": \"/webhooks/ph/event_reminder\",\n            \"domain\": \"posthook.io\",\n            \"data\": {\n                \"eventID\": 25\n            },\n            \"postAt\": \"2018-07-15T21:00:00Z\",\n            \"status\": \"pending\",\n            \"createdAt\": \"2018-04-30T17:45:06.475047Z\",\n            \"updatedAt\": \"2018-04-30T17:45:06.475047Z\"\n        }\n    ]\n}"}],"_postman_id":"d219deb5-7915-42bc-96b3-34f255569161"},{"name":"Get a Hook","id":"e00b22ae-2caa-46eb-b011-44bfd7bcc978","request":{"auth":{"type":"noauth"},"method":"GET","header":[{"key":"Content-Type","value":"application/json","disabled":true},{"key":"X-API-Key","value":"{{apiKey}}"}],"url":"{{apiBaseURL}}/hooks/bbc8b97b-dda7-47f4-bff5-bc729b310ea1","description":"Get a specific Hook."},"response":[{"id":"611399e3-fb12-421c-b360-6aab342881df","name":"Get a Hook","originalRequest":{"method":"GET","header":[{"key":"X-API-Key","value":"{{apiKey}}","disabled":false}],"url":"{{apiBaseURL}}/hooks/8e3aa909-fb84-4495-944d-a4c192defe66"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Length","value":"269","name":"Content-Length","description":"The length of the response body in octets (8-bit bytes)"},{"key":"Content-Type","value":"application/json","name":"Content-Type","description":"The mime type of this content"},{"key":"Date","value":"Mon, 30 Apr 2018 17:49:25 GMT","name":"Date","description":"The date and time that the message was sent"},{"key":"Vary","value":"Origin","name":"Vary","description":"Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server."}],"cookie":[],"responseTime":null,"body":"{\n    \"data\": {\n        \"id\": \"8e3aa909-fb84-4495-944d-a4c192defe66\",\n        \"path\": \"/webhooks/ph/event_reminder\",\n        \"domain\": \"posthook.io\",\n        \"data\": {\n            \"eventID\": 25\n        },\n        \"postAt\": \"2018-07-19T21:00:00Z\",\n        \"status\": \"pending\",\n        \"createdAt\": \"2018-04-30T17:45:20.68114Z\",\n        \"updatedAt\": \"2018-04-30T17:45:20.68114Z\"\n    }\n}"}],"_postman_id":"e00b22ae-2caa-46eb-b011-44bfd7bcc978"},{"name":"Delete a Hook","id":"55c69b2b-9e36-4305-9523-997091612095","request":{"auth":{"type":"noauth"},"method":"DELETE","header":[{"key":"X-API-Key","value":"{{apiKey}}"}],"body":{"mode":"raw","raw":""},"url":"{{apiBaseURL}}/hooks/acee432b-86a8-4511-ba64-a9b6969dd12a","description":"Delete a Hook. This will stop Posthook from making the request back to your application for this Hook."},"response":[{"id":"6540e89b-cdb5-4099-84bd-0f5b998aca65","name":"Delete a Hook","originalRequest":{"method":"DELETE","header":[{"key":"X-API-Key","value":"{{apiKey}}","disabled":false}],"body":{"mode":"raw","raw":""},"url":"{{apiBaseURL}}/hooks/bbc8b97b-dda7-47f4-bff5-bc729b310ea1"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Length","value":"11","name":"Content-Length","description":"The length of the response body in octets (8-bit bytes)"},{"key":"Content-Type","value":"application/json","name":"Content-Type","description":"The mime type of this content"},{"key":"Date","value":"Tue, 10 Apr 2018 18:48:14 GMT","name":"Date","description":"The date and time that the message was sent"},{"key":"Vary","value":"Origin","name":"Vary","description":"Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server."}],"cookie":[],"responseTime":null,"body":"{\"data\":{}}"}],"_postman_id":"55c69b2b-9e36-4305-9523-997091612095"}],"id":"e1c1422b-673d-4d85-bf7f-5d24f5c225d5","description":"A **Hook** is what you will be interacting with. It is a contract for **Posthook** to fulfill by attempting to make a POST request to your application.","event":[{"listen":"prerequest","script":{"id":"a8916162-e4eb-4db8-867d-0d5c7145569e","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"832c4cb1-ef17-4cb6-aece-e4c6d7d453cc","type":"text/javascript","exec":[""]}}],"_postman_id":"e1c1422b-673d-4d85-bf7f-5d24f5c225d5"},{"name":"Projects","item":[{"name":"Update Project","id":"b587c9d5-d9ad-43c8-b467-d256955bc4f5","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PUT","header":[{"key":"X-API-Key","value":"{{apiKey}}","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"name\": \"updated-project\",\n    \"domain\": \"api.example.com\",\n    \"headerAuthorization\": \"\",\n    \"minRetries\": 1,\n    \"retryDelaySecs\": 5\n}","options":{"raw":{"language":"json"}}},"url":"{{apiBaseURL}}/projects/{{projectID}}"},"response":[],"_postman_id":"b587c9d5-d9ad-43c8-b467-d256955bc4f5"}],"id":"f0241c70-d241-4a87-8e6e-3f77fb08c915","_postman_id":"f0241c70-d241-4a87-8e6e-3f77fb08c915"}],"event":[{"listen":"prerequest","script":{"id":"255c1e59-a422-40c0-8ba1-035a4dec0b48","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"ec4adce2-07d8-4b3c-af04-703d1ac455ae","type":"text/javascript","exec":[""]}}]}