connectors

object

%Connector

/phlo/resources/connectors/Connector.phlo
version 1.0
creator q-ai.nl
summary Base class for API connectors: credentials, JSON requests, retries, pagination and a normalized result contract
package connectors
frontend false
backend true
requires creds HTTP
tags api connector http rest base
const

Connector :: section

line 10
Defines a section within a Connector, allowing for the organization of related components and functionalities.
void
const

Connector :: api

line 11
Defines a connector for API interactions, allowing seamless communication between different services.
void
method

%Connector -> __construct (?array $config = null)

line 13
Initializes a Connector instance with optional configuration settings. If no configuration is provided, it attempts to load credentials from a predefined section.
if ($config === null){
	$section = static::section
	$creds = $section ? %creds->{$section} : null
	$config = $creds ? (array)$creds->toArray : []
}
$this->config = $config
$this->timeout = 15
$this->retries = 0
static

Connector :: make (?array $config = null):static

line 24
Creates a new instance of the Connector class using the provided configuration.
new static($config)
method

%Connector -> base

line 26
Accesses the base API for the Connector, allowing interaction with its core functionalities.
static::api
method

%Connector -> headers

line 27
This property retrieves the headers associated with the Connector.
[]
static

Connector :: fields

line 29
Connector::$fields is a static property that holds an array of field definitions for the Connector class.
[]
method

%Connector -> configured (...$keys):bool

line 31
Checks if all specified keys are configured in the Connector's configuration. Returns true if all keys are present, otherwise returns false.
foreach ($keys AS $key){
	if (($this->config[$key] ?? void) === void) return false
}
return true
method

%Connector -> missing (...$keys):?obj

line 38
Checks if the specified credentials are configured and returns null if they are; otherwise, it triggers a failure indicating which credentials are missing.
return $this->configured(...$keys) ? null : static::fail(static::section.' credentials not configured ('.implode(', ', $keys).')')
static

Connector :: bearer ($token):string

line 42
The Connector::$bearer property holds the authorization header value formatted with a Bearer token for API requests.
'Authorization: Bearer '.$token
static

Connector :: basic ($user, $pass):string

line 43
Generates a Basic Authorization header by encoding the provided username and password in base64 format.
'Authorization: Basic '.base64_encode($user.colon.$pass)
static

Connector :: build (string $method, string $url, ?array $query = null, array $headers = [], mixed $json = null, mixed $form = null):array

line 45
Constructs an HTTP request configuration including method, URL, headers, and body based on provided parameters.
if ($query) $url .= (str_contains($url, qm) ? '&' : qm).http_build_query($query)
$body = null
if ($json !== null){
	$body = is_string($json) ? $json : json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
	$headers[] = 'Content-Type: application/json'
}
elseif ($form !== null){
	$body = is_string($form) ? $form : http_build_query($form)
	$headers[] = 'Content-Type: application/x-www-form-urlencoded'
}
$headers[] = 'Accept: application/json'
return ['method' => strtoupper($method), 'url' => $url, 'headers' => $headers, 'body' => $body]
static

Connector :: ok ($data, int $status = 200):obj

line 60
The Connector::$ok property holds an object with a boolean 'ok' value, a 'status', and 'data' attributes.
obj(ok: true, status: $status, data: $data)
static

Connector :: fail ($error, int $status = 0):obj

line 61
The Connector::$fail property represents a failure state, containing an object with 'ok' set to false, along with the 'status' and 'error' details.
obj(ok: false, status: $status, error: $error)
static

Connector :: errorMessage ($data, string $raw, int $status):string

line 63
Connector::$errorMessage retrieves the error message from a given data object, checking various properties for a string representation of the error, and defaults to a formatted HTTP status message if no error is found.
if (is_object($data)){
	if (isset($data->error->message)) return (string)$data->error->message
	if (isset($data->error) && is_string($data->error)) return $data->error
	if (isset($data->message)) return (string)$data->message
	if (isset($data->errors)){
		$errors = $data->errors
		if (is_string($errors)) return $errors
		if (is_array($errors)) return is_string($errors[0] ?? null) ? $errors[0] : json_encode($errors)
		if (is_object($errors)) return json_encode($errors)
	}
}
return $raw !== void ? $raw : 'HTTP '.$status
static

Connector :: parse ($raw, int $status = 200):obj

line 78
Parses a raw input string into a JSON object, returning a success response or an error message based on the HTTP status code.
$raw = (string)$raw
$data = $raw === void ? null : json_decode($raw)
if ($status < 200 || $status >= 300) return static::fail(static::errorMessage($data, $raw, $status), $status)
return obj(ok: true, status: $status, data: $data ?? $raw)
static

Connector :: retryable ($method, int $status):bool

line 85
in_array($method, ['GET', 'HEAD', 'QUERY']) && ($status === 429 || $status >= 500)
static

Connector :: backoff (int $attempt, $response):int

line 87
The Connector::$backoff property calculates the backoff time in microseconds based on the 'retry-after' header from the response, with a maximum limit of 30 seconds or a default value multiplied by the attempt count.
$after = (int)($response->headers['retry-after'] ?? 0)
return $after > 0 ? min($after, 30) * 1000000 : 200000 * $attempt
method

%Connector -> dispatch (array $req):obj

