Positioning
The selection criteria for the 3 patterns (direct call / proxy / ingestion) are shared with 0-4 of /kuroco-app-builder . This skill goes further—what to check and what to be careful about after selecting—and explores it in depth. The authoritative source for the exact syntax of Smarty plugins is /kuroco-server-processing , and this skill cites it as material for design decisions.
If the other party is a REST API,{api}plugins cover methods, headers, bodies, file uploads, and even mTLS, so you will almost never get stuck on "whether it can connect" itself. When considering the proxy pattern, the focus of the design is not "whether it can be called in a REST-like way" but rather(1) Where to place constants and secrets(described later) and **(2) token lifecycle management** (described later). If you proceed to implementation without thoroughly resolving these two, even if you build something that works, it will stop after operations begin due to token expiration or misplaced keys.
Review of three patterns
| Pattern | Configuration | Cases it suits |
|---|---|---|
| Direct call | The frontend calls the external API directly. Kuroco is not involved. | The external API side has CORS allowed, it is acceptable to place keys on the frontend, and real-time responsiveness is the top priority. |
| Proxy (via Kuroco) | From the Smarty template of the custom endpoint {api} Calls the external API with a plugin and returns the result. |
You want to hide keys, centralize authentication/CORS/rate limiting on the Kuroco side, and process the response. |
| Ingestion | Ingest external data into Topics/CSV tables in advance and serve it via the standard Topics API. | The update frequency is low, and you want to put external data on Kuroco's standard features (search, cache, multilingual). |
Implementation Constraints of the Proxy Pattern
The plugin name is{api}。api_requestthere is no plugin with that name({api_internal}is a different thing that calls Kuroco's own API). Main parameters:
| Parameter | Content |
|---|---|
endpoint |
Destination URL (required) |
method |
GET/POST/PUT/PATCH/DELETE/PURGE/HEAD |
headers |
'Key: value'a string array in the format |
json_body / body |
JSON / non-JSON body |
files |
File to send.Only one file can be sent per call |
timeout |
Timeout in seconds (e.g., 60)。the default value and upper limit have not been confirmed in primary sources—if the design depends on a slow external API, either measure it before starting or consider switching not to a proxy but to ingestion (batch) for the reasons described later. |
sslcert/sslkey/cainfo |
Certificate, key, and CA information for mTLS. The value is not the certificate itself butthe secret's key name |
For detailed syntax and response storage (var/json_var/status_var) · Cache (cache_time)は /kuroco-server-processing refer to.
The overall execution time limit for custom endpoints also cannot be confirmed from the primary sources. separate pluginapi_mng(admin API) specifies a 20-second timeout, but this is{api}and cannot be reused. When designing a "proxy that depends on a slow external API," document this uncertainty in the deliverable, and if possible, measure it on a small scale before finalizing.
Ingestion patterns: batch vs spider vs Webhook
Spider is not suitable for periodic polling of structured APIs. The spider is a feature that "crawls specified web pages and files (S3 buckets, etc.), collects text, images, and files, and ingests them into Kuroco content," and its targets are unstructured data (web pages and files).The crawling itself generates billable API requestsso it is also unsuitable cost-wise for polling structured APIs.
When periodically fetching structured data such as from an external API,batch processingで {api} fetch via, and{api_internal} insert/update into Topics. For the batch free tier,if payment information is not registered, an execution limit of about 100 per hour(unlimited if a credit card is registered or payment is by invoice).
If you only want to receive pushes from the external system,Webhookor pre-preparedTrigger email address(e.g., sending an email to a phone number triggers SMS sending{番号}@twilio.r-cms.jp) may let you avoid writing Smarty code—before implementation, /kuroco-server-processing check the list of trigger email addresses.
Managing secret information
API keys, Webhook secret URLs, etc.Values that could be used in attacks are{secret}Pluginretrieved from (pre-registered in [Environment Settings]→[Secrets]).$smarty.const.*(site constants) are for non-secret configuration values and should not be a place to store confidential information. mTLS certificates, keys, and CA information are likewise{secret}referenced by the key name.
{secret var='api_key' key='EXAMPLE_API_KEY'}
Token management
Many causes of broken external integrations are not "cannot connect" but "it was connected, but the token later expired." For each authentication method of the integration destination, design the token's nature and management policy separately.
| Authentication method | Nature of the token | Management policy |
|---|---|---|
| Fixed API key | Does not expire (unless rotated) | {secret}Simply register it in. The simplest |
| OAuth2 client credentials | A short-lived access token can be issued each time (no user context) | client_id/client_secretを{secret}Place it in,Acquire the token on the spot each time it is called(JIT) is acceptable. There is little need for persistence |
| OAuth2 authorization code + refresh token | Long-lived refresh token + short-lived access token | The refresh token is{secret}. The access token isRefresh each time before useor, if the update frequency can be low, pass it around using the method described later |
| Signed requests (HMAC, etc.) | Not a token, but a signature for each request | The secret key{secret}and calculate the signature immediately before the call |
Constraints when an access token needs to be passed around: {secret}is a mechanism registered from the admin panel, andno plugin for writing values from Smarty has been found in primary sources(read-only{secret}only plugins were confirmed). Therefore, design the destination for passing around the access token that is periodically updated by a batch as one of the following.
- Acquire each time (JIT): Each time the proxy is called, first call the token issuance/refresh API with
{api}before calling the main process. Implementation is simple, but adds one round trip per call - Store in a protected Topics record: The batch process uses
{api}to update the token, and{api_internal}to write it to private dedicated content (e.g., an "external integration token" definition). The proxy side uses{api_internal}to read that record before calling the external API. This is suitable when you want to reduce round trips for a frequently called proxy. Always apply access restrictions so that the relevant content does not appear in lists or searches
api_tokenDo not confuse it with the plugin. api_tokenis a mechanism for issuing Kuroco's own static/dynamic access tokens from Smarty (used for{api_internal}preparing a token for calls on the spot, etc.), andis unrelated to managing OAuth tokens for external systems。
Even long-lived tokens may need to be refreshed (Instagram Basic Display API long-lived access tokens expire in 60 days), sodo not assume it is a "token that never expires"; always check the expiration and refresh method in the integration partner's documentation, and include whether an update batch is needed in the design.
Notes on the direct call pattern
KurocoFront settings (kuroco_front.json) handle only rewrites, Basic authentication, and IP address restrictions, andthere is no mechanism such as CSP to restrict outbound calls from the frontend. Whether CORS is allowed in the direct call pattern depends entirely onthe external API's policy on the other side, and there is no room for Kuroco to control it. If the other party does not allow CORS, the direct call cannot be chosen (switch to a proxy).
Pitfalls visible from real examples
| Integration partner/service | Pattern | Pitfall |
|---|---|---|
| Instagram Basic Display API | Import (batch) | Long-term access tokensexpire in 60 daysIf you do not prepare a separate batch that performs token renewal itself, the integration will stop within a few months. Estimate this operational cost at the design stage |
| Twilio | Proxy (trigger email address, no code required) | {番号}@twilio.r-cms.jp A no-Smarty-code proxy variant that sends SMS just by sending an email to . Before implementing individually, check whether this method is sufficient |
| LINE / Slack | Proxy (Webhook-based) | The main setup cost is not the implementation on the Kuroco side, but registering the OAuth app and configuring the Bot on the external service side |
| Amazon S3 / Vimeo / Google Analytics | Integrations premised on secret information | In either case{secret}The starting point is handling the credentials registered in . First confirm the types of credentials required for each integration destination |
Design deliverable template
## 外部連携: {連携先名}
- パターン: 直接呼び出し / プロキシ / 取り込み(バッチ|スパイダー|Webhook)
- 秘密情報: {secret}に登録する項目一覧
- トークンの性質: 固定キー / クライアントクレデンシャル / リフレッシュトークン付き / 署名方式
- トークンの持ち回し方針: JIT取得 / 保護Topicsレコードに保存(該当する場合)
- 運用コスト: トークン更新など定期メンテが必要か、有効期限は何日か
- タイムアウト: 相手APIの応答時間の想定と対策(未確認事項として明記するか、実測するか)
Anti-pattern
| Things you must not do | Reason |
|---|---|
| Trying to periodically fetch structured APIs with a spider | Spiders are for crawling web pages and files. Structured data is better suited to batch processing +{api}is appropriate |
API keys and Webhook secret URLs$smarty.const.*(site constants) |
A mechanism intended for non-secret configuration values. Values that could be used in attacks{secret}place in |
api_requestSearching for or trying to use a plugin named |
Does not exist. The correct plugin name is{api} |
| Adopting the proxy pattern without checking the external API's response time | {api}The default and maximum timeout values, as well as the overall endpoint execution time limit, are unconfirmed in primary sources. If the external API is slow, switch to import (batch) or measure in advance |
| Not estimating the operational cost of token renewal for integrations that use long-term access tokens | Example: Instagram Basic Display API expires in 60 days, requiring a separate batch for renewal |
Access tokens that require rotation{secret}trying to write to |
From Smarty{secret}No plugin has been confirmed that updates the value of . Design with JIT acquisition or storage in a protected Topics record |
api_tokenTrying to manage an external system's OAuth token with a plugin |
api_tokenis for Kuroco's own token issuance. It is unrelated to external system tokens |
Related skills
| Skill | Role |
|---|---|
/kuroco-app-builder |
Entry point for choosing a pattern in phases 0-4 |
/kuroco-server-processing |
{api}/{api_internal}/{secret}Smarty syntax references such as , and setup procedures for batch, spider, and trigger |
/kuroco-security-audit |
Audit secret information storage status and token inventory (read-only) |
/kuroco-api-performance-review |
When you are concerned about the frequency and cost of external calls |