SuperAPI AI Directory

kuroco-server-processing

Coding & development

View repository

Updated 10-15 21:10

About this skill

Kuroco Server-Side Processing

Kuroco's Smarty template plugin reference and Webhook/batch processing patterns.

Documentation Reference: /kuroco-docs You can search and reference the official Kuroco documentation using skills.

Table of Contents

Part 1: Smarty Plugin Reference

Part 2: Webhook/Batch Processing Patterns


Part 1: Smarty Plugin Reference

Complete reference of all plugins available in Kuroco's Smarty templates.

Frequently Used Plugins

Variable/Data Operations

Plugin Description Example
assign Variable assignment.var can be written with dot notation for nested arrays {assign var="request.status" value="pending"}
append Array append. Use this when the key is a variable {append var="arr" index=$key value="値"}
json_decode JSON Parse {$json|json_decode:true}
rcms_json_encode JSON Encode {$arr|@rcms_json_encode}

API/Data Retrieval

Plugin Description Example
api_internal Internal API call {api_internal endpoint='/rcms-api/1/news' var='result'}
api_method Directly execute model operations without creating an endpoint (GET only) {api_method var='result' model='Topics' method='list' ...}
assign_tag_list Retrieve tag list {assign_tag_list var='tags'}

→ Details: references/api-plugins.md

String Processing

Plugin Description Example
escape Escape {$html|escape}
truncate String truncation {$text|truncate:100:"..."}
mb_truncate Multibyte support {$text|mb_truncate:50}
date_format Date format {$date|date_format:"%Y-%m-%d"}
translate Translation {$key|translate}
nl2br Convert newlines to BR {$text|nl2br}
replace String replacement {$text|replace:"a":"b"}

→ Details: references/string-plugins.md

Form/UI

Plugin Description Example
fileupload File Upload {fileupload id="photo" hidden_nm="photo_url" url=$upload_url}{/fileupload}
inquiry_input Form input {inquiry_input col="name" ...}
pager Pagination {pager info=$pageInfo}

→ Details: references/form-plugins.md

Authentication/Permissions

Plugin Description Example
rcms_auth Permission control block {rcms_auth target="read:/topics/"}...{/rcms_auth}
login Login processing {login ...}
logout Logout processing {logout ...}

→ Details: references/auth-plugins.md

External Service Integration

Plugin Description Example
sendmail Email sending {sendmail to=$email subject="件名" contents="本文"}
slack_post_message Slack notification {slack_post_message channel="#general" text="..."}
ai_completion AI call {ai_completion var='result' message=$prompt model='gpt-4'}
github_deploy GitHub Deploy {github_deploy ...}

→ Details: references/integration-plugins.md

File Operations

Plugin Description Example
write_file File writing {write_file var="path" value="内容"}
put_file Storage Upload {put_file path="/files/..." tmp_path=$tmp}
read_file Read file line by line (blocking) {read_file name="log" path="/files/user/..." row="line"}{$line}{/read_file}
read_dir Directory reading {read_dir name="files" path="/files/user/..." file_var='file'}...{/read_dir}

→ Details: references/file-plugins.md

Vue.js integration

Plugin Description Example
rcms_vue_component Vue Component {rcms_vue_component config="rcms-mng" name="..."}
head_include Add to head {head_include file="..."}

→ Details: references/vue-plugins.md

Reference by category

Category File Main plugins
Syntax reference syntax.md Basic syntax, control structures, built-in variables, best practices
API・Data retrieval api-plugins.md api_internal, api_method, assign_tag_list
String processing string-plugins.md escape, truncate, date_format, translate
Array operations array-plugins.md count, in_array, implode, explode, sort family
Form/UI form-plugins.md fileupload, inquiry_input, pager, html_*
Authentication・Permissions auth-plugins.md rcms_auth, login, logout
External integration integration-plugins.md sendmail, slack_*, ai_completion
File operations file-plugins.md write_file, put_file, read_file, read_dir
Vue.js integration vue-plugins.md rcms_vue_component, head_include
All plugins all-plugins.md List of all 151 plugins
Part 2: Webhook・Batch processing patterns

Best practices for Webhooks, batch processing, and external integration in Kuroco HeadlessCMS.

About Smarty syntax: Batch processing and triggers are written in Smarty templates. For details on syntax and plugins, refer to Part 1 above.

Batch processing

Overview

Batch processing is processing that is automatically executed at fixed intervals.

Execution frequency options:

Frequency Use case
Every 15 minutes When frequent synchronization is required
Every 30 minutes Near real-time processing
Every hour Regular aggregation and updates
Daily (specified time) Daily reports, backups