line 92
$method = $req['method']
$body = $req['body']
$attempt = 0
$response = null
while (true){
	try {
		if ($method === 'GET') $raw = HTTP($req['url'], $req['headers'], cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'DELETE') $raw = HTTP($req['url'], $req['headers'], DELETE: true, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'PUT') $raw = HTTP($req['url'], $req['headers'], PUT: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'PATCH') $raw = HTTP($req['url'], $req['headers'], PATCH: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'QUERY') $raw = HTTP($req['url'], $req['headers'], QUERY: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		else $raw = HTTP($req['url'], $req['headers'], POST: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
	}
	catch (\Throwable $e){
		return static::fail($e->getMessage(), 0)
	}
	$status = $response->status ?? 0
	if (($status >= 200 && $status < 300) || !static::retryable($method, $status) || $attempt >= $this->retries) break
	usleep(static::backoff(++$attempt, $response))
}
$result = static::parse($raw, $status)
$result->headers = $response->headers ?? []
return $result
method

%Connector -> request (string $method, string $url, ?array $query = null, array $headers = [], mixed $json = null, mixed $form = null):obj

line 118
Sends an HTTP request using the specified method, URL, query parameters, headers, and optional JSON or form data.
if (!str_starts_with($url, 'http')) $url = rtrim((string)$this->base, slash).slash.ltrim($url, slash)
$headers = array_merge((array)$this->headers, $headers)
return $this->dispatch(static::build($method, $url, $query, $headers, $json, $form))
method

%Connector -> get (string $url, ?array $query = null, array $headers = []):obj

line 124
Sends a GET request to the specified URL with optional query parameters and headers.
$this->request('GET', $url, query: $query, headers: $headers)
method

%Connector -> post (string $url, mixed $json = null, array $headers = []):obj

line 125
Sends a POST request to the specified URL with optional JSON data and headers.
$this->request('POST', $url, headers: $headers, json: $json)
method

%Connector -> put (string $url, mixed $json = null, array $headers = []):obj

line 126
Sends a PUT request to the specified URL with optional JSON data and headers.
$this->request('PUT', $url, headers: $headers, json: $json)
method

%Connector -> patch (string $url, mixed $json = null, array $headers = []):obj

line 127
Sends a PATCH request to the specified URL with optional JSON data and headers.
$this->request('PATCH', $url, headers: $headers, json: $json)
method

%Connector -> query (string $url, mixed $json = null, array $headers = []):obj

line 128
$this->request('QUERY', $url, headers: $headers, json: $json)
method

%Connector -> del (string $url, array $headers = []):obj

line 129
Sends a DELETE request to the specified URL with optional headers.
$this->request('DELETE', $url, headers: $headers)
method

%Connector -> form (string $url, array $fields, array $headers = []):obj

line 130
Sends a POST request to the specified URL with the given form fields and headers.
$this->request('POST', $url, headers: $headers, form: $fields)
method

%Connector -> paginate (string $url, callable $extract, ?array $query = null, string $param = 'page', int $start = 1, int $max = 0):array

line 132
Fetches paginated data from a specified URL, extracting items using a provided callable and accumulating them until a maximum count is reached or no more data is available.
$items = []
$page = $start
while (true){
	$res = $this->get($url, ($query ?? []) + [$param => $page])
	if (!$res->ok) break
	$batch = $extract($res->data)
	if (!$batch) break
	foreach ($batch AS $item) $items[] = $item
	if ($max && count($items) >= $max) break
	$page++
}
return $items
object

%EBoekhouden

/phlo/resources/connectors/finance/EBoekhouden.phlo
version 1.0
creator q-ai.nl
summary e-Boekhouden.nl connector: session auth from an API token, relations and sales invoices
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:EBoekhouden
tags eboekhouden accounting invoices relations connector
const

EBoekhouden :: section

line 11
'EBoekhouden'
const

EBoekhouden :: api

line 12
'https://api.e-boekhouden.nl/v1'
prop

%EBoekhouden -> sessionToken

line 14
void
method

%EBoekhouden -> headers

line 16
$this->sessionToken !== void ? ['Authorization: '.$this->sessionToken] : []
static

EBoekhouden :: fields

line 18
arr(
	section: 'EBoekhouden',
	config: arr(source: 'Source label shown in the e-Boekhouden audit trail (optional)'),
	secret: arr(api_token: 'API token (Beheer > Instellingen > API)'),
)
method

%EBoekhouden -> session:obj

line 25
if ($m = $this->missing('api_token')) return $m
if ($this->sessionToken !== void) return static::ok($this->sessionToken)
$res = $this->post('session', ['accessToken' => trim((string)$this->config['api_token']), 'source' => (string)($this->config['source'] ?? 'Phlo')])
if (!$res->ok) return $res
$token = (string)($res->data->token ?? void)
if ($token === void) return static::fail('e-Boekhouden session token missing in response', $res->status)
$this->sessionToken = $token
return static::ok($token)
method

%EBoekhouden -> guard:?obj

line 36
$res = $this->session
return $res->ok ? null : $res
method

%EBoekhouden -> relations (array $query = []):obj

line 41
if ($m = $this->guard) return $m
return $this->get('relation', $query)
method

%EBoekhouden -> createRelation (array $relation):obj

line 46
if ($m = $this->guard) return $m
return $this->post('relation', $relation)
method

%EBoekhouden -> invoices (array $query = []):obj

line 51
if ($m = $this->guard) return $m
return $this->get('invoice', $query)
method

%EBoekhouden -> createInvoice (array $invoice):obj

line 56
if ($m = $this->guard) return $m
return $this->post('invoice', $invoice)
object

%ExactOnline

/phlo/resources/connectors/finance/ExactOnline.phlo
version 1.0
creator q-ai.nl
summary Exact Online connector (OAuth2): read sales invoices and accounts, create sales invoices
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:ExactOnline
tags exact exactonline accounting invoices oauth connector
const

ExactOnline :: section

line 11
Defines a section within the ExactOnline resource, allowing for structured data management.
'ExactOnline'
const

ExactOnline :: tokenUrl

line 12
Returns the URL for obtaining an OAuth2 token from ExactOnline.
'https://start.exactonline.nl/api/oauth2/token'
method

%ExactOnline -> base

line 14
Constructs the base URL for the ExactOnline API using the specified division from the configuration.
'https://start.exactonline.nl/api/v1/'.($this->config['division'] ?? void)
static

ExactOnline :: fields

line 16
Defines the fields required for integrating with ExactOnline, including configuration for OAuth credentials and scopes.
arr(
	section: 'ExactOnline',
	config: arr(division: 'Division (administration) number'),
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (managed and rotated after first authorization)',
	),
	scopes: 'OAuth2 authorization code flow; token endpoint refreshes automatically',
)
method

%ExactOnline -> guard

line 27
Checks for the presence of required parameters 'division', 'client_id', 'client_secret', and 'refresh_token'.
$this->missing('division', 'client_id', 'client_secret', 'refresh_token')
method

%ExactOnline -> invoices (array $query = []):obj

line 29
Retrieves a list of sales invoices from ExactOnline based on the provided query parameters.
if ($m = $this->guard) return $m
return $this->get('salesinvoice/SalesInvoices', $query)
method

%ExactOnline -> accounts (array $query = []):obj

line 34
Retrieves account information from ExactOnline using the specified query parameters.
if ($m = $this->guard) return $m
return $this->get('crm/Accounts', $query)
method

%ExactOnline -> createInvoice (array $invoice):obj

line 39
Creates a new invoice in ExactOnline using the provided invoice data.
if ($m = $this->guard) return $m
return $this->post('salesinvoice/SalesInvoices', $invoice)
object

%GoogleCalendar

/phlo/resources/connectors/cloud/GoogleCalendar.phlo
version 1.0
creator q-ai.nl
summary Google Calendar connector (OAuth2): read events and create events
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:Google
tags google calendar events oauth connector
const

GoogleCalendar :: section

line 11
Defines a section within a Google Calendar resource, allowing for the organization of events and details.
'Google'
const

GoogleCalendar :: tokenUrl

line 12
This is the URL endpoint used to obtain an access token from Google Calendar's OAuth 2.0 authorization server.
'https://oauth2.googleapis.com/token'
method

%GoogleCalendar -> base

line 14
This defines the base URL for accessing the Google Calendar API version 3.
'https://www.googleapis.com/calendar/v3'
static

GoogleCalendar :: fields

line 16
GoogleCalendar::$fields provides configuration details for accessing Google Calendar, including OAuth credentials and required scopes.
arr(
	section: 'Google',
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (scopes: calendar, spreadsheets)',
	),
	scopes: 'https://www.googleapis.com/auth/calendar, https://www.googleapis.com/auth/spreadsheets',
)
method

