Skip to main content
Find answers to the most common questions about Gomobile.

Authentication & Access

API keys are provisioned by the Gomobile team to ensure security and proper access control.To request an API key:
  1. Visit our API Key Request Form
  2. Fill in your details and use case
  3. Our team will review and provision your key within 24 hours
  4. You’ll receive your API key via secure email
Once you receive your key, store it securely and use it in the Authorization header:
x-api-key YOUR_API_KEY
Gomobile uses API key-based authentication. Your API key is a long-lived credential that you include in every request:
x-api-key YOUR_API_KEY
FeatureAPI Key
LifespanLong-lived
Obtained viaRequest from Gomobile team
Refresh neededNo
Best forAll API integrations
API keys are provisioned by our team. Request your API key to get started.
Common reasons:
  1. Expired - Your key may have an expiration date
  2. Revoked - The key may have been revoked for security reasons
  3. Wrong format - Ensure you’re using x-api-key: <your-key>
  4. Typo - Double-check you’re using the correct key
To resolve: Contact our support team and we’ll help you verify your key status or provision a new one.
Yes! You can have multiple API keys for different purposes:
  • Per environment: Separate keys for development, staging, and production
  • Per integration: One key per third-party service
  • Per team member: Individual keys for accountability
To request additional API keys, contact our team with your use case.

Contacts & Audiences

ConceptDescription
ContactAn individual person with a phone number and optional details (name, email, address, custom attributes)
AudienceA named group of contacts that can be targeted by a program
Think of contacts as rows in a database, and audiences as saved filters or segments. One contact can belong to multiple audiences.
Yes! Contacts can belong to any number of audiences simultaneously. Add contacts to an audience using:
POST /audience/:id/add-contacts
{
  "contacts": ["contact-uuid-1", "contact-uuid-2"]
}
Phone numbers must be 3-20 characters. We recommend E.164 format:
+[country code][number]
Examples:
  • +212612345678 (Morocco)
  • +14155551234 (USA)
  • 06-12-34-56-78 (spaces/dashes)
  • 0612345678 (missing country code)
Use the upsert endpoint to import multiple contacts at once:
POST /contact/upsert
{
  "data": [
    {
      "firstName": "John",
      "lastName": "Doe",
      "primaryPhone": "+212612345678"
    },
    {
      "firstName": "Jane",
      "lastName": "Smith",
      "primaryPhone": "+212612345679"
    }
  ]
}
Existing contacts (matched by phone number) are updated; new contacts are created.
Yes! First, define a custom attribute for your organization:
POST /custom-attributes
{
  "displayName": "Customer Tier",
  "type": "text"
}
Supported types: text, number, boolean, date, phone_number, email, url.Then include it when creating/updating contacts:
{
  "primaryPhone": "+212612345678",
  "customAttributes": {
    "customer_tier": "gold"
  }
}

Flows & Nodes

ConceptPurpose
FlowDefines what happens during a call - the logic, audio, inputs, branching
ProgramDefines when, who, and how - audience, schedule, retry strategy, pause windows
A flow is like a script; a program is like a scheduled performance of that script to a specific audience.
Yes! Flows are templates that can be used by many programs. Create the flow once, then reference its flowId in different programs targeting different audiences or schedules.
NodePurposeKey Outputs
DialPlaces outbound callonAnswer, onVoicemail, onNoAnswer, onBusy, onRejected, onError
AnswerAnswers inbound callonSuccess, onError
PlayPlays audioonComplete, onError
DTMFCollects keypad inputbranches (by digit), onSuccess, onTimeout, onInvalid, onMaxRetries
RecordRecords voiceonComplete, onTimeout, onError
ConditionBranches on logiconTrue, onFalse, onError
Set VariableStores a valueonSuccess, onError
HangupEnds the callNone (terminal)
Use the validate endpoint to check your flow without saving:
POST /flows/validate
Pass your flow definition (the graph object) in the request body.Response:
{
  "valid": true,
  "errors": []
}
You can also execute a single test call using POST /flows/execute with a test contact.

Calls & Execution

Check the call report (GET /call-report/:jobId) for the outcome field:
OutcomeMeaning
no_answerRecipient didn’t pick up (timeout reached)
busyLine was busy
rejectedRecipient declined the call
failedSystem error (check outcomeReason)
cancelledCall was cancelled before completion
Also verify:
  • Phone number format is correct
  • DID pool has valid numbers
  • Program status is active
AMD = Answering Machine DetectionWhen enabled (enableAMD: true) on a Dial node, the system detects whether a human or voicemail answered:
  • Human detected → Routes to onAnswer
  • Machine detected → Routes to onVoicemail
This lets you play different messages or skip voicemails entirely.
Two options:
  1. Pause (can resume later):
    PATCH /program-executions/:id/pause
    
  2. Cancel (permanent):
    DELETE /program-executions/:id
    
Note: Already-queued calls will complete; only pending contacts are affected.
Yes, through retry strategies. If a call fails (no answer, busy, etc.), the system can automatically retry based on your configuration:
  • fixed_delay: Retry after X minutes
  • scheduled: Retry at specific times
See Retry Strategies for details.

Retry Strategies

It depends on your retry strategy:
  • none: No retries (1 attempt total)
  • fixed_delay: Up to maxRetries additional attempts
  • scheduled: Number of dates in retryDates array
Example with 3 retries (4 total attempts):
{
  "type": "fixed_delay",
  "delayMinutes": 30,
  "maxRetries": 3
}
Retries are triggered when a call doesn’t reach a successful outcome:
  • completed - No retry (success)
  • 🔄 no_answer - Retry
  • 🔄 busy - Retry
  • 🔄 rejected - Retry
  • 🔄 voicemail - Retry (configurable)
  • failed - Retry (system error)
Yes. If a retry is scheduled during a pause window, it waits until the pause window ends before attempting the call.

Audio & Media

Upload audio files via POST /audio-management/upload using multipart/form-data. The system processes and converts files automatically.Supported content types include:
  • audio/wav
  • audio/mp3
  • audio/mpeg
Audio is processed to telephony-optimized format (8kHz sample rate, mono).
POST /audio-management/upload
Content-Type: multipart/form-data

file: [binary audio file]
title: "Welcome Message"
description: "Greeting for customers"
usageType: "welcome"
tags: ["greeting", "intro"]

Response includes the id to use in your Play nodes.
Dictionaries map keys to audio files for dynamic content. For example, a “Numbers” dictionary might have:
  • Key "1" → audio of “one” spoken
  • Key "100" → audio of “one hundred” spoken
  • Key "thousand" → audio of “thousand” spoken
Use dictionaries in Play nodes to dynamically construct spoken content like amounts or dates.

Troubleshooting

Causes:
  • API key expired or revoked
  • Missing or malformed Authorization header
  • Typo in your API key
Solutions:
  1. Check header format: x-api-key YOUR_API_KEY
  2. Verify you’re using the correct API key
  3. Contact our team if you need a new API key
You’ve hit the rate limit. Solutions:
  1. Reduce request frequency - Add delays between calls
  2. Implement exponential backoff - Wait longer after each retry
  3. Batch operations - Use bulk endpoints like /contact/upsert
  4. Check response headers for rate limit details
Verify:
  1. startAt is in the future - Or already passed if you want immediate start
  2. Audience is not empty - AudienceEmptyError if no contacts
  3. No existing running execution - ExecutionAlreadyRunningError
  4. Program status is active - Not draft or archived
Launch with: POST /programs/:id/launch

Still have questions?

If you couldn’t find the answer you’re looking for: