Send your first request

PHP

Run a published flow from your application with the SDK and read what it answered.

6 min read

This page takes you from an API key to the first answer of a flow. Your application names an operation, Slen runs the flow bound to it, and the SDK hands back what the flow answered.

What you need

  • An API key with the gateway:write scope. Issue it on Keys & Access — Manage API keys walks through it.

  • A published flow. Flows are built and published on AI Flows — Publish, versions and rollback walks through a publish.

  • An operation code bound to the flow. Open the flow, then its Settings tab. Under Operation binding type a code into Operation code and press Save binding. The examples of this page use the code generate_email.

  • A connected provider for the model the flow calls. Connections are added on Connections — Connections walks through it.

Send the request

1. Install the SDK

Composer
composer require slen/sdk guzzlehttp/guzzle

The request of this page can be sent without the SDK as well. The same request over HTTP comes after the steps. Installation says what each SDK needs.

Put the key where your application reads its secrets. The examples of this reference read it from the SLEN_API_KEY environment variable.

Terminal
export SLEN_API_KEY="sl_live_…"

2. Create the client

The client takes the API key, and nothing else is needed: it calls the API of Slen. Configuration lists its other options.

PHP
use Slen\Sdk\SlenConfig;
use Slen\Sdk\SlenSdk;

$slen = SlenSdk::create(new SlenConfig(apiKey: (string) getenv('SLEN_API_KEY')));

An empty key is refused when the client is created, before any request is sent.

3. Run the operation

PHP
use Slen\Sdk\Modules\Operations\Options\ExecuteOptions;

$execution = $slen->operations()->execute(
    'generate_email',
    ['messages' => [['role' => 'user', 'content' => 'Write a short follow-up email.']]],
    new ExecuteOptions(idempotencyKey: 'order-42:email'),
);
  • The first argument is the operation code bound to the flow. It is not the name of the flow.

  • The second argument is the input of the flow. A flow with an AI Model node needs a non-empty input.messages.

  • The idempotency key names the piece of work, here an email of order 42. A request repeated under the same key with the same body does not run the flow a second time. It is answered with the execution the first request started, as that execution is at that moment, and replayed is true in the answer.

Warning:

Without a key of your own the SDK makes a new one for every call. A request your application sends again is then a second execution and a second spend.

4. Read the answer

The call returns the execution. When its status is completed, output holds what the flow returned. cost.estimated is what its model calls were expected to cost. What they cost, cost.actual, arrives after the answer — Send a request says when.

PHP
if ($execution->isCompleted()) {
    echo $execution->output['content'], PHP_EOL;
}

The same request over HTTP

The SDK sends one request. This is the request and its answer.

Terminal
curl https://api.slen.ai/api/v1/operations/execute \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Idempotency-Key: order-42:email" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "generate_email",
    "input": {
      "messages": [
        {
          "role": "user",
          "content": "Write a short follow-up email."
        }
      ]
    }
  }'
200 OK
{
  "data": {
    "execution_id": "74438200973594700",
    "status": "completed",
    "operation": "generate_email",
    "output": {
      "model": "gpt-4o",
      "content": "Hi Ada, just checking in on the proposal I sent last week.",
      "finish_reason": "stop",
      "tool_calls": null,
      "usage": {
        "input_tokens": 14,
        "output_tokens": 16,
        "cached_input_tokens": 0
      }
    },
    "error": null,
    "error_code": null,
    "error_message": null,
    "cost": {
      "estimated": "0.00412500",
      "actual": null
    },
    "cache": {
      "hit": false,
      "cached_at": null
    },
    "replayed": false,
    "waiting_on": null,
    "trace_url": "/v1/executions/74438200973594700"
  }
}

What the answer says

The status of the execution says how the request ended.

StatusWhat it means
completedThe flow reached Return Response. output holds its answer
rejectedThe flow reached Reject Request, or a refusal on the way closed the execution. error_code and error_message say why
failedAn error on the way closed the execution. error_code names the reason, and is null when the API has no code for the error
uncertainIt is not known how a model call ended: a provider did not answer in time, or could not be asked about a call it runs in the background
waitingThe flow stopped at a node that waits, and it continues later
queuedThe request was sent in async mode, and the flow has not started
runningThe flow is being walked now. A repeated request that comes during the walk reads this status

waiting, queued and running are not final. Async runs and waiting shows how to wait for the result.

A request that is refused or fails on the way is not answered with an execution. The API answers with an error, and the SDK raises it — Handling errors shows how to catch it. Two errors are common on a first request.

  • 404 with the code flow_not_found — no flow is bound to the operation code, the flow has no published version, or the flow is archived.

  • 422 with the code invalid_flow_input — the flow calls a model, and the input has no messages.

An error that comes after the execution has started leaves that execution closed, and the key stays with it. invalid_flow_input is such an error, and flow_not_found is not.

  • A repeat of the same request under that key is answered with the execution, not with the error again. Its status says how it ended — failed after invalid_flow_input — and error_code names the reason.

  • The same key with another body is refused: 409 with the code idempotency_conflict. Send a corrected request under a new key.

Find the execution in the console

Open the flow, then its Executions tab. The tab lists the executions of the flow, the newest first. Open one to see the path it took, node by node.

trace_url of the answer is the path of the same execution in the API.

Where to go next