%GoogleCalendar -> guard

line 26
Checks for the presence of required credentials: client_id, client_secret, and refresh_token.
$this->missing('client_id', 'client_secret', 'refresh_token')
method

%GoogleCalendar -> events (string $calendarId = 'primary', array $query = []):obj

line 28
Retrieves events from a specified Google Calendar using the provided calendar ID and optional query parameters.
if ($m = $this->guard) return $m
return $this->get('calendars/'.rawurlencode($calendarId).'/events', $query)
method

%GoogleCalendar -> createEvent (array $event, string $calendarId = 'primary'):obj

line 33
Creates a new event in the specified Google Calendar using the provided event details.
if ($m = $this->guard) return $m
return $this->post('calendars/'.rawurlencode($calendarId).'/events', $event)
object

%GoogleSheets

/phlo/resources/connectors/cloud/GoogleSheets.phlo
version 1.0
creator q-ai.nl
summary Google Sheets connector (OAuth2): read ranges and append rows
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:Google
tags google sheets spreadsheet oauth connector
const

GoogleSheets :: section

line 11
Defines a section for organizing data within a Google Sheets resource.
'Google'
const

GoogleSheets :: tokenUrl

line 12
This is the URL endpoint for obtaining OAuth 2.0 tokens from Google Sheets.
'https://oauth2.googleapis.com/token'
method

%GoogleSheets -> base

line 14
This item represents a base URL for accessing the Google Sheets API, specifically the endpoint for interacting with spreadsheets.
'https://sheets.googleapis.com/v4/spreadsheets'
static

GoogleSheets :: fields

line 16
Defines the configuration fields for Google Sheets integration, including OAuth credentials and required scopes.
arr(
	section: 'Google',
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (scopes: calendar, spreadsheets)',
	),
	scopes: 'https://www.googleapis.com/auth/spreadsheets',
)
method

%GoogleSheets -> guard

line 26
Checks for the presence of required credentials: client_id, client_secret, and refresh_token.
$this->missing('client_id', 'client_secret', 'refresh_token')
method

%GoogleSheets -> values ($spreadsheetId, string $range):obj

