Document Scheme

281 visitas Markdown

The ten endpoints that define which document is asked of whom: the field pool and the filters that use it.

Overview

The document scheme has two layers. Fields are a shared pool — single inputs such as "passport copy" or "tax certificate". Filters pick a set out of that pool and carry the rules that decide who is asked for it.

One field can sit in several filters; that is what the pool is for. Updating a field reaches every filter using it at once.

Reference

Listing Filters

get/api/v1/admin/clients/document-filters
Clients/GetDocumentFilters admin

Returns the document filters. Each one carries a set of fields and the rules that decide who is asked for them.

Query parameters 3
statusstringactive or inactive.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
Response fields data[] — 5
idintFilter id.
namestringFilter name.
statusstringactive or inactive.
fieldsint[]An ordered list of ids from the field pool. The order is what the client sees.
rulesobject[]The rules that decide who the filter applies to.
typestringWhat the rule looks at: email_provider, vpn_proxy, account_age, service_count, total_spending, country_mismatch, country.
valuestringDepends on the type: a list of domains, yes, a numeric threshold or a country id.
extrastringAn extra value for some types. Empty on most rules.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/clients/document-filters' \
  -H "Authorization: Bearer $API_KEY" \
  -d status=active
const url = new URL('https://panel.example.com/api/v1/admin/clients/document-filters');
url.searchParams.set('status', 'active');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/clients/document-filters?' . http_build_query(['status' => 'active']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetDocumentFilters([], ['status' => 'active']);

Adding a Filter

post/api/v1/admin/clients/document-filters
Clients/CreateDocumentFilter admin

Defines a new filter. The field ids have to exist in the pool.

Body 4
namestringrequiredFilter name.
fieldsint[]requiredOrdered field ids, for example [3, 1].
activeboolDefaults to false; the filter is born inactive.
rulesobject[]The rules that apply it.
typestringWhat the rule looks at: email_provider, vpn_proxy, account_age, service_count, total_spending, country_mismatch, country.
valuestringDepends on the type: a list of domains, yes, a numeric threshold or a country id.
extrastringAn extra value for some types. Empty on most rules.
Response fields data — 5
idintId of the new filter.
namestringFilter name.
statusstringactive or inactive. A new filter is born inactive unless you sent active.
fieldsint[]The ordered field ids, as stored.
rulesobject[]The stored rules — same type / value / extra shape as the listing.
Errors 5
name_required422name was empty.
fields_required422fields was empty or malformed.
fields_invalid422None of the ids exist in the field pool.
filter_add_failed500The record could not be created.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/clients/document-filters' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"High spend","fields":[3,1],"active":true,"rules":[{"type":"total_spending","value":"5000","extra":""}]}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-filters', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"name":"High spend","fields":[3,1],"active":true,"rules":[{"type":"total_spending","value":"5000","extra":""}]}),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-filters');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name'   => 'High spend',
        'fields' => [3, 1],
        'active' => true,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->CreateDocumentFilter([
    'name'   => 'High spend',
    'fields' => [3, 1],
    'active' => true,
    'rules'  => [
        ['type' => 'total_spending', 'value' => '5000', 'extra' => ''],
    ],
]);

Filter Detail

get/api/v1/admin/clients/document-filters/{fid}
Clients/GetDocumentFilter admin

Returns one filter; the schema is the same as in the list.

Response fields data — 5
idintFilter id.
namestringFilter name.
statusstringactive or inactive.
fieldsint[]The ordered field ids, exactly as the listing returns them.
rulesobject[]The rules, same type / value / extra shape as the listing.
Errors 2
not_found404No such record.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/document-filters/7' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/document-filters/7', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-filters/7');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetDocumentFilter(['fid' => 7]);

Updating a Filter

patch/api/v1/admin/clients/document-filters/{fid}
Clients/UpdateDocumentFilter admin

Changes the filter name, the field order, the status or the rules.

Body at least one
namestringFilter name.
fieldsint[]The new ordered field list. What you send replaces the old list.
activeboolTurns the filter on or off.
rulesobject[]The new rule list. This replaces as well, it does not append.
Response fields data — 5
idintFilter id.
namestringFilter name after the update.
statusstringactive or inactive.
fieldsint[]The stored field order — read it back to see what the replace actually left.
rulesobject[]The stored rules; an empty array means the filter now applies to everyone.
Errors 5
not_found404No such filter.
name_required422name was sent empty.
fields_required422fields was sent empty or malformed.
fields_invalid422An id does not exist in the field pool.
insufficient_scope403The key lacks the required scope.
Request
curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/document-filters/7' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"active":false}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-filters/7', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ active: false }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-filters/7');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['active' => false]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->UpdateDocumentFilter([
    'fid'    => 7,
    'active' => false,
]);

Deleting a Filter

delete/api/v1/admin/clients/document-filters/{fid}
Clients/DeleteDocumentFilter admin

Deletes the filter. The field pool is untouched; the fields stay in whatever other filters use them.

Response fields data — 2
deletedboolWhether the delete succeeded.
idintId of the deleted filter.
Errors 1
not_found404No such filter.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/clients/document-filters/7' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-filters/7', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-filters/7');
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);
$response = Api::Clients()->DeleteDocumentFilter(['fid' => 7]);

Listing Fields

get/api/v1/admin/clients/document-fields
Clients/GetDocumentFields admin

Returns the shared field pool. Filters pick their fields from here.