Execution limits for free-use users: For sites that have selected card payment and have no card registered,batch launches (registrations) are limited to 100 times per hour. The count is the number of batch launches, not the number of requests issued within the batch (external {api} sending is counted separately at 1,000 times/hour). If a card is registered or payment is by invoice, there is no limit.

The maximum execution time for one batch is 4 hours by default, and 6 hours for Smarty batches—exceeding this results in a timeout failure. Rather than trying to fit large amounts of data within this limit, split it into pages as described in "Timeout countermeasures" below to keep each run short.

Use Cases

  • CSV generation and integration with external systems
  • Data import from external systems
  • Log aggregation and statistical data calculation
  • Regular email delivery
  • GitHub Actions integration (deploy trigger)

Creating batch processing

Admin panel: [Operations] → [Batch processing] → [Add]

Item Description Example
Title Batch name CSV output batch
Identifier Unique identifier (alphanumeric) csv_export
Execution frequency Execution interval Daily 03:00
Execution content Written in Smarty syntax See below

Internal API calls

Basic syntax

{api_internal
  endpoint='/rcms-api/1/news'
  method='GET'
  member_id=1
  queries=$queries
  var='response'
}

Retrieve content list

{assign var="queries" value=$dataSet.emptyArray}
{append var="queries" index="cnt" value=0}
{append var="queries" index="filter" value="topics_flg = 1"}

{api_internal
  endpoint='/rcms-api/1/news'
  method='GET'
  member_id=1
  queries=$queries
  var='news_list'
}

{foreach from=$news_list.list item="news"}
  ID: {$news.topics_id}, タイトル: {$news.subject}
{/foreach}

Create content

The POST request body is also queries Passed viabody There is no such parameter).

{assign var="body" value=$dataSet.emptyArray}
{append var="body" index="subject" value="タイトル"}
{append var="body" index="contents" value="本文"}
{append var="body" index="open_flg" value=1}

{api_internal
  endpoint='/rcms-api/1/news/insert'
  method='POST'
  member_id=1
  queries=$body
  var='result'
}

Update (/update/{topics_id}) has the same form; put only the keys to change in queries . For extended fields, use the ext_slug name (if not set, the ext_1 / ext_col_01 format) as the key—check the key name and see bulk_upsert は /kuroco-api-content .

Designing integration methods for external systems

Before connecting to an external system, decide which of the 3 patterns to use (the selection criteria are the same as 0-4 in /kuroco-app-builder ).

Pattern Configuration Suitable cases
Direct call The frontend calls the external API directly. Kuroco is not involved The external API allows CORS, the key can be placed in the frontend, real-time performance is the top priority
Proxy (via Kuroco) From the Smarty template of the custom endpoint, {api} Call the external API with the plugin and return the result You want to hide the key, unify authentication/CORS/rate limiting on the Kuroco side, or process the response
Ingestion Import external data into Topics/CSV tables in advance and provide it via the standard Topics API The update frequency is low, and you want external data to also use Kuroco's standard features (search, cache, multilingual)

Judgment criteria:

  • Is it necessary to keep the key secret? → If yes, use a proxy or ingestion. Direct calls allow the key to be read from the frontend JS, so they cannot be used for private keys
  • Is real-time performance required? → If required, use a proxy; if acceptable, use ingestion
  • Do you want external data to also use Kuroco's standard features (search, categories, cache, multilingual)? → If yes, use ingestion
  • Spider is not suitable for polling structured APIs(It is for crawling and ingesting web pages and files, and the crawl itself counts as billable requests). If you want to periodically fetch structured APIs, ingestion can also use batch processing +{api} .
  • Sending notifications to external destinations (Slack / LINE / SMS / email) is outside the 3 patterns. You can either call an integration plugin from trigger processing or simply send to a trigger email address (→ External service integration)

If the other party has a REST API, {api} will rarely get stuck on "whether it can connect." The focus of the design is (1) where to place secrets ({secret}) と (2) token lifecycle management Place it in. Things to confirm after choosing—{api} restrictions (1 file per call, default timeout 30 seconds / maximum 3600 seconds. Custom endpoints themselves are cut off at 30 seconds), the suitability/unsuitability of batch / spider / Webhook, whether to obtain OAuth tokens each time (JIT) or store them in protected Topics records, practical pitfalls such as Instagram long-lived tokens expiring in 60 days, and design deliverable templates—are references/integration-design.md summarized in. Once you choose proxy / ingestion, read this before implementation (if you only need the syntax, you may proceed to the next section). For how to write returning results to the frontend via proxy, see Returning from a proxy endpoint。

External API calls