line 28
Retrieves the values from a specified range in a Google Sheets spreadsheet identified by the given spreadsheet ID.
if ($m = $this->guard) return $m
return $this->get($spreadsheetId.'/values/'.rawurlencode($range))
method

%GoogleSheets -> append ($spreadsheetId, string $range, array $rows, string $valueInputOption = 'USER_ENTERED'):obj

line 33
Appends rows of data to a specified range in a Google Sheets spreadsheet, using the provided value input option.
if ($m = $this->guard) return $m
return $this->post($spreadsheetId.'/values/'.rawurlencode($range).':append?valueInputOption='.$valueInputOption, ['values' => $rows])
object

%Lightspeed

/phlo/resources/connectors/shops/Lightspeed.phlo
version 1.0
creator q-ai.nl
summary Lightspeed Retail (V3) connector: read customers and sales, create customers
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Lightspeed
tags lightspeed webshop retail pos customers connector
const

Lightspeed :: section

line 11
Defines a section in a Lightspeed application, allowing for the organization and management of content within that section.
'Lightspeed'
method

%Lightspeed -> base

line 13
Lightspeed->base constructs the base URL for accessing the Lightspeed API, incorporating the cluster ID from the configuration if available.
'https://api.lightspeedapp.com/API/V3/Account/'.($this->config['cluster_id'] ?? void)
method

%Lightspeed -> headers

line 15
This method retrieves the headers required for Lightspeed API authentication using the provided API key and secret from the configuration.
[static::basic($this->config['api_key'] ?? void, $this->config['api_secret'] ?? void)]
static

Lightspeed :: fields

line 17
Lightspeed::$fields defines the configuration fields required for connecting to the Lightspeed API, including cluster ID, language, API key, API secret, and access scopes.
arr(
	section: 'Lightspeed',
	config: arr(
		cluster_id: 'Account / cluster ID',
		language: 'Language (optional, default nl)',
	),
	secret: arr(
		api_key: 'API key',
		api_secret: 'API secret',
	),
	scopes: 'Customer read/write, Sale read',
)
method

%Lightspeed -> customers (array $query = []):obj

line 30
Retrieves customer data from the Lightspeed API using the provided query parameters.
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Customer.json', $query)
method

%Lightspeed -> findCustomer ($participant):obj

line 35
Finds a customer by their email or phone number, depending on the format of the provided participant identifier.
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
$field = str_contains((string)$participant, '@') ? 'Email' : 'Phone'
return $this->get('Customer.json', [$field => $participant, 'limit' => 1])
method

%Lightspeed -> customer ($id):obj

line 41
Retrieves customer information from the Lightspeed API using the specified customer ID.
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Customer/'.$id.'.json')
method

%Lightspeed -> sales (array $query = []):obj

line 46
Retrieves sales data from the API using the provided query parameters, ensuring that required credentials are present.
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Sale.json', $query)
method

%Lightspeed -> createCustomer (array $customer):obj

line 51
Creates a new customer by sending the provided customer data to the Lightspeed API, ensuring that required parameters are present.
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->post('Customer.json', $customer)
object

%MessageBird

/phlo/resources/connectors/chat/MessageBird.phlo
version 1.0
creator q-ai.nl
summary MessageBird connector: send SMS
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:MessageBird
tags messagebird sms messaging connector
const

MessageBird :: section

line 11
Defines a section for MessageBird within the Phlo application.
'MessageBird'
method

%MessageBird -> base

line 13
This defines the base URL for the MessageBird API, which is used for sending and receiving messages.
'https://rest.messagebird.com'
method

%MessageBird -> headers

line 15
This retrieves the headers required for authenticating requests to the MessageBird API using the provided access key.
['Authorization: AccessKey '.($this->config['access_key'] ?? void)]
static

MessageBird :: fields

line 17
Defines the fields for the MessageBird configuration, including the originator and access key.
arr(
	section: 'MessageBird',
	config: arr(originator: 'Originator (sender number or name)'),
	secret: arr(access_key: 'Access key'),
)
static

MessageBird :: errorMessage ($data, string $raw, int $status):string

line 23
Retrieves the error message from the MessageBird API response, if available; otherwise, it falls back to the parent class's error message method.
if (is_object($data) && isset($data->errors[0]->description)) return (string)$data->errors[0]->description
return parent::errorMessage($data, $raw, $status)
method

%MessageBird -> sms ($to, $body, array $extra = []):obj

line 28
Sends an SMS message to the specified recipient(s) using the MessageBird API, requiring an access key and originator configuration.
if ($m = $this->missing('access_key', 'originator')) return $m
$recipients = is_array($to) ? $to : [$to]
return $this->post('messages', ['originator' => $this->config['originator'], 'recipients' => $recipients, 'body' => $body] + $extra)
object

%MicrosoftGraph

/phlo/resources/connectors/cloud/MicrosoftGraph.phlo
version 1.0
creator q-ai.nl
summary Microsoft Graph connector (app-only client credentials): read users and calendars, send mail, create events
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Microsoft
tags microsoft graph office365 calendar mail connector
const

MicrosoftGraph :: section

line 11
This function interacts with the Microsoft Graph API to manage sections within a resource.
'Microsoft'
method

%MicrosoftGraph -> base

line 13
This defines the base URL for accessing the Microsoft Graph API, allowing interaction with Microsoft services and resources.
'https://graph.microsoft.com/v1.0'
method

