Developer documentation
Relay home

Website Form API

Send website forms to Relay.

Connect a form on your website to an existing Relay form. A successful submission creates a contact or matches an existing one, then records the form activity in Relay.

EndpointPOST /api/v1/forms/FORM_ID/submissionsBase URL: https://www.tapintorelay.com

Step 1

Set up Relay

  1. Create and save a form in Relay.Add the contact fields and custom fields your website will send.
  2. Copy the form ID.On the Forms page, find the form card and select Copy beside its Form ID.
  3. Generate a company API key.Go to Settings → Integrations → Website Form API. Copy the key when Relay shows it.
  4. Add the key to your website server.Save it as a private environment variable named RELAY_API_KEY. Save the form ID as RELAY_FORM_ID.

Step 2

Authenticate the request

Send the company API key in the Authorization header on every request.

Authorization: Bearer YOUR_RELAY_API_KEY
Keep the API key private.

Call Relay from your website's server. Never put this key in HTML, browser JavaScript, a React client component, or a public environment variable such as NEXT_PUBLIC_RELAY_API_KEY.

Step 3

Send the form data

Send JSON using only the fields included on the selected Relay form. Every form must receive a fullName or company. Any field marked required in Relay must also be included.

{
  "company": "Example Restaurant",
  "email": "owner@example.com"
}
FieldTypeWhat to send
fullNamestringA person's full name.
companystringA company, organization, or restaurant name.
emailstringA valid email address.
phonestringA phone number with 7 to 15 digits.
jobTitlestringThe person's job title.
websitestringA valid website URL.
fieldsobjectOptional custom form values keyed by custom field ID.

Custom fields

Put custom field values inside fields. Each key must be the ID of a custom field on that Relay form, and every value must be a string.

{
  "company": "Example Restaurant",
  "email": "owner@example.com",
  "fields": {
    "CUSTOM_FIELD_ID": "Dinner"
  }
}

Step 4

Choose your language

These examples send a company name and email address. Replace the sample values with data from your website form.

cURL

Available in most terminals. Replace the three placeholder values before running it.

curl --request POST \
  "https://www.tapintorelay.com/api/v1/forms/FORM_ID/submissions" \
  --header "Authorization: Bearer YOUR_RELAY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "company": "Example Restaurant",
    "email": "owner@example.com"
  }'

JavaScript / Node.js

Uses the built-in fetch function in Node.js 18 or newer. No package is required.

const formId = process.env.RELAY_FORM_ID;
const apiKey = process.env.RELAY_API_KEY;

const response = await fetch(
  `https://www.tapintorelay.com/api/v1/forms/${formId}/submissions`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      company: "Example Restaurant",
      email: "owner@example.com",
    }),
  },
);

const result = await response.json();

if (!response.ok) {
  throw new Error(result.message ?? "Relay submission failed");
}

console.log(result);

Python

Install Requests first with: pip install requests

import os
import requests

form_id = os.environ["RELAY_FORM_ID"]
api_key = os.environ["RELAY_API_KEY"]
url = f"https://www.tapintorelay.com/api/v1/forms/{form_id}/submissions"

response = requests.post(
    url,
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    json={
        "company": "Example Restaurant",
        "email": "owner@example.com",
    },
    timeout=15,
)

response.raise_for_status()
print(response.json())

PHP

Uses PHP's cURL extension. Store the values as private server environment variables.

<?php
$formId = getenv('RELAY_FORM_ID');
$apiKey = getenv('RELAY_API_KEY');
$url = "https://www.tapintorelay.com/api/v1/forms/{$formId}/submissions";

$request = curl_init($url);
curl_setopt_array($request, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {$apiKey}",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "company" => "Example Restaurant",
        "email" => "owner@example.com",
    ]),
]);

$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
curl_close($request);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException("Relay submission failed: {$body}");
}

echo $body;

Ruby

Uses Ruby's built-in Net::HTTP library. No gem is required.

require "json"
require "net/http"
require "uri"

form_id = ENV.fetch("RELAY_FORM_ID")
api_key = ENV.fetch("RELAY_API_KEY")
uri = URI("https://www.tapintorelay.com/api/v1/forms/#{form_id}/submissions")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{api_key}"
request["Content-Type"] = "application/json"
request.body = {
  company: "Example Restaurant",
  email: "owner@example.com"
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "Relay submission failed: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

puts response.body

Result

Successful response

Relay returns HTTP 201 Created when the submission is accepted.

{
  "success": true,
  "submissionId": "SUBMISSION_ID",
  "contactId": "CONTACT_ID",
  "existingContact": false
}

When existingContact is true, Relay matched the submission to a contact already in the workspace by email or phone.

Reference

Errors and limits

StatusErrorMeaning
400invalid_json / invalid_requestThe JSON or request shape is invalid.
401invalid_api_keyThe API key is missing, invalid, or revoked.
403feature_not_availableWebsite Form API access requires Relay Pro.
404form_not_foundThe form ID does not belong to this Relay company.
409capacity_reachedThe workspace has reached its contact limit.
413payload_too_largeThe JSON body is larger than 32 KB.
422invalid_submissionA required or configured form value is invalid.
429rate_limitedToo many submissions were sent. Retry after 60 seconds.

Each API key and form combination can accept up to 120 requests per minute and 10,000 requests per day. Request bodies are limited to 32 KB.

Ready to connect a form?

Generate your API key in Relay.

Open API settings