Prokeep SNAPI API (1.0.0)

Download OpenAPI specification:

Prokeep Support: support@prokeep.com License: MIT

Introduction

The Supplier Network API (SNAPI) provides programmatic access to Prokeep's messaging platform, enabling suppliers to integrate their systems with Prokeep's communication infrastructure. This API allows suppliers to search for customer groups, retrieve industry information, and send messages to Prokeep users.

Authentication

Overview

SNAPI uses HTTP Basic Authentication with supplier-specific credentials. Each supplier partner is provided with:

  • Username: A unique API username for your supplier partner account
  • Password: A secure API password

Authentication Headers

All API requests must include an Authorization header with Basic authentication: The resulting header would look like this:

Authorization: Basic {base64_encoded_credentials}

Where {base64_encoded_credentials} is the Base64 encoding of username:password

Example Authentication

# Encode credentials
$ echo -n "your_username:your_password" | base64
# Output: eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk

# Use in request
$ curl -H "Authorization: Basic eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk" \
    https://snapi.prokeep.com/v1/groups

Rate Limiting

SNAPI implements rate limiting to ensure fair usage and system stability. Contact Prokeep support for specific rate limit information for your partner account.

Webhooks

Suppliers can receive real-time updates about message responses through webhooks. When configuring your supplier partner account, you'll provide:

  • Webhook URL: The HTTPS endpoint where Prokeep will send webhook events
  • Webhook Secret: A shared secret used to verify webhook authenticity

Security

All webhooks include an HMAC signature in the X-Prokeep-Signature header for verification:

# Verify webhook signature (example in Javascript)
const crypto = require('crypto');

/**
 * Verifies SNAPI webhook signature according to official specification
 *
 * @param {string} payload - The raw request body as a string
 * @param {string} signature - The X-Prokeep-Signature header value
 * @param {string} timestamp - The X-Timestamp header value
 * @param {string} secret - Your webhook secret from Prokeep
 * @returns {boolean} - True if signature is valid, false otherwise
 */
function verifyWebhookSignature(payload, signature, timestamp, secret) {
    if (!signature || !timestamp) {
        return false;
    }

    // Remove sha256= prefix if present
    const cleanSignature = signature.startsWith('sha256=') ? signature.slice(7) : signature;

    // Create message: timestamp + "." + request_body
    const message = timestamp + '.' + payload;

    // Calculate HMAC-SHA256
    const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(message, 'utf8')
        .digest('hex');

    // Use timing-safe comparison to prevent timing attacks
    return crypto.timingSafeEqual(
        Buffer.from(cleanSignature, 'hex'),
        Buffer.from(expectedSignature, 'hex')
    );
}

// Example usage:
const payload = '{"event":"message.reply","data":{...}}';
const timestamp = req.get('X-Timestamp');          // e.g., "1642253400"

// Check both possible signature headers (one or the other will exist)
const prokeepSignature = req.get('X-Prokeep-Signature');
const xSignature = req.get('X-Signature');
const signature = prokeepSignature || xSignature;  // e.g., "sha256=abc123def456..."

const secret = 'your_webhook_secret_here';
const isValid = verifyWebhookSignature(payload, signature, timestamp, secret);

Best Practices

  1. Rate Limiting: Implement exponential backoff when encountering rate limits
  2. Pagination: Always handle pagination for large result sets
  3. Error Handling: Implement robust error handling for all API calls
  4. Caching: Cache industry and group data when appropriate to reduce API calls
  5. Webhook Verification: Always verify webhook signatures before processing
  6. Idempotency: Use unique identifiers for contacts to ensure message consistency
  7. Monitoring: Log all API interactions for debugging and audit purposes
  8. Attachment Validation: Ensure attachment URLs are publicly accessible and stable
  9. Contact Information: Provide either email or phone number for all contacts
  10. Group Validation: Verify groups accept supplier messages before sending

Message reply Webhook