%MicrosoftGraph -> headers

line 15
This item retrieves the headers required for authentication with Microsoft Graph using a bearer token.
[static::bearer((string)$this->token)]
static

MicrosoftGraph :: fields

line 17
Defines the configuration fields required to connect to Microsoft Graph, including tenant ID, client ID, mailbox, client secret, and application permissions.
arr(
	section: 'Microsoft',
	config: arr(
		tenant_id: 'Azure AD tenant ID',
		client_id: 'App registration client ID',
		mailbox: 'Default mailbox / user UPN for calendar and mail (optional)',
	),
	secret: arr(client_secret: 'App registration client secret'),
	scopes: 'Application permissions: User.Read.All, Calendars.ReadWrite, Mail.Send',
)
prop

%MicrosoftGraph -> token

line 28
Retrieves an access token from Microsoft Graph using the fetchToken method.
$this->fetchToken()
method

%MicrosoftGraph -> fetchToken

line 30
Fetches an OAuth2 token from Microsoft Graph using client credentials, caching the token for future use if APCu is available.
$tenant = $this->config['tenant_id'] ?? void
$id = $this->config['client_id'] ?? void
$secret = $this->config['client_secret'] ?? void
if ($tenant === void || $id === void || $secret === void) return void
$key = 'phlo:graph:'.$tenant.colon.$id
if (function_exists('apcu_fetch')){
	$cached = apcu_fetch($key)
	if ($cached) return $cached
}
$res = $this->dispatch(static::build('POST', 'https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/token', null, [], null, ['grant_type' => 'client_credentials', 'client_id' => $id, 'client_secret' => $secret, 'scope' => 'https://graph.microsoft.com/.default']))
if (!$res->ok) return void
$token = $res->data->access_token ?? void
$expires = (int)($res->data->expires_in ?? 3600)
if ($token !== void && function_exists('apcu_store')) apcu_store($key, $token, max(60, $expires - 60))
return $token
method

%MicrosoftGraph -> mailbox ($user = null)

line 48
Retrieves the mailbox associated with a specified user, or defaults to a configured mailbox if no user is provided.
$user ?? ($this->config['mailbox'] ?? void)
method

%MicrosoftGraph -> users (array $query = []):obj

line 50
Retrieves a list of users from Microsoft Graph based on the provided query parameters.
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
return $this->get('users', $query)
method

%MicrosoftGraph -> user ($id):obj

line 55
Fetches user information from Microsoft Graph using the specified user ID.
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
return $this->get('users/'.rawurlencode((string)$id))
method

%MicrosoftGraph -> events ($user = null, array $query = []):obj

line 60
Fetches events from a specified user's Microsoft mailbox using the Microsoft Graph API.
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->get('users/'.rawurlencode((string)$mailbox).'/events', $query)
method

%MicrosoftGraph -> sendMail ($message, $user = null, bool $save = true):obj

line 67
Sends an email message using the Microsoft Graph API, optionally specifying a user and whether to save the message to the Sent Items folder.
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->post('users/'.rawurlencode((string)$mailbox).'/sendMail', ['message' => $message, 'saveToSentItems' => $save])
method

%MicrosoftGraph -> createEvent (array $event, $user = null):obj

line 74
Creates a new event in the specified user's Microsoft calendar using the provided event details.
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->post('users/'.rawurlencode((string)$mailbox).'/events', $event)
object

%Moneybird

/phlo/resources/connectors/finance/Moneybird.phlo
version 1.0
creator q-ai.nl
summary Moneybird connector: read contacts and invoices, create sales invoices
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Moneybird
tags moneybird accounting invoices contacts connector
const

Moneybird :: section

line 11
Defines a section within the Moneybird integration for organizing related functionalities.
'Moneybird'
method

%Moneybird -> base

line 13
This retrieves the base URL for the Moneybird API, incorporating the administration ID from the configuration if available.
'https://moneybird.com/api/v2/'.($this->config['administration_id'] ?? void)
method

%Moneybird -> headers

line 15
Returns the headers required for authentication with the Moneybird API, using a bearer token derived from the access token in the configuration.
[static::bearer($this->config['access_token'] ?? void)]
static

Moneybird :: fields

line 17
Defines the fields for the Moneybird integration, including the administration ID and a personal access token for accessing contacts and invoices.
arr(
	section: 'Moneybird',
	config: arr(administration_id: 'Administration ID'),
	secret: arr(access_token: 'Personal access token with read/write for contacts and invoices'),
)
method

%Moneybird -> contacts (array $query = []):obj

line 23
Retrieves a list of contacts from Moneybird based on the provided query parameters.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts.json', $query)
method

%Moneybird -> findContact ($query):obj

line 28
Finds a contact in Moneybird based on the provided query, returning the first result found.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts.json', ['query' => $query, 'per_page' => 1])
method

%Moneybird -> contact ($id):obj

line 33
Retrieves the contact information associated with the specified ID from Moneybird, requiring an administration ID and access token.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts/'.$id.'.json')
method

%Moneybird -> invoices (array $query = []):obj

line 38
Fetches invoices from Moneybird based on the provided query parameters, requiring an 'administration_id' and 'access_token'.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('sales_invoices.json', $query)
method

%Moneybird -> createContact (array $contact):obj

line 43
Creates a new contact in Moneybird using the provided contact details. It requires an administration ID and access token to function properly.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->post('contacts.json', ['contact' => $contact])
method

