{
  "info": {
    "name": "Hometown Workforce Estimate API",
    "description": "Generated from https://api.wfskills.com/openapi/v1.json. Set apiKey to a hw_test_ key to try the sandbox.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.wfskills.com/v1"
    },
    {
      "key": "apiKey",
      "value": "hw_test_..."
    }
  ],
  "item": [
    {
      "name": "Estimates",
      "item": [
        {
          "name": "List estimates, newest first",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/estimates?limit=&starting_after=&status=&from=&to=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "estimates"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last estimate of the previous page."
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "from",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "",
                  "disabled": true
                }
              ],
              "variable": []
            }
          }
        },
        {
          "name": "Estimate a job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/estimates",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "estimates"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"input\": {\n    \"text\": \"Install 100 linear feet of wood privacy fence, 6 ft tall\"\n  },\n  \"region\": \"US-MS\",\n  \"metadata\": {\n    \"order_ref\": \"A-1042\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "10 credits for text or a conversation, 25 with photos. A priced, needs_detail, unsupported or unclear answer spends them; any 4xx or 5xx does not. A test key never spends credits; input.text starting with `sandbox:` answers from the sandbox."
          }
        },
        {
          "name": "Get an estimate",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/estimates/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "estimates",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            }
          }
        },
        {
          "name": "Delete an estimate",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/estimates/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "estimates",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deletes the estimate, its follow-ups and everything they held, at once. A follow-up carries the text of the estimate it answers, so it is deleted with it. Deleting a follow-up leaves the estimate it answered."
          }
        },
        {
          "name": "Answer an estimate's question and estimate again",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/estimates/:id/follow-up",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "estimates",
                ":id",
                "follow-up"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"input\": {\n    \"messages\": [\n      {\n        \"role\": \"customer\",\n        \"content\": \"About 100 feet\"\n      }\n    ]\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "5 credits. The earlier exchange is carried over; send only what the customer says now."
          }
        }
      ]
    },
    {
      "name": "Tasks",
      "item": [
        {
          "name": "The jobs that can be priced in a region",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/tasks?region=US-MS&limit=&starting_after=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "tasks"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "US-MS",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true
                }
              ],
              "variable": []
            }
          }
        }
      ]
    },
    {
      "name": "Regions",
      "item": [
        {
          "name": "Regions, their currency, language and time zone",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/regions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "regions"
              ],
              "query": [],
              "variable": []
            }
          }
        }
      ]
    },
    {
      "name": "Usage",
      "item": [
        {
          "name": "Requests, errors, credits and p95 latency, by day or route",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/usage?from=&to=&group_by=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "usage"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "disabled": true,
                  "description": "First day, in UTC. Defaults to 29 days before today. The range covers at most 90 days."
                },
                {
                  "key": "to",
                  "value": "",
                  "disabled": true,
                  "description": "Last day, in UTC, on or after from. Defaults to today."
                },
                {
                  "key": "group_by",
                  "value": "",
                  "disabled": true
                }
              ],
              "variable": []
            }
          }
        }
      ]
    },
    {
      "name": "Balance",
      "item": [
        {
          "name": "Credits available, by lot",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/balance",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "balance"
              ],
              "query": [],
              "variable": []
            }
          }
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "The account and key making the call",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "me"
              ],
              "query": [],
              "variable": []
            }
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "List webhook endpoints",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints?limit=&starting_after=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last item of the previous page."
                }
              ],
              "variable": []
            },
            "description": "The endpoints of the key's environment, newest first."
          }
        },
        {
          "name": "Create a webhook endpoint",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://example.com/hooks/hometown\",\n  \"description\": \"production\",\n  \"events\": [\n    \"estimate.completed\",\n    \"estimate.failed\",\n    \"credits.low\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Hometown checks the URL before it is saved. It must use HTTPS on port 443 or 1024 to 65535, resolve to public addresses only and answer without a redirect. An environment has at most 16 active endpoints. The answer carries the signing secret, which is not shown again. This operation takes no Idempotency-Key, so the secret is never stored for a replay."
          }
        },
        {
          "name": "Get a webhook endpoint",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            }
          }
        },
        {
          "name": "Update a webhook endpoint",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"active\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Change the URL, the description or the events, or enable or disable the endpoint. A new URL is checked like on create."
          }
        },
        {
          "name": "Delete a webhook endpoint",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deliveries still waiting for it are dropped, and its delivery history goes with it."
          }
        },
        {
          "name": "Rotate the signing secret",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints/:id/rotate_secret",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints",
                ":id",
                "rotate_secret"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "A new secret signs every delivery from now on. For 24 hours the previous secret signs too, as a second v1 in Hometown-Signature, so receivers can switch without missing an event."
          }
        },
        {
          "name": "Send a test event",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/webhook_endpoints/:id/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "webhook_endpoints",
                ":id",
                "test"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Sends webhook.test to this endpoint, signed like any event, whatever events it subscribes to and even while it is disabled. It is tried once and never retried; GET the event to read the answer."
          }
        }
      ]
    },
    {
      "name": "Events",
      "item": [
        {
          "name": "List events, newest first",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/events?limit=&starting_after=&type=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "events"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last item of the previous page."
                },
                {
                  "key": "type",
                  "value": "",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "description": "Events of the key's environment from the last 30 days."
          }
        },
        {
          "name": "Get an event and its deliveries",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/events/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "events",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "The event as receivers got it, and every delivery attempt with what the endpoint answered."
          }
        },
        {
          "name": "Send an event again",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/events/:id/redeliver",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "events",
                ":id",
                "redeliver"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Sends the event again with the same body and Hometown-Event-Id. By default it goes to every active endpoint that listens to its type. With endpoint, it goes only to that endpoint, if it is active. An event older than 30 days answers 422 event_not_redeliverable, or 404 not_found once it has been deleted."
          }
        }
      ]
    },
    {
      "name": "Customers",
      "item": [
        {
          "name": "List customers",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers?limit=&starting_after=&external_id=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last item of the previous page."
                },
                {
                  "key": "external_id",
                  "value": "",
                  "disabled": true,
                  "description": "Only the customer with this external_id."
                }
              ],
              "variable": []
            },
            "description": "The customers of the key's environment, newest first. Needs the Records add-on and the `customers:write` scope."
          }
        },
        {
          "name": "Create a customer",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/customers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_id\": \"crm-2291\",\n  \"name\": \"Dana Reyes\",\n  \"phone\": \"+16015550123\",\n  \"email\": \"dana@example.com\",\n  \"region_code\": \"US-MS\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "external_id is your own id for the customer and is unique in each environment. Phone and email are stored encrypted. Customers and records share a cap of 50,000 per environment. Needs the Records add-on and the `customers:write` scope."
          }
        },
        {
          "name": "Get a customer",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Needs the Records add-on and the `customers:write` scope."
          }
        },
        {
          "name": "Update a customer",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/customers/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phone\": \"+16015550188\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Send only the fields to change; null clears a field. Needs the Records add-on and the `customers:write` scope."
          }
        },
        {
          "name": "Delete a customer",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "The customer is erased at once with its phone and email. Estimates linked to it stay and lose the link. Needs the Records add-on and the `customers:write` scope."
          }
        },
        {
          "name": "List a customer's estimates",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers/:id/estimates?limit=&starting_after=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "customers",
                ":id",
                "estimates"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last item of the previous page."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Estimates created with this customer_id, and their follow-ups, newest first. Needs the Records add-on and the `customers:write` scope."
          }
        }
      ]
    },
    {
      "name": "Records",
      "item": [
        {
          "name": "List records",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/records/:collection?limit=&starting_after=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "records",
                ":collection"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "disabled": true,
                  "description": "The id of the last record of the previous page."
                }
              ],
              "variable": [
                {
                  "key": "collection",
                  "value": "jobs"
                }
              ]
            },
            "description": "The records of a collection in the key's environment, by id in ascending order. Needs the Records add-on and the `records:read` scope."
          }
        },
        {
          "name": "Get a record",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/records/:collection/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "records",
                ":collection",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "collection",
                  "value": "jobs"
                },
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Needs the Records add-on and the `records:read` scope."
          }
        },
        {
          "name": "Create or replace a record",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/records/:collection/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "records",
                ":collection",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "collection",
                  "value": "jobs"
                },
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"payload\": {\n    \"title\": \"Back fence\",\n    \"status\": \"scheduled\"\n  },\n  \"updated_at_ms\": 1760100000000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Creates the record, or replaces its payload when updated_at_ms is equal to or later than the stored one. An older write changes nothing and answers with the stored record. The payload is a JSON object of at most 64 KB. Needs the Records add-on and the `records:write` scope."
          }
        },
        {
          "name": "Delete a record",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/records/:collection/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "records",
                ":collection",
                ":id"
              ],
              "query": [],
              "variable": [
                {
                  "key": "collection",
                  "value": "jobs"
                },
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "The record is erased at once. Needs the Records add-on and the `records:write` scope."
          }
        }
      ]
    },
    {
      "name": "Billing",
      "item": [
        {
          "name": "Open a Checkout page",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/billing/checkout",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "billing",
                "checkout"
              ],
              "query": [],
              "variable": []
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"pack\": \"credits_10000\",\n  \"success_url\": \"https://example.com/billing/done\",\n  \"cancel_url\": \"https://example.com/billing\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Opens a Stripe Checkout page to buy a credit pack, the Business plan or the Records add-on. Send the customer to url; credits arrive when the invoice is paid, a few seconds after the payment, never when the page returns. Needs a live key with the `billing:manage` scope and a billing profile with the legal name, address and country, which the dashboard keeps."
          }
        }
      ]
    }
  ]
}
