Guide

Send survey invitations from backend events with API triggers.

Use an API trigger when your application already knows the right moment to ask for feedback. Survey.is handles the tracked invitation link, email queue, reminders, attribution, and results table metadata.

Endpoint: POST /api/invitation-trigger Best for lifecycle and post-purchase surveys

Why Use an API Trigger?

Most customer feedback is best requested after a real event: an order is delivered, a support case is resolved, a trial reaches day seven, a service appointment ends, or a customer finishes onboarding. API triggers let your backend queue that survey without building an invitation system yourself.

The integration can stay small. Your system sends a recipient, optional timing, and optional metadata. Survey.is creates one tracked invitation, sends it through the survey invitation worker, and connects the eventual response back to that invitation.

Example: when an order is marked delivered, your backend can queue an NPS invitation three days later. The respondent gets a personal survey link, and the order identifier can appear as hidden metadata in the authenticated Results response data table.

Setup

  1. Create the survey and make it Active when you are ready to receive responses.
  2. Open Invitations, then the API trigger tab.
  3. Create a trigger token, copy the secret immediately, and store it in your backend environment.
  4. Set the default subject, message, reminder days, and token cooldown in Survey.is.
  5. Call the trigger endpoint from your server when the customer event happens.

The API trigger tab inside Survey.is shows the endpoint and a copyable cURL example for the active token. For every supported request field, keep the API docs open while you wire the first integration.

Do not call API triggers from browser JavaScript or mobile clients. The trigger secret can queue invitations, so keep it on a trusted server.

Payload

The smallest request needs one recipient email. Add a name for friendlier email templates, send_in_seconds for a delay, and metadata for stable identifiers you want available later in Results.

{
  "email": "customer@example.com",
  "name": "Example Customer",
  "send_in_seconds": 259200,
  "metadata": {
    "order_id": "ord_1042",
    "fulfillment_event": "delivered"
  }
}

This obfuscated log shows a successful delayed invitation request and response:

Mon May 18 09:42:11 EDT 2026 [1024] - SENDING SURVEY TO: customer@example.com
Mon May 18 09:42:11 EDT 2026 [1024] - Send survey endpoint: https://survey.is/api/invitation-trigger
Mon May 18 09:42:11 EDT 2026 [1024] - Sending Survey.is payload:
Mon May 18 09:42:11 EDT 2026 [1024] - {"email":"customer@example.com","name":"Example Customer","send_in_seconds":259200,"metadata":{"order_id":"ord_1042","fulfillment_event":"delivered"}}
Mon May 18 09:42:11 EDT 2026 [1024] - RECEIVED SURVEY.IS RESPONSE:
Mon May 18 09:42:11 EDT 2026 [1024] - HTTP Code: 200
Mon May 18 09:42:11 EDT 2026 [1024] - {"ok":true,"message":"Invitation queued.","batch":{"uuid":"4b95d20a-bb8f-4c42-b894-d9fd83303ec2","scheduled_at":"2026-05-21 13:42:11","status":"scheduled"}}

Keep metadata useful and boring: source event IDs, order IDs, customer segments, or workflow names. Do not send passwords, payment card data, raw API secrets, or sensitive regulated information.

Examples

Each example sends the same delayed invitation. Use the language your backend already uses, and keep SURVEYIS_TRIGGER_TOKEN in server-side environment configuration.

<?php
function queueSurveyInvitation($email, $name = '', array $metadata = array(), $delaySeconds = 0)
{
	$endpoint = 'https://survey.is/api/invitation-trigger';

	// Keep this token server-side. Anyone with it can queue invitations.
	$token = getenv('SURVEYIS_TRIGGER_TOKEN');
	if (!$token) {
		throw new RuntimeException('Missing Survey.is trigger token.');
	}

	$payload = array(
		'email' => $email,
		'name' => $name,
		'metadata' => $metadata,
	);

	// Optional: wait before Survey.is sends the invitation email.
	if ((int) $delaySeconds > 0) {
		$payload['send_in_seconds'] = (int) $delaySeconds;
	}

	$ch = curl_init($endpoint);
	curl_setopt_array($ch, array(
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_POST => true,
		CURLOPT_POSTFIELDS => json_encode($payload),
		CURLOPT_TIMEOUT => 30,
		CURLOPT_HTTPHEADER => array(
			'Authorization: Bearer ' . $token,
			'Content-Type: application/json',
		),
	));

	$body = curl_exec($ch);
	$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	$error = curl_error($ch);
	curl_close($ch);

	if ($error || $httpCode < 200 || $httpCode >= 300) {
		throw new RuntimeException('Survey.is trigger failed: ' . ($error ?: $body));
	}

	return json_decode($body, true);
}

$result = queueSurveyInvitation(
	'customer@example.com',
	'Example Customer',
	// Metadata appears in Results after this recipient submits a response.
	array('order_id' => 'ord_1042', 'fulfillment_event' => 'delivered'),
	3 * 24 * 60 * 60
);

error_log('Queued Survey.is batch ' . $result['batch']['uuid']);

Responses and Retries

Successful requests return HTTP 200 with a batch summary. The batch is scheduled immediately or at the time calculated from send_in_seconds or send_at.

{
  "ok": true,
  "message": "Invitation queued.",
  "batch": {
    "uuid": "4b95d20a-bb8f-4c42-b894-d9fd83303ec2",
    "scheduled_at": "2026-05-21 13:42:11",
    "status": "scheduled"
  }
}

For network errors and 5xx responses, retry with normal backoff from your job queue. For HTTP 429, wait for the trigger token cooldown. For HTTP 400, fix the payload, token, survey state, or workspace plan before retrying.

Implementation Checklist

  • Store the trigger token in backend environment configuration, not in client code.
  • Keep the survey Active before expecting queued invitations to send.
  • Use one timing field per request: send_in_seconds or send_at.
  • Include a stable event or order identifier in metadata so results can be traced later.
  • Log request outcomes, but do not log bearer tokens or personal survey invitation links.
  • Make your own backend event handling idempotent so retries do not create duplicate invitations.

For full field reference and multi-recipient payloads, use the API docs.