%Moneybird -> createInvoice (array $invoice):obj

line 48
Creates a new invoice in Moneybird using the provided invoice data.
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->post('sales_invoices.json', ['sales_invoice' => $invoice])
object

%OAuthConnector

/phlo/resources/connectors/OAuthConnector.phlo
version 1.0
creator q-ai.nl
summary Base class for OAuth2 connectors: stored, auto-refreshed bearer access tokens via TokenStore, on the OAuth2 primitive
extends Connector
package connectors
frontend false
backend true
requires @Connector TokenStore
tags oauth oauth2 connector base token refresh
const

OAuthConnector :: tokenUrl

line 11
Specifies the URL for obtaining an OAuth token.
void
method

%OAuthConnector -> oauthKey

line 13
Retrieves the OAuth key for the current section in the OAuthConnector.
static::section
prop

%OAuthConnector -> token

line 15
Retrieves the OAuth token using the provided credentials and refresh token from the TokenStore.
TokenStore::access($this->oauthKey, static::tokenUrl, $this->config['client_id'] ?? void, $this->config['client_secret'] ?? void, ['refresh_token' => $this->config['refresh_token'] ?? null])
method

%OAuthConnector -> headers

line 17
Returns the headers required for OAuth authentication, including a bearer token derived from the instance's token.
[static::bearer((string)$this->token)]
method

%OAuthConnector -> authed

line 19
Checks if the OAuth token is authenticated by verifying that it is not void.
(string)$this->token !== void
object

%Resend

/phlo/resources/connectors/chat/Resend.phlo
version 1.0
creator q-ai.nl
summary Resend connector: send transactional email via the HTTP API
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Resend
tags resend email transactional messaging connector
const

Resend :: section

line 11
Resend::section allows you to define a section in a Resend resource for organizing related content.
'Resend'
method

%Resend -> base

line 13
Sets the base URL for the Resend API.
'https://api.resend.com'
method

%Resend -> headers

line 15
Sets the headers for the Resend request using the provided API key from the configuration.
[static::bearer($this->config['api_key'] ?? void)]
static

Resend :: fields

line 17
Defines the fields for the Resend configuration, including the default sender email and the API key.
arr(
	section: 'Resend',
	config: arr(from_email: 'Default sender, e.g. "App <noreply@yourdomain.com>"'),
	secret: arr(api_key: 'API key (re_...)'),
)
method

%Resend -> send ($to, $subject, $html = void, array $extra = []):obj

line 23
Sends an email to the specified recipient(s) with the given subject and optional HTML content, using the configured sender email address.
if ($m = $this->missing('api_key', 'from_email')) return $m
$email = ['from' => $this->config['from_email'], 'to' => is_array($to) ? $to : [$to], 'subject' => $subject]
if ($html !== void) $email['html'] = $html
return $this->post('emails', $email + $extra)
object

%Shopify

/phlo/resources/connectors/shops/Shopify.phlo
version 1.0
creator q-ai.nl
summary Shopify Admin API connector: read customers, orders and products; create draft orders and products; update inventory
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Shopify
tags shopify webshop ecommerce orders products connector
const

Shopify :: section

line 11
Defines a section in a Shopify theme, allowing for customizable content and layout within the store.
'Shopify'
method

%Shopify -> base

line 13
Constructs the base URL for the Shopify API using the shop domain and API version from the configuration.
'https://'.($this->config['shop_domain'] ?? void).'/admin/api/'.($this->config['api_version'] ?? '2024-01')
method

%Shopify -> headers

line 15
This retrieves the headers required for Shopify API authentication, including the access token from the configuration.
['X-Shopify-Access-Token: '.($this->config['access_token'] ?? void)]
static

Shopify :: fields

line 17
Defines the configuration fields for integrating with Shopify, including shop domain, API version, access token, and required scopes.
arr(
	section: 'Shopify',
	config: arr(
		shop_domain: 'Shop domain, e.g. your-store.myshopify.com',
		api_version: 'Admin API version (optional, default 2024-01)',
	),
	secret: arr(access_token: 'Admin API access token (shpat_...)'),
	scopes: 'read_customers, read_orders, read_products, write_draft_orders, write_inventory',
)
method

%Shopify -> customers (array $query = []):obj

line 27
Fetches a list of customers from Shopify using the provided query parameters.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers.json', $query)
method

%Shopify -> searchCustomers ($query, int $limit = 10):obj

line 32
Searches for customers in Shopify based on a query string and an optional limit on the number of results returned.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers/search.json', ['query' => $query, 'limit' => $limit])
method

%Shopify -> customer ($id):obj

line 37
Retrieves customer information from Shopify using the specified customer ID.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers/'.$id.'.json')
method

%Shopify -> orders (array $query = []):obj

line 42
Fetches a list of orders from Shopify based on the provided query parameters.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('orders.json', $query)
method

%Shopify -> products (array $query = []):obj

line 47
Fetches a list of products from Shopify using the provided query parameters.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('products.json', $query)
method

%Shopify -> createDraftOrder (array $order):obj

line 52
Creates a draft order in Shopify using the provided order details.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('draft_orders.json', ['draft_order' => $order])
method

%Shopify -> createProduct (array $product):obj

line 57
Creates a new product in Shopify using the provided product details.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('products.json', ['product' => $product])
method