For external API calls, use the {api} plugin ({api_internal}is a different plugin that calls Kuroco's own API, so do not confuse them.api_requestThere is no plugin with that name).

Basic syntax

{api
  endpoint='https://api.example.com/endpoint'
  method='GET'
  headers=$headers
  var='response'
  status_var='status'
}

POST request example (JSON)

headersは'Key: value'format strings in an array. Pass the JSON body tojson_body.

{secret var='api_key' key='EXAMPLE_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value='Content-Type: application/json'}
{append var=headers value="Authorization: Bearer `$api_key`"}

{assign_array var=body values=""}
{append var=body index='message' value='Hello'}

{api
  endpoint='https://api.example.com/post'
  method='POST'
  headers=$headers
  json_body=$body|@json_encode
  json_var='response'
  status_var='status'
}

When sending non-JSON (e.g. CSV)

bodyattribute. Even for non-JSON content, in order to escape multibyte characters, you need to pass it through|@json_encode. Specify the Content-Type header explicitly in thetext/***format.

{assign_array var=headers values=""}
{append var=headers value='Content-Type: text/csv'}
{assign var=csv value="ID,NAME,PRICE\n1,apple,150\n2,orange,200"}

{api
  endpoint='https://api.example.com/upload'
  method='PUT'
  headers=$headers
  body=$csv|@json_encode
  var='response'
  status_var='status'
}

Main parameters

Parameters Description
endpoint Destination URL (required)
query / queries Query string / query parameter array (may also be written directly in the URL)
method GET/POST/PUT/PATCH/DELETE/PURGE/HEAD
headers 'Key: value'format string array
json_body / body JSON / non-JSON request body
files File to send.Only 1 file can be sent per call(the second and subsequent items in the array are ignored)
var / json_var Response storage variable.For APIs that return JSON, use json_var (you can receive it as a decoded array.(var is the raw string)
status_var Success/failure (0/1)
http_code_var / resp_header_var Storage variables for HTTP status code / response headers
timeout Timeout in seconds.Default 30, specifiable from 1 to 3600(out of range is an error). For slow external APIs, either extend it explicitly or switch to ingestion (batch).
cache_time Cache time (minutes). Reduces round trips to the counterpart API. This has a different purpose from caching on the Kuroco side endpoint (which reduces Kuroco API request billing), and they can be used together.
sslcert / sslkey / cainfo Certificate, key, and CA information for mTLS. The value isthe secret key name, not the certificate itself

Values that should be kept secret, such as external API keys, should be read via the **{secret}plugin** (registered in advance from [Environment Settings] → [Secrets]).$smarty.const.*(site constants) are for non-secret configuration values, and should not be used for confidential information such as API keys.

{secret var='api_key' key='EXAMPLE_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value="Authorization: Bearer `$api_key`"}
{api
  endpoint='https://api.example.com/endpoint'
  headers=$headers
  var='response'
}

Proxy endpoint response (custom processing)

request_api / request_api_post By default, the custom endpoint forThe data returns the variable {"data": …} in the form。PHP execution time for 1 request is 30 secondsassigned in the template (the API entry's set_time_limit(30)), so in the proxy {api} When calling timeout set it to less than 30 (e.g. 10)—if left at the default 30 seconds, the endpoint side will be cut off first while waiting externally. To return JSON in any form as-is, enable show_contents in the endpoint settings, and the template outputs a JSON string (if the output is empty, [], and if the JSON is invalid, Contents JSON error). The request parameters are $smarty.request.*(common to GET/POST) or $smarty.post.* and validate before embedding it in an external URL.

{assign var=city value=$smarty.request.city|default:"tokyo"}
{secret var='weather_key' key='WEATHER_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value="X-Api-Key: `$weather_key`"}

{api
  endpoint="https://api.weather.example/today?city=`$city`"
  method='GET'
  headers=$headers
  json_var='forecast'
  status_var='ok'
  timeout=10
  cache_time=30
}

{if $ok == 1}
  {assign var='data' value=$forecast}
{else}
  {logger msg1="weather-proxy-error" msg2="city=`$city`"}
  {assign_array var=err values=""}
  {append var=err index='error' value='weather_unavailable'}
  {assign var='data' value=$err}
{/if}
{* 既定はこれで {"data": …} が返る。show_contents を有効にした場合は代わりに {$data|@rcms_json_encode} を出力する *}

Trigger processing

Trigger on content update

Admin screen: [Content definition] → [Trigger settings]

Available events:

Event Timing
On create After content creation
On update After content update
On delete After content deletion
On publish When publication status changes
After preview site submission After the submission process to the preview site (stage site) is complete

Available variables:

{$topics.topics_id}      {* コンテンツID *}
{$topics.subject}        {* タイトル *}
{$topics.contents}       {* 本文 *}
{$topics.ymd}            {* 公開日 *}
{$topics.ext_col_01}     {* 拡張項目 *}

Trigger on form submission

Admin screen: [Form] → [Trigger settings]

{$inquiry.inquiry_id}    {* 回答ID *}
{$inquiry.name}          {* 名前 *}
{$inquiry.email}         {* メールアドレス *}
{$inquiry.message}       {* メッセージ *}

External service integration

Detailed integration patterns: references/integrations.md(GitHub Actions / Slack / Chatwork / Email / SendGrid / Webhook / custom processing). LINE, SMS, and X only have trigger email addresses, and there is no additional information in references

Trigger email address (integration triggered by email sending)

By specifying a dedicated address as the email recipient, you can trigger sending to external services, batch processing, or starting AI agents upon email sending. The triggering email may be the {sendmail}of trigger processing, the recipient of a form's auto-reply or admin notification email, or a newsletter—first consider recipient settings that avoid writing code。

Prerequisites: Each recipient requires the integration settings for the target channel to be enabled (For LINE, the trigger email address is displayed in [Channel]→[Messaging]→[LINE]. For Slack, Slack integration in site settings). The local part (before @) is Slack=channel ID or #channel name, LINE=the destination LINE user ID (obtained via the official account's friend-add Webhook or LINE Login (OAuth SSO) and saved to the member—kuroco-docs LINE integration tutorial), SMS=phone number. Only the text of the email body can be sent (For LINE, [emoji:…] notation emoji are also allowed).

Destination address Action
{channel}@slack.r-cms.jp Slack send
{twitter_id}@tweets.twitter.r-cms.jp X (Twitter) post
{batch_id}@batch.r-cms.jp Batch processing startup
{ai_agent_id}@agent.r-cms.jp AI agent startup
{LINE ID}@text.line.r-cms.jp LINE sending
{tel}@twilio.r-cms.jp Text message (SMS) sending (Twilio)

Slack notification

The plugin name is slack_post_message(slack_send plugin does not exist). Instead of a webhook URL, use the site settings' Slack integration (slack_bot_token).

{slack_post_message
  channel="#general"
  text="通知メッセージ"
}

Email notification

The parameter name in the body is contents(body ).

{sendmail
  to="recipient@example.com"
  subject="件名"
  contents="本文"
}

GitHub Actions integration

{secret var='github_token' key='GITHUB_TOKEN'}
{assign_array var=headers values=""}
{append var=headers value="Authorization: token `$github_token`"}
{append var=headers value='Accept: application/vnd.github.v3+json'}

{assign_array var=body values=""}
{append var=body index='event_type' value='kuroco-update'}

{api
  endpoint='https://api.github.com/repos/owner/repo/dispatches'
  method='POST'
  headers=$headers
  json_body=$body|@json_encode
  var='response'
  status_var='status'
}

Best Practices

  • Execution time: Set it to a time slot with low system load (late night/early morning), and process large amounts of data once a day with paging ({while} Example of looping through pages: references/examples.md)
  • Error Handling: errors To avoid |@count > 0 even when empty, check with{logger}(msg1〜msg4, each within 1KB) and slack_post_message to notify (example: references/examples.md)
  • There is no tag for early termination. To "do not execute the rest" on failure, express it by enclosing the write part in {if $status == 1}…{/if}(or errors|@count == 0)
  • Dynamic endpoint pathis interpolated with backticks.{id} If you write curly braces like the following as-is, they will be interpreted as Smarty tags
  • Shortened assignment {$var = ...} does not exist. Arguments following a variable tag are not read by the compiler and are discarded, so the save and execution succeed but only the assignment disappears. Use {assign} か {append} to write values (references/syntax.md)
{api_internal endpoint="/rcms-api/3/product/update/`$row.topics_id`" method='POST' member_id=1 queries=$body var='res' status_var='ok'}

Related skills

  • /kuroco-api-content - API design, authentication patterns, content CRUD operations
  • /kuroco-admin-mcp - Management operations via Admin MCP

Related documents

  • ../kuroco-docs/docs/tutorials-api-custom-1.md(how-to-use-batch) - How to use batch processing
  • ../kuroco-docs/docs/tutorials-content-1.md(auto-run-github-with-contents-update) - GitHub Actions integration
  • ../kuroco-docs/docs/tutorials-form-mail-1.md(send-slack-notification-after-a-form-has-been-submitted) - Slack notification
  • ../kuroco-docs/docs/reference-smarty-trigger-3.md(trigger-variables) - Trigger variables