# Start an automation

Source: https://docs.revoplyai.com/api-reference/hooks/start-flow-from-hook/

> Starts the flow this hook belongs to for the customer your JSON names, by the paths set in the flow's trigger.

```http
POST https://api.revoplyai.com/hooks/{token}
```

Starts the flow this hook belongs to for the customer your JSON names, by the paths set in the flow's trigger. The run is queued, not finished: `202 accepted` returns its id at once, and `flow.completed` or `flow.failed` tells you how it ended. Send an `Idempotency-Key` to make retries safe.

## Parameters

| Name | In | Required | Description |
| --- | --- | --- | --- |
| `token` | path | yes | The hook's token, as the flow builder shows it once: `rvh_` and 43 URL-safe characters. Keep it secret; regenerate it if it leaks. |
| `Idempotency-Key` | header | no | Your own id for this request, such as the order number. A repeat with the same key starts nothing new and answers 200 `duplicate` with the first run's id. |

## Request body

```json
{
  "type": "object"
}
```

Example:

```json
{
  "order": {
    "id": "10482",
    "status": "shipped"
  },
  "customer": {
    "name": "نورة العتيبي",
    "phone": "+966501234567"
  }
}
```

## Responses

### 200

`duplicate`: A request with this `Idempotency-Key` already started a run; nothing new was queued. `id` is that run.

```json
{
  "id": "8f14e45f-ceea-467a-9575-5b1e2c7d3a90",
  "status": "duplicate",
  "detail": null
}
```

### 202

`accepted`: The flow was queued for the customer the body names. `id` is the run.

```json
{
  "id": "8f14e45f-ceea-467a-9575-5b1e2c7d3a90",
  "status": "accepted",
  "detail": null
}
```

### 400

`invalid_json`: The body is not JSON. `idempotency_key_too_long`: The `Idempotency-Key` header is longer than 200 characters.

```json
{
  "id": null,
  "status": "invalid_json",
  "detail": null
}
```

### 403

`not_in_plan`: The account's plan does not include automations, the developer API or automated templates.

```json
{
  "id": null,
  "status": "not_in_plan",
  "detail": null
}
```

### 404

`not_found`: No hook has this token. It may have been regenerated or deleted.

```json
{
  "id": null,
  "status": "not_found",
  "detail": null
}
```

### 409

`flow_off`: The flow is not published, is switched off, or is beyond the plan's number of flows. `flow_not_listening`: The published flow is not started by its webhook. `channel_unavailable`: The flow's WhatsApp number is not connected. `opted_out`: The customer opted out of messages from this business.

```json
{
  "id": null,
  "status": "flow_off",
  "detail": "The flow is not published, switched on and within the plan's flows."
}
```

### 413

`payload_too_large`: The body is over 64 KB.

```json
{
  "id": null,
  "status": "payload_too_large",
  "detail": "Keep the body under 64 KB."
}
```

### 415

`unsupported_media_type`: The body was not sent as `application/json`.

```json
{
  "id": null,
  "status": "unsupported_media_type",
  "detail": "Send the body as application/json."
}
```

### 422

`invalid_phone`: No phone number at the flow's phone path, or one that cannot be read. Send it in E.164, such as +9665XXXXXXXX.

```json
{
  "id": null,
  "status": "invalid_phone",
  "detail": "No phone number at \"customer.phone\"."
}
```

### 429

`rate_limited`: More than 60 requests a minute to this hook, or 1000 an hour to the account's hooks together. `template_limit_reached`: Today's automated templates for the account are used up. `customer_limit_reached`: This customer has had 3 automated templates in the last 24 hours. Our per-address limit on hook URLs may also answer 429, as plain text.

```json
{
  "id": null,
  "status": "rate_limited",
  "detail": null
}
```

### 503

`service_unavailable`: Hooks are paused on our side, or we could not count requests. Try again in a minute.

```json
{
  "id": null,
  "status": "service_unavailable",
  "detail": "Try again in a minute."
}
```

## Code samples

### cURL

```bash
# --fail-with-body exits non-zero on 4xx/5xx and still prints the problem JSON;
# branch on its "status" field, never on "detail".
curl --fail-with-body -X POST "https://api.revoplyai.com/hooks/{token}" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "order": {
    "id": "10482",
    "status": "shipped"
  },
  "customer": {
    "name": "نورة العتيبي",
    "phone": "+966501234567"
  }
}'
```

### Node.js

```js
import { randomUUID } from 'node:crypto';

const res = await fetch("https://api.revoplyai.com/hooks/{token}", {
  method: 'POST',
  headers: {
    'Idempotency-Key': randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "order": {
      "id": "10482",
      "status": "shipped"
    },
    "customer": {
      "name": "نورة العتيبي",
      "phone": "+966501234567"
    }
  }),
});

const data = await res.json();
if (!res.ok) {
  // branch on data.status, never on data.detail
  throw new Error(`${res.status} ${data.status}: ${data.detail ?? data.title}`);
}
console.log(data);
```

### Python

```python
import uuid

import requests

res = requests.request(
    "POST",
    "https://api.revoplyai.com/hooks/{token}",
    headers={
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "order": {
            "id": "10482",
            "status": "shipped",
        },
        "customer": {
            "name": "نورة العتيبي",
            "phone": "+966501234567",
        },
    },
    timeout=30,
)

data = res.json()
if not res.ok:
    # branch on data["status"], never on data["detail"]
    raise RuntimeError(f"{res.status_code} {data['status']}: {data.get('detail')}")
print(data)
```

### PHP

```php
<?php

function uuidv4(): string
{
    $b = random_bytes(16);
    $b[6] = chr((ord($b[6]) & 0x0f) | 0x40);
    $b[8] = chr((ord($b[8]) & 0x3f) | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($b), 4));
}

$body = <<<'JSON'
{
  "order": {
    "id": "10482",
    "status": "shipped"
  },
  "customer": {
    "name": "نورة العتيبي",
    "phone": "+966501234567"
  }
}
JSON;

$ch = curl_init('https://api.revoplyai.com/hooks/{token}');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Idempotency-Key: ' . uuidv4(),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$data = json_decode($response, true);

if ($status >= 400) {
    // branch on $data['status'], never on $data['detail']
    throw new RuntimeException("$status {$data['status']}: " . ($data['detail'] ?? ''));
}
print_r($data);
```

### C#

```csharp
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

using var http = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.revoplyai.com/hooks/{token}");
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent(
    """
    {
      "order": {
        "id": "10482",
        "status": "shipped"
      },
      "customer": {
        "name": "نورة العتيبي",
        "phone": "+966501234567"
      }
    }
    """,
    Encoding.UTF8, "application/json");

using var response = await http.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
if (!response.IsSuccessStatusCode)
{
    // branch on "status", never on "detail"
    var code = doc.RootElement.GetProperty("status").GetString();
    throw new HttpRequestException($"{(int)response.StatusCode} {code}");
}
Console.WriteLine(json);
```
