Your first submission
The fastest way to confirm you can talk to Expeed Relay: send one submission using values your admin gave you.
What you need
Section titled “What you need”siteKey— from your admin (looks likemarketing-site-a)formKey— from your admin (looks likecontact-us)captchaToken— set tononeif the site has no CAPTCHA configured; otherwise a real Google/Cloudflare token (covered in CAPTCHA — Phase 3)
The submission
Section titled “The submission”Every submission POSTs to https://api.relay.expeed.com/api/v1/submissions with a JSON body. Below is the same submission in three languages — click a tab.
curl -X POST https://api.relay.expeed.com/api/v1/submissions \ -H "Content-Type: application/json" \ -d '{ "siteKey": "YOUR_SITE_KEY", "formKey": "YOUR_FORM_KEY", "captchaToken": "none", "data": { "name": "Jane Smith", "email": "jane@example.com", "message": "Testing Expeed Relay" } }'const res = await fetch('https://api.relay.expeed.com/api/v1/submissions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ siteKey: 'YOUR_SITE_KEY', formKey: 'YOUR_FORM_KEY', captchaToken: 'none', data: { name: 'Jane Smith', email: 'jane@example.com', message: 'Testing Expeed Relay' } })});const json = await res.json();console.log(json); // { success: true, submissionId: '...' }import requests
r = requests.post( 'https://api.relay.expeed.com/api/v1/submissions', json={ 'siteKey': 'YOUR_SITE_KEY', 'formKey': 'YOUR_FORM_KEY', 'captchaToken': 'none', 'data': { 'name': 'Jane Smith', 'email': 'jane@example.com', 'message': 'Testing Expeed Relay' } })print(r.json()) # {'success': True, 'submissionId': '...'}What to expect
Section titled “What to expect”201 Created— success. Response body is{ "success": true, "submissionId": "<uuid>" }. The submission is now in Expeed Relay’s queue and will be delivered per your form’s configuration (email / WhatsApp / webhook).400 Bad Request— usually a missing or invalid field. Response has amessageexplaining which. Also covers payload limits: at most 100 fields, 10,000 characters per value, 128 characters per field name. The field names_subject,_body, and_footerare reserved and rejected.404 Not Found— messageSubmission target not found or not permitted. Read the section below before you start debugging this one.429 Too Many Requests— you have exceeded ten submissions per minute from your IP. Clears by itself after a minute. Easy to hit while testing.503 Service Unavailable— Expeed Relay couldn’t reach an upstream provider (Google CAPTCHA verify, etc.). Safe to retry. If the message isCAPTCHA is misconfigured for this site, retrying will not help — the site names a CAPTCHA provider but has no secret stored, and an admin has to fix it.
The 404 is deliberately ambiguous
Section titled “The 404 is deliberately ambiguous”Submission target not found or not permitted is returned for four different causes, with nothing in the response to tell them apart:
- the
siteKeydoes not match any site - the
formKeydoes not match any form on that site - the site or the form has been deactivated
- your request’s
Originis not in the site’s allowed origins list
This is intentional. A more specific error would let anyone probe the API to discover which site keys are real, so the ambiguity is a deliberate anti-enumeration measure rather than a gap in the error handling.
The practical consequence is that an origin problem looks exactly like a typo in your site key. If you are confident the keys are right, do not keep re-checking them — ask your admin to confirm the exact contents of the site’s allowed origins list and compare it against the Origin header your browser is actually sending. An origin is a scheme, host, and optional port with no path and no trailing slash, so https://example.com matches and https://example.com/ does not. Server-to-server calls send no Origin header at all, which passes only when the site’s list is empty.
Ask your admin to check both Active toggles too — a deactivated site or form is indistinguishable from a wrong key from where you are sitting.
Verifying delivery
Section titled “Verifying delivery”Ask your admin to open the Submissions page in the dashboard. Your test should show up within seconds. From there, the Jobs page shows the actual delivery attempt (email sent, webhook fired) and its status.
- Full HTML example with reCAPTCHA v3 wired up — coming in Phase 3
- Framework integrations (React, Angular, Vue) — coming in Phase 3
- Backend integrations with API keys for server-to-server calls — coming in Phase 3
- All error codes with cause + fix — coming in Phase 3