{{ vendor?.name || 'Vendor setup' }}

{{ vendor?.work }}

@if (vendor) { {{ vendor.active ? 'Active' : 'Switched off' }} {{ vendor.environment }} } ← All vendors
@if (error && !editing && !importOpen) {
{{ error }}
} @if (info && !editing) {
{{ info }}
} @if (loading && !vendor) {
Loading…
} @if (vendor) { @if (vendor.configNote) {
{{ vendor.configNote }}
} @if (vendor.links.length) {
{{ vendor.code }} also has its own screens: @for (l of vendor.links; track l.route) { {{ l.label }} }
}
@if (tab === 'connection') {

Vendor and connection

Every OUT / pull API path is added to this. PRODUCTION needs https://.
@if (form.authType === 'BASIC') {
} @if (form.authType === 'API_KEY') {
} @if (needsSecret()) {
@if (vendor.hasSecret) { }
}
The bank's id at this vendor (SMS sender id, WhatsApp number id, CIC member code …).

Default headers — sent on every API of this vendor (an API can override one)

} @if (tab === 'apis') {

API set

@if (!vendor.apis.length) {
No API yet. Add one, then fill it in by hand or read it from a JSON / cURL / Postman file.
} @else {
@for (a of vendor.apis; track a.id) { }
API Direction Call Used for Headers / query Mapping Active
{{ a.name }} {{ a.direction }} @if (a.mode) { {{ a.mode === 'PULL' ? 'pull' : 'push' }} } {{ a.method }} {{ a.path }} {{ a.usedFor }} {{ a.headers.length }} / {{ a.queryParams.length }} {{ a.requestRows.length }} / {{ a.responseRows.length }} {{ a.active ? 'Yes' : 'Off' }}
}
} @if (tab === 'test') {

Test an API simulated — nothing is sent to the vendor; the result is added to the logs

@if (!vendor.apis.length) {
Add an API first.
} @else {
@if (testPreview; as p) {

The request

{{ p.method }} {{ p.url }}
@for (h of p.headers; track h.key) {
{{ h.key }}: {{ h.value }}
}
}
}
@if (testResult) {
{{ testResult.reference }} — HTTP {{ testResult.httpStatus }} in {{ testResult.durationMs }} ms

Response headers

{{ testResult.responseHeaders }}

Response body

{{ testResult.response || '(empty)' }}
} } @if (tab === 'calls') {

Recent calls All logs

@if (!calls.length) {
No call yet.
} @else {
@for (l of calls; track l.id) { }
Time API Direction HTTP ms Result Reference
{{ l.time | slice: 0 : 16 }} {{ l.apiName }} {{ l.direction }} {{ l.httpStatus }} {{ l.durationMs }} {{ l.result }} {{ l.reference }}
}
} }
@if (editing) {

{{ isNewApi ? 'New' : 'Edit' }} API {{ editing.direction }} @if (editing.mode) { {{ editing.mode === 'PULL' ? 'pull' : 'push' }} }

@if (editing.direction === 'OUT') { OUT — the CBS calls the vendor: fill the request it sends and the response it expects. } @else if (editing.mode === 'PULL') { IN (pull) — the CBS asks the vendor for data on a schedule: fill the request it sends and the response it reads. } @else { IN (push) — the vendor calls a CBS path: fill what the vendor sends us and what we answer. } Type everything in, or read it from a file with the import button — then check each tab.

@if (info) {
{{ info }}
} @if (error) {
{{ error }}
}
@if (editorTab === 'basics') {
@if (editing.direction === 'IN') {
} @else {
}
Use {{ '{' }}name{{ '}' }} for a value that changes, e.g. /v21.0/{{ '{' }}senderId{{ '}' }}/messages.
@if (preview(editing); as p) {

{{ outbound ? 'The call as it will go out' : 'The call the vendor will make to us' }} (credentials masked)

{{ p.method }} {{ p.url }}
@for (h of p.headers; track h.key) {
{{ h.key }}: {{ h.value }}
}
{{ p.body }}
} } @if (editorTab === 'request') {

Path parameters

Query parameters

Headers — this API's own; the vendor's default headers and its authentication are added automatically

{{ outbound ? 'The constant parts of the payload; the mapping below puts CBS values into it.' : 'A sample of what arrives; the mapping reads values out of it.' }}

{{ mappingTitle('request') }} · {{ matchedCount('request') }} of {{ editing.requestRows.length }} rows found in the sample {{ 'request' === 'request' ? 'payload' : 'body' }}

@let requestMatch = sampleMatches('request'); @for (r of editing.requestRows; track $index; let i = $index) { }
{{ fromLabel('request') }} {{ toLabel('request') }} Transform Fixed / default value In the sample payload Required
@if (fromIsCbs('request')) { } @else { } @if (requestMatch[i].found) { ✓ {{ requestMatch[i].value }} } @else if (r.defaultValue) { fixed: {{ r.defaultValue }} } @else { ✗ {{ requestMatch[i].value || 'no path' }} }
} @if (editorTab === 'response') {
{{ outbound ? 'Codes the vendor answers with when it worked.' : 'Codes the CBS answers with.' }}

{{ outbound ? 'Response headers' : 'Headers of our answer' }}

What comes back when it fails (wrong key, rate limit …) — shown in the logs for a failed call.

{{ mappingTitle('response') }} · {{ matchedCount('response') }} of {{ editing.responseRows.length }} rows found in the sample {{ 'response' === 'request' ? 'payload' : 'body' }}

@let responseMatch = sampleMatches('response'); @for (r of editing.responseRows; track $index; let i = $index) { }
{{ fromLabel('response') }} {{ toLabel('response') }} Transform Fixed / default value In the sample payload Required
@if (fromIsCbs('response')) { } @else { } @if (responseMatch[i].found) { ✓ {{ responseMatch[i].value }} } @else if (r.defaultValue) { fixed: {{ r.defaultValue }} } @else { ✗ {{ responseMatch[i].value || 'no path' }} }
}
} @if (importOpen && editing) {

Import from JSON / cURL / Postman

Paste it or choose a file — {{ outbound ? 'the request and the response' : 'what the vendor sends us and what we answer' }}. Any of these works: a cURL command, a Postman collection or request, a HAR capture, an API definition ({{ '{' }} method, url, headers, query, body, status … {{ '}' }}), or just the JSON payload. The method, URL / path, query parameters, headers, content type, payload, status code, response headers, bodies and a first CBS mapping are filled in for you. Passwords, keys and tokens are never kept.

@if (importError) {
{{ importError }}
}
@if (importRequestFile) { {{ importRequestFile }} }
@if (importResponseFile) { {{ importResponseFile }} }
}