%Shopify -> setInventory ($inventoryItemId, $locationId, int $available):obj

line 62
Sets the available inventory level for a specific inventory item at a given location in Shopify.
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('inventory_levels/set.json', ['inventory_item_id' => $inventoryItemId, 'location_id' => $locationId, 'available' => $available])
object

%Slack

/phlo/resources/connectors/chat/Slack.phlo
version 1.0
creator q-ai.nl
summary Slack connector: post messages, read channel history and list channels
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Slack
tags slack messaging chat connector
const

Slack :: section

line 11
Creates a section block in a Slack message, allowing for the inclusion of text and other elements.
'Slack'
const

Slack :: api

line 12
This item provides access to the Slack API, allowing integration with Slack services and functionalities.
'https://slack.com/api'
method

%Slack -> headers

line 14
Returns the headers required for authentication when making requests to the Slack API using a bearer token.
[static::bearer($this->config['bot_token'] ?? void)]
static

Slack :: fields

line 16
Defines the configuration fields for integrating with Slack, including the bot token, signing secret, and required scopes.
arr(
	section: 'Slack',
	secret: arr(
		bot_token: 'Bot user OAuth token (xoxb-...)',
		signing_secret: 'Signing secret for inbound webhook verification (optional)',
	),
	scopes: 'chat:write, channels:history, channels:read',
)
method

%Slack -> result (obj $res):obj

line 25
Processes the result from a Slack API call, returning the response if successful or a failure message if an error occurred.
if (!$res->ok) return $res
$data = $res->data
if (is_object($data) && ($data->ok ?? null) === false) return static::fail($data->error ?? 'Slack API error', $res->status)
return $res
method

%Slack -> send ($channel, $text, array $extra = []):obj

line 32
Sends a message to a specified Slack channel using the Slack API. It requires a configured bot token and accepts additional parameters through an array.
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->post('chat.postMessage', ['channel' => $channel, 'text' => $text] + $extra))
method

%Slack -> history ($channel, int $limit = 20):obj

line 37
Fetches the message history from a specified Slack channel, with an optional limit on the number of messages returned.
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->get('conversations.history', ['channel' => $channel, 'limit' => $limit]))
method

%Slack -> channels (int $limit = 100, string $types = 'public_channel'):obj

line 42
Retrieves a list of channels from Slack, with optional parameters to limit the number of channels and specify the types of channels to return.
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->get('conversations.list', ['limit' => $limit, 'types' => $types]))
object

%Telegram

/phlo/resources/connectors/chat/Telegram.phlo
version 1.0
creator q-ai.nl
summary Telegram Bot API connector: send messages, photos and documents; poll updates
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Telegram
tags telegram bot messaging chat connector
const

Telegram :: section

line 11
Defines a section within a Telegram resource, allowing for organized grouping of related content.
'Telegram'
method

%Telegram -> base

line 13
Constructs the base URL for the Telegram Bot API using the provided bot token from the configuration.
'https://api.telegram.org/bot'.($this->config['bot_token'] ?? void)
static

Telegram :: fields

line 15
Defines the fields related to Telegram configuration, including the bot token and optional webhook secret for verification.
arr(
	section: 'Telegram',
	secret: arr(
		bot_token: 'Bot token from BotFather',
		webhook_secret: 'Webhook secret token for inbound verification (optional)',
	),
	help: 'Create a bot via BotFather and store its token. The chat_id is the recipient or chat to message.',
)
method

%Telegram -> result (obj $res):obj

line 24
Processes the result from a Telegram API response, returning the response if successful or a failure message if an error is detected.
if (!$res->ok) return $res
$data = $res->data
if (is_object($data) && ($data->ok ?? null) === false) return static::fail($data->description ?? 'Telegram API error', $res->status)
return $res
method

%Telegram -> send ($chatId, $text, array $extra = []):obj

line 31
Sends a message to a specified Telegram chat using the provided chat ID and text, with optional extra parameters.
if ($m = $this->missing('bot_token')) return $m
return $this->result($this->post('sendMessage', ['chat_id' => $chatId, 'text' => $text] + $extra))
method

%Telegram -> photo ($chatId, $photo, $caption = void, array $extra = []):obj

line 36
Sends a photo to a specified Telegram chat with an optional caption and additional parameters.
if ($m = $this->missing('bot_token')) return $m
$payload = ['chat_id' => $chatId, 'photo' => $photo]
if ($caption !== void) $payload['caption'] = $caption
return $this->result($this->post('sendPhoto', $payload + $extra))
method

%Telegram -> document ($chatId, $document, $caption = void, array $extra = []):obj

line 43
Sends a document to a specified chat on Telegram, optionally including a caption and additional parameters.
if ($m = $this->missing('bot_token')) return $m
$payload = ['chat_id' => $chatId, 'document' => $document]
if ($caption !== void) $payload['caption'] = $caption
return $this->result($this->post('sendDocument', $payload + $extra))
method

%Telegram -> updates (int $offset = 0, int $limit = 100):obj

line 50
Retrieves updates from the Telegram bot API, allowing for pagination through the 'offset' and 'limit' parameters.
if ($m = $this->missing('bot_token')) return $m
return $this->result($this->get('getUpdates', ['offset' => $offset, 'limit' => $limit]))
object

%TokenStore

/phlo/resources/connectors/TokenStore.phlo
version 1.0
creator q-ai.nl
summary Persisted OAuth2 token store with automatic refresh via the OAuth2 resource
package connectors
frontend false
backend true
requires OAuth2
tags oauth oauth2 token refresh store credentials
static

