# Service Requirement Answers

https://dev.wisecp.com/es/service-requirement-answers

The four endpoints that read, add, edit and delete a client's requirement answers on a service.

## Overview

A requirement is the question a product asks at order time; what is managed here are the **answers on a service**. The questions themselves are defined on the product side.

An answer comes from one of two sources. Ones **from a definition** are tied to a product requirement and carry its type, its options and its module mapping. **Free-form** ones carry nothing but a label and some content, added by hand later, and they never reach the module.

## Reference

### Listing the Answers

get/api/v1/admin/services/{id}/requirements

`Services/GetServiceRequirements` admin

Returns every requirement answer recorded on the service.

Response fields data[] — 8

idintId of the answer record. Update and delete use this one.

requirement_idintId of the product requirement definition behind it. Zero on a free-form one.

keystring`product` comes from a definition, `custom` was added freely.

namestringThe requirement name or label.

typestringThe field type: `text`, `select`, `radio`, `checkbox` or `file`.

responsestring | array 4 fieldsThe answer given. An array of file objects on the file type, plain text on the rest.

namestringThe name stored on the server.

file_namestringThe original name that was uploaded.

sizeintThe file size in bytes.

pathstringWhere the file is kept.

response_mkeystringWhat the choice maps to in the module. Filled on the choice types only, and resolved for you.

field_optionsarrayThe options the definition offers.

Errors 2

not_found404No such service.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/services/506/requirements' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/services/506/requirements', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/requirements');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Services()->GetServiceRequirements(['id' => 506]);

// 'response' changes shape by type: an array on file, text on the rest.
foreach ($response['data'] as $req) {
    $answer = $req['type'] === 'file'
        ? array_column($req['response'], 'file_name')
        : $req['response'];
}
```

Response 200

```json
{
  "data": [
    {
      "id": 12,
      "requirement_id": 22,
      "key": "product",
      "name": "Game Name",
      "type": "text",
      "response": "Minecraft",
      "response_mkey": "",
      "field_options": []
    }
  ]
}
```

### Adding an Answer

post/api/v1/admin/services/{id}/requirements

`Services/CreateServiceRequirement` admin two body shapes

Adds a requirement answer to the service, either from a definition or free-form.

Body — shared 1

sourcestringWhich body shape applies: `defined` ties it to a definition, `custom` adds it freely. Defaults to `defined`.

Body — from a definition 3

requirement_idintrequiredId of the product requirement definition to tie it to.

responsestring | arrayThe answer. On the choice types you send the option's **id** from the definition, not its text; for multiple choice a comma-separated list or an array.

filestringThe file input. Needed instead when the definition is a file type: a base64 data URI or a link that can be fetched.

Body — free-form 4

labelstringrequiredThe requirement label.

typestring`text` or `file`. Defaults to `text`; a free-form requirement has no choice types.

contentstringThe text answer. Needed on the text type.

filestringThe file input. Needed on the file type.

Response fields data

dataobjectThe answer that was created, returned with `201`. Same shape as one row of the list schema.

Errors 8

not_found404No such service.

requirement_id_required422No definition id was given when tying to one.

definition_not_found422The requirement definition was not found.

response_required422The answer was empty.

content_required422The text was empty.

label_required422The label was empty.

file_invalid422The file could not be read or stored.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/services/506/requirements' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"source":"custom","label":"Server Name","type":"text","content":"srv-01"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/requirements', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: 'custom',
    label: 'Server Name',
    type: 'text',
    content: 'srv-01',
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/requirements');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'source'  => 'custom',
        'label'   => 'Server Name',
        'type'    => 'text',
        'content' => 'srv-01',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// On a choice type you send the OPTION'S ID; sending its text records the wrong thing.
$definition = Api::Products()->GetRequirement(['id' => 22])['data'];
$option     = $definition['langs']['en']['options'][0];

Api::Services()->CreateServiceRequirement([
    'id'             => 506,
    'source'         => 'defined',
    'requirement_id' => 22,
    'response'       => $option['id'],
]);
```

### Updating an Answer

patch/api/v1/admin/services/{id}/requirements/{req_id}

`Services/UpdateServiceRequirement` admin files cannot be edited

Changes a text-based answer. File answers cannot be edited.

Body 1

responsestringThe new answer. Comma-separated option ids on multiple choice.

Response fields data

dataobjectThe answer in its updated state. Same shape as one row of the list schema; on the choice types `response_mkey` is resolved again.

Errors 3

not_found404No such service or requirement.

file_not_editable422A file requirement cannot be edited. Delete it and add it again.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PATCH 'https://panel.example.com/api/v1/admin/services/506/requirements/12' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"response":"Valheim"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/requirements/12', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ response: 'Valheim' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/requirements/12');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['response' => 'Valheim']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The way to change a file answer is delete-then-add.
Api::Services()->DeleteServiceRequirement(['id' => 506, 'req_id' => 12]);

Api::Services()->CreateServiceRequirement([
    'id'     => 506,
    'source' => 'custom',
    'label'  => 'Contract',
    'type'   => 'file',
    'file'   => 'data:application/pdf;base64,' . base64_encode($pdf),
]);
```

### Deleting an Answer

delete/api/v1/admin/services/{id}/requirements/{req_id}

`Services/DeleteServiceRequirement` admin the file goes too

Deletes the answer. On a file type the uploaded file is removed from disk as well.

Response fields data — 2

deletedboolWhether the delete succeeded.

idintId of the deleted record.

Errors 2

not_found404No such service or requirement.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/506/requirements/12' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/requirements/12', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/requirements/12');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Services()->DeleteServiceRequirement([
    'id'     => 506,
    'req_id' => 12,
]);
```

## Pitfalls

> **Choice types take the id, not the text**
> 
> On the dropdown, single-choice and multiple-choice types the answer is the option's **id** from the definition. Sending the option's visible text raises no error but records the wrong value and leaves the module mapping unresolved. Read the ids from the product requirement definition.

> **A file answer cannot be edited**
> 
> The update endpoint answers `file_not_editable` on a file type. The only way to change one is to delete the record and add a new one; the delete also removes the uploaded file from disk, so nothing stale is left behind.

> **The answer changes shape with the type**
> 
> In the list the `response` field is an **array** on the file type and **plain text** on the rest. Code expecting one shape breaks on the first service with a file requirement, so check `type` before reading it.

> **A free-form requirement never reaches the module**
> 
> A free-form requirement only sits on the record: with no definition behind it there is no module mapping either. If the answer has to do something on the server, define the requirement on the product side and add it here from that definition.

## Related Articles

- [Product Requirements](https://dev.wisecp.com/en/product-requirements)
- [Service Endpoints](https://dev.wisecp.com/en/service-endpoints)