Query parameters 4
statusstringactive or inactive.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
typestringFilters by input type.
Response fields data[] — 8
idintField id. A filter's fields list points here.
statusstringactive or inactive. An inactive field is not shown to the client.
typestringinput, textarea, selectbox, radio, checkbox, file.
labelsobjectLabel per language, for example {"en": "Passport copy"}.
optionsobjectOptions per language. Only meaningful on the choice types.
allowed_extstringAllowed file extensions. Only on the file type.
max_sizeintMaximum file size in MB. Only on the file type.
used_inobject[]The filters using this field: [{ id, name }].
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/clients/document-fields' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=file
const url = new URL('https://panel.example.com/api/v1/admin/clients/document-fields');
url.searchParams.set('type', 'file');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/clients/document-fields?' . http_build_query(['type' => 'file']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetDocumentFields([], ['type' => 'file']);

Adding a Field

post/api/v1/admin/clients/document-fields
Clients/CreateDocumentField admin

Adds a field to the pool. The label has to be given in at least one language.

Body 6
typestringrequiredInput type.
labelsobjectrequiredLabel per language; at least one.
activeboolDefaults to true.
optionsobjectOptions per language. In practice required on the choice types.
allowed_extstringAllowed extensions. Only on the file type.
max_sizeintLimit in MB. Only on the file type.
Response fields data — 7
idintId of the new field.
statusstringactive or inactive.
typestringThe stored input type.
labelsobjectThe stored labels, per language.
optionsobjectThe stored choices, per language.
allowed_extstringAllowed file extensions.
max_sizeintMaximum file size in MB.
used_inNot part of this answer: a newly created field belongs to no filter yet.
Errors 4
type_invalid422type is not one of the allowed input types.
labels_required422No language carried a non-empty label.
field_add_failed500The record could not be created.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/clients/document-fields' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"file","labels":{"en":"Passport copy"},"allowed_ext":"jpg,png,pdf","max_size":5}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-fields', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'file',
    labels: {"en":"Passport copy"},
    allowed_ext: 'jpg,png,pdf',
    max_size: 5,
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-fields');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'type'        => 'file',
        'labels'      => ['en' => 'Passport copy'],
        'allowed_ext' => 'jpg,png,pdf',
        'max_size'    => 5,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->CreateDocumentField([
    'type'        => 'file',
    'labels'      => ['en' => 'Passport copy'],
    'allowed_ext' => 'jpg,png,pdf',
    'max_size'    => 5,
]);

Field Detail

get/api/v1/admin/clients/document-fields/{fid}
Clients/GetDocumentField admin

Returns one field. used_in comes with it, showing which filters use it.

Response fields data — 8
idintField id — this is what a filter's fields list refers to.
statusstringactive or inactive. An inactive field is not shown to clients even where a filter still lists it.
typestringInput type: input, textarea, selectbox, radio, checkbox, file.
labelsobjectThe label per language, for example { "en": "Passport copy" }.
optionsobjectPer-language choices for the list types. Empty on the other types.
allowed_extstringAllowed file extensions — file type only.
max_sizeintMaximum file size in MB — file type only.
used_inobject[]The filters referencing this field, as { id, name }. Read it before deleting — every one of them loses the field.
Errors 2
not_found404No such field.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/document-fields/3' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/document-fields/3', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-fields/3');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetDocumentField(['fid' => 3]);

// Before deleting: which filters hold this field?
$usedIn = $response['data']['used_in'] ?? [];

Updating a Field

patch/api/v1/admin/clients/document-fields/{fid}
Clients/UpdateDocumentField admin

Updates the field. The change reaches every filter using it at once.

Body 6
typestringrequiredInput type. Required even on an update — this endpoint rewrites the field rather than patching single keys.
labelsobjectrequiredLabel per language; at least one must be non-empty.
activeboolTurns the field on or off. Defaults to true.
optionsobjectChoices per language. In practice required on the choice types.
allowed_extstringAllowed extensions. Only on the file type.
max_sizeintLimit in MB. Only on the file type.
Response fields data — 7
idintField id.
statusstringactive or inactive.
typestringThe stored input type.
labelsobjectThe stored labels, per language.
optionsobjectThe stored choices, per language.
allowed_extstringAllowed file extensions.
max_sizeintMaximum file size in MB.
Errors 4
not_found404No such field.
type_invalid422type is not one of the allowed input types.
labels_required422No language carried a non-empty label.
insufficient_scope403The key lacks the required scope.
Request
curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/document-fields/3' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"max_size":10}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-fields/3', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ max_size: 10 }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-fields/3');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['max_size' => 10]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->UpdateDocumentField([
    'fid'      => 3,
    'max_size' => 10,
]);

Deleting a Field

delete/api/v1/admin/clients/document-fields/{fid}
Clients/DeleteDocumentField admin affects filters

Removes the field from the pool.

Response fields data — 2
deletedboolWhether the delete succeeded.
idintId of the deleted field.
Errors 1
not_found404No such field.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/clients/document-fields/3' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/clients/document-fields/3', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/document-fields/3');
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);
$response = Api::Clients()->DeleteDocumentField(['fid' => 3]);

Pitfalls

The field list is ordered

fields is not a set but an ordered list, and the client sees the fields in that order. On update the list you send replaces the old one; it does not append to it.

A field is shared, not copied

Updating or deleting a field affects every filter that uses it. Look at used_in on the field detail before you delete.

A new filter is born switched off

Leave active out and the filter is created as inactive, asking nobody for anything. Creating one and walking away leaves a verification that never runs.

¿Le ha resultado útil?

¡Gracias por sus comentarios!

¿Todavía necesita ayuda?

Nuestro equipo de soporte está disponible las 24 horas para ayudarle con lo que no encuentre aquí.