TokenStore :: path ($key):string

line 10
The TokenStore::$path property defines the file path for storing token data, formatted as a JSON file based on a sanitized version of the provided key.
data.'tokens/'.preg_replace('/[^a-z0-9_.-]+/i', us, (string)$key).'.json'
static

TokenStore :: read ($key):array

line 12
Reads a token from the TokenStore by its key, returning an array of tokens if the file exists and is accessible.
$file = static::path($key)
if (!is_file($file)) return []
@chmod(data.'tokens', 0700)
@chmod($file, 0600)
return (array)json_read($file, true)
static

TokenStore :: write ($key, array $token):void

line 20
This method writes a token to a specified file in a secure directory, ensuring the directory and file have appropriate permissions.
$dir = data.'tokens'
is_dir($dir) || mkdir($dir, 0700, true)
@chmod($dir, 0700)
$file = static::path($key)
json_write($file, $token)
@chmod($file, 0600)
static

TokenStore :: valid (array $token):bool

line 29
Checks if the access token is valid by ensuring it exists and has not expired, allowing for a 30-second buffer before expiration.
($token['access_token'] ?? void) !== void && (int)($token['expires_at'] ?? 0) > time() + 30
static

TokenStore :: store ($res, $refresh):array

line 31
Stores the access token, refresh token, and expiration time for authentication purposes.
$token = [
	'access_token' => $res['access_token'],
	'refresh_token' => $res['refresh_token'] ?? $refresh,
	'expires_at' => time() + (int)($res['expires_in'] ?? 3600),
]
return $token
static

TokenStore :: lock ($key)

line 42
TokenStore::$lock manages a file-based locking mechanism for token storage, ensuring exclusive access to the token file during operations.
$dir = data.'tokens'
is_dir($dir) || mkdir($dir, 0700, true)
$lock = @fopen(static::path($key).'.lock', 'c')
if (!$lock || !flock($lock, LOCK_EX)){
	$lock && fclose($lock)
	return null
}
return $lock
static

TokenStore :: access ($key, $tokenUrl, $clientId, $clientSecret, array $seed = []):?string

line 53
Retrieves the access token from the TokenStore, refreshing it if necessary using the refresh token.
$token = static::read($key)
if (static::valid($token)) return $token['access_token']
$lock = static::lock($key)
if (!$lock) return null
try {
	$token = static::read($key)
	if (!($token['refresh_token'] ?? null) && ($seed['refresh_token'] ?? null)){
		$token = ['refresh_token' => $seed['refresh_token']]
		static::write($key, $token)
	}
	if (static::valid($token)) return $token['access_token']
	$refresh = $token['refresh_token'] ?? null
	if (!$refresh || !$tokenUrl || !$clientId) return null
	$res = OAuth2::refresh($tokenUrl, $clientId, $clientSecret, $refresh)
	if (!($res['access_token'] ?? null)) return null
	$token = static::store($res, $refresh)
	static::write($key, $token)
	return $token['access_token']
} finally {
	flock($lock, LOCK_UN)
	fclose($lock)
}
object

%Twilio

/phlo/resources/connectors/chat/Twilio.phlo
version 1.0
creator q-ai.nl
summary Twilio connector: send SMS and read message status
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Twilio
tags twilio sms messaging connector
const

Twilio :: section

line 11
Defines a section for Twilio integration within a Phlo application.
'Twilio'
method

%Twilio -> base

line 13
Constructs the base URL for accessing the Twilio API using the account SID from the configuration.
'https://api.twilio.com/2010-04-01/Accounts/'.($this->config['account_sid'] ?? void)
method

%Twilio -> headers

line 15
Retrieves the headers required for Twilio API requests using the provided account SID and auth token from the configuration.
[static::basic($this->config['account_sid'] ?? void, $this->config['auth_token'] ?? void)]
static

Twilio :: fields

line 17
Defines the fields for configuring Twilio integration, including account SID, sender number, and optional messaging service SID, along with the authentication token.
arr(
	section: 'Twilio',
	config: arr(
		account_sid: 'Account SID (ACxxxx)',
		from_number: 'Sender number in E.164, e.g. +31600000000 (use this or messaging_service_sid)',
		messaging_service_sid: 'Messaging Service SID (optional alternative to from_number)',
	),
	secret: arr(auth_token: 'Auth token'),
)
method

%Twilio -> sms ($to, $body, array $extra = []):obj

line 27
Sends an SMS message using Twilio's API, requiring either a from_number or messaging_service_sid from the configuration.
if ($m = $this->missing('account_sid', 'auth_token')) return $m
$from = $this->config['from_number'] ?? void
$service = $this->config['messaging_service_sid'] ?? void
if ($from === void && $service === void) return static::fail('Twilio from_number or messaging_service_sid required')
$fields = ['To' => $to, 'Body' => $body] + $extra
if ($service !== void) $fields['MessagingServiceSid'] = $service
else $fields['From'] = $from
return $this->form('Messages.json', $fields)
method

%Twilio -> message ($sid):obj

line 38
Retrieves a message from Twilio using the specified message SID.
if ($m = $this->missing('account_sid', 'auth_token')) return $m
return $this->get('Messages/'.$sid.'.json')

We use essential cookies to make this site work. With your permission we also use analytics to improve the site.