{
  "info": {
    "_postman_id": "2d779d98-f3dd-4fc8-9a84-040000000001",
    "name": "Voyced API v1",
    "description": "Voyced API collection for Sandbox-first testing. Import the separate environment, select it, add credentials there, then run request 1.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "version": {
      "major": 0,
      "minor": 4,
      "patch": 0
    }
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{access_token}}",
        "type": "string"
      }
    ]
  },
  "item": [
    {
      "name": "1. Request bearer token",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"api_key\", \"api_secret\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Token request succeeded', () => pm.response.to.have.status(200));",
              "const body = pm.response.json();",
              "pm.test('Bearer token returned', () => pm.expect(body.data && body.data.access_token).to.be.a('string').and.not.empty);",
              "if (body.data && body.data.access_token) { pm.environment.set('access_token', body.data.access_token); pm.environment.set('access_token_expires_at', body.data.expires_at || ''); }"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "description": "Run this first. The test script stores the returned token automatically.",
        "url": "{{base_url}}/auth/token",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"api_key\": \"{{api_key}}\",\n  \"api_secret\": \"{{api_secret}}\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "auth": {
          "type": "noauth"
        }
      }
    },
    {
      "name": "2. Test connection",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Confirm authentication and customer access.",
        "url": "{{base_url}}/test"
      }
    },
    {
      "name": "3. Capabilities",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read the exact functions and permissions enabled for this API key.",
        "url": "{{base_url}}/capabilities"
      }
    },
    {
      "name": "4. Customer",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read the customer summary.",
        "url": "{{base_url}}/customer"
      }
    },
    {
      "name": "5. Telephone numbers",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "List active telephone numbers.",
        "url": "{{base_url}}/numbers"
      }
    },
    {
      "name": "6. One telephone number",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"telephone_number\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read one active telephone number.",
        "url": "{{base_url}}/numbers/{{telephone_number}}"
      }
    },
    {
      "name": "7. Call credit balance",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read the current reported call credit balance.",
        "url": "{{base_url}}/balance"
      }
    },
    {
      "name": "8. Read Follow-Me",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"telephone_number\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read Follow-Me for one active number.",
        "url": "{{base_url}}/numbers/{{telephone_number}}/follow-me"
      }
    },
    {
      "name": "9. Update Follow-Me",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"telephone_number\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "description": "Replace supported Follow-Me settings for one active number.",
        "url": "{{base_url}}/numbers/{{telephone_number}}/follow-me",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"sequence\": \"ordered\",\n  \"timeout_seconds\": 45,\n  \"max_forwards\": 3,\n  \"destinations\": [\n    {\n      \"name\": \"Mobile\",\n      \"number\": \"+442079460001\",\n      \"enabled\": true,\n      \"ring_seconds\": 20,\n      \"period\": \"\"\n    }\n  ]\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "10. Call history and xDRs",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read the last seven days of call history. Add supported query parameters when needed.",
        "url": "{{base_url}}/calls"
      }
    },
    {
      "name": "11. Call queues",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "List call queues.",
        "url": "{{base_url}}/call-queues"
      }
    },
    {
      "name": "12. One call queue",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"queue_id\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read one call queue.",
        "url": "{{base_url}}/call-queues/{{queue_id}}"
      }
    },
    {
      "name": "13. Update call queue",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"queue_id\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "PATCH",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "description": "Update supported fields on one call queue.",
        "url": "{{base_url}}/call-queues/{{queue_id}}",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"capacity\": 25,\n  \"incoming_capacity\": 12,\n  \"average_duration_minutes\": 3,\n  \"announce_number_of_callers\": true,\n  \"announce_estimated_wait_time\": true,\n  \"announcement_interval_minutes\": 2\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "14. IVR and auto-attendant menus",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "List IVR and auto-attendant menus.",
        "url": "{{base_url}}/ivrs"
      }
    },
    {
      "name": "15. One IVR menu",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"ivr_id\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "description": "Read one IVR menu.",
        "url": "{{base_url}}/ivrs/{{ivr_id}}"
      }
    },
    {
      "name": "16. Update IVR menu",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const missing = [];",
              "const required = [\"base_url\", \"access_token\", \"ivr_id\"];",
              "required.forEach(name => { if (!pm.environment.get(name)) missing.push(name); });",
              "if (!pm.environment.name) throw new Error('Select the Voyced Sandbox environment before running this request.');",
              "if (missing.length) throw new Error('Open the selected Voyced environment and enter: ' + missing.join(', ') + '.');"
            ]
          }
        }
      ],
      "request": {
        "method": "PATCH",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "description": "Update supported fields on one IVR menu.",
        "url": "{{base_url}}/ivrs/{{ivr_id}}",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"schedule\": \"always\",\n  \"schedule_description\": \"All hours\",\n  \"replay_count\": 3,\n  \"first_digit_timeout_seconds\": 10,\n  \"next_digit_timeout_seconds\": 5,\n  \"direct_dial_enabled\": true\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    }
  ]
}