Sent to your configured webhook_url when a Prokeep user replies to a message sent via SNAPI Verify the X-Prokeep-Signature header before processing: it is sha256= followed by the hex-encoded HMAC-SHA256 of {X-Timestamp}.{raw request body}, computed using your partner webhook secret. Use a timing-safe comparison.

Authorizations:
snapi_auth
header Parameters
X-Prokeep-Signature
required
string
Example: sha256=3f786850e387550fdab836ed7e6dc881de23001b

HMAC-SHA256 signature of the payload, prefixed with sha256=.

X-Timestamp
required
string
Example: 1642253400

Unix timestamp (seconds) the request was signed at.

Request Body schema: application/cloudevents+json
specversion
string
id
string <uuid>

A unique identifier for this event delivery

source
string
type
string
Value: "com.prokeep.snapi.message.reply"
object

Responses

Request samples

Content type
application/cloudevents+json
{
  • "specversion": "1.0",
  • "id": "20c805d7-9135-4761-a7b8-9ba48d65a35d",
  • "source": "https://prokeep.com",
  • "type": "com.prokeep.snapi.message.reply",
  • "data": {
    }
}

Group

List groups

Search and retrieve Prokeep groups that accept supplier messages.

Authorizations:
snapi_auth
query Parameters
q
string
Examples:
  • q={ "postal_code": "94105" } - Search by postal code
  • q={ "address": { "$geoWithin": { "$centerSphere": [[-122.4194, 37.7749], 5000] } } } - Search within a radius of coordinates ([longitude, latitude], meters)
  • q={ "address": { "$geoWithin": { "$centerSphere": ["94105", 5000] } } } - Search within a radius of a postal code
  • q={ "industries": { "$or": [ {"$elemMatch": {"id": "industry_id_1"}}, {"$elemMatch": {"id": "industry_id_2"}} ] } } - Search by industries (any of the listed IDs)
  • q={ "industries": { "$and": [ {"$elemMatch": {"id": "industry_id_1"}}, {"$elemMatch": {"id": "industry_id_2"}} ] } } - Search by industries (all of the listed IDs)
  • q={ "industries": { "$elemMatch": {"id": "industry_id"} } } - Search by a single industry

A JSON-encoded search filter. See the request samples for supported criteria.

page-limit
integer <= 25
Default: 25

Maximum number of results to return (max 25).

page-after
string

Opaque cursor for the next page.

page-before
string

Opaque cursor for the previous page.

Responses

Response samples

Content type
application/json; charset=utf-8
{
  • "data": [
    ],
  • "links": {
    }
}

Industry

List industries

Retrieve a list of all available industries in the Prokeep system.

Authorizations:
snapi_auth
query Parameters
page-limit
integer <= 50
Default: 50
Example: page-limit=20

Maximum number of results to return (max 50).

page-after
string
Example: page-after=eyJuYW1lIjoiSFZBQyJ9

Opaque cursor for the next page.

page-before
string

Opaque cursor for the previous page.

Responses

Response samples

Content type
application/json; charset=utf-8
{
  • "data": [
    ],
  • "links": {
    }
}

Messages

Send message

Send a message to a Prokeep group on behalf of a contact.

Authorizations:
snapi_auth
Request Body schema: application/json; charset=utf-8
required

The message details

group_id
required
string <uuid>

The ID of an existing group that accepts supplier messages

body
required
string

The message content

subject
string or null <= 255 characters

An optional subject line

attachments
Array of strings <uri> [ items <uri > ]

URLs of publicly-reachable attachments. Each URL is validated with a HEAD request and must return a 2xx status.

required
object (Contact)

Contact information femail address. Either email_address or phone_number must be provided.

Responses

Request samples

Content type
application/json; charset=utf-8
Example
{
  • "group_id": "123e4567-e89b-12d3-a456-426614174000",
  • "body": "Hello, I wanted to follow up on your recent inquiry about our new product line.",
  • "subject": "New Product Line Follow-up",
  • "contact": {
    }
}

Response samples

Content type
application/json; charset=utf-8
{
  • "status": "accepted",
  • "message": "Message queued for